FFMpegLoader.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using MediaBrowser.Common.Configuration;
  2. using MediaBrowser.Common.Net;
  3. using MediaBrowser.Model.IO;
  4. using Microsoft.Extensions.Logging;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. namespace Emby.Server.Implementations.FFMpeg
  10. {
  11. public class FFMpegLoader
  12. {
  13. private readonly IHttpClient _httpClient;
  14. private readonly IApplicationPaths _appPaths;
  15. private readonly ILogger _logger;
  16. private readonly IZipClient _zipClient;
  17. private readonly IFileSystem _fileSystem;
  18. private readonly FFMpegInstallInfo _ffmpegInstallInfo;
  19. public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, FFMpegInstallInfo ffmpegInstallInfo)
  20. {
  21. _logger = logger;
  22. _appPaths = appPaths;
  23. _httpClient = httpClient;
  24. _zipClient = zipClient;
  25. _fileSystem = fileSystem;
  26. _ffmpegInstallInfo = ffmpegInstallInfo;
  27. }
  28. public FFMpegInfo GetFFMpegInfo(StartupOptions options)
  29. {
  30. var customffMpegPath = options.GetOption("-ffmpeg");
  31. var customffProbePath = options.GetOption("-ffprobe");
  32. if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath))
  33. {
  34. return new FFMpegInfo
  35. {
  36. ProbePath = customffProbePath,
  37. EncoderPath = customffMpegPath,
  38. Version = "external"
  39. };
  40. }
  41. var downloadInfo = _ffmpegInstallInfo;
  42. var prebuiltFolder = _appPaths.ProgramSystemPath;
  43. var prebuiltffmpeg = Path.Combine(prebuiltFolder, downloadInfo.FFMpegFilename);
  44. var prebuiltffprobe = Path.Combine(prebuiltFolder, downloadInfo.FFProbeFilename);
  45. if (_fileSystem.FileExists(prebuiltffmpeg) && _fileSystem.FileExists(prebuiltffprobe))
  46. {
  47. return new FFMpegInfo
  48. {
  49. ProbePath = prebuiltffprobe,
  50. EncoderPath = prebuiltffmpeg,
  51. Version = "external"
  52. };
  53. }
  54. var version = downloadInfo.Version;
  55. if (string.Equals(version, "0", StringComparison.OrdinalIgnoreCase))
  56. {
  57. return new FFMpegInfo();
  58. }
  59. var rootEncoderPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
  60. var versionedDirectoryPath = Path.Combine(rootEncoderPath, version);
  61. var info = new FFMpegInfo
  62. {
  63. ProbePath = Path.Combine(versionedDirectoryPath, downloadInfo.FFProbeFilename),
  64. EncoderPath = Path.Combine(versionedDirectoryPath, downloadInfo.FFMpegFilename),
  65. Version = version
  66. };
  67. _fileSystem.CreateDirectory(versionedDirectoryPath);
  68. var excludeFromDeletions = new List<string> { versionedDirectoryPath };
  69. if (!_fileSystem.FileExists(info.ProbePath) || !_fileSystem.FileExists(info.EncoderPath))
  70. {
  71. // ffmpeg not present. See if there's an older version we can start with
  72. var existingVersion = GetExistingVersion(info, rootEncoderPath);
  73. // No older version. Need to download and block until complete
  74. if (existingVersion == null)
  75. {
  76. return new FFMpegInfo();
  77. }
  78. else
  79. {
  80. info = existingVersion;
  81. versionedDirectoryPath = _fileSystem.GetDirectoryName(info.EncoderPath);
  82. excludeFromDeletions.Add(versionedDirectoryPath);
  83. }
  84. }
  85. // Allow just one of these to be overridden, if desired.
  86. if (!string.IsNullOrWhiteSpace(customffMpegPath))
  87. {
  88. info.EncoderPath = customffMpegPath;
  89. }
  90. if (!string.IsNullOrWhiteSpace(customffProbePath))
  91. {
  92. info.ProbePath = customffProbePath;
  93. }
  94. return info;
  95. }
  96. private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath)
  97. {
  98. var encoderFilename = Path.GetFileName(info.EncoderPath);
  99. var probeFilename = Path.GetFileName(info.ProbePath);
  100. foreach (var directory in _fileSystem.GetDirectoryPaths(rootEncoderPath)
  101. .ToList())
  102. {
  103. var allFiles = _fileSystem.GetFilePaths(directory, true).ToList();
  104. var encoder = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), encoderFilename, StringComparison.OrdinalIgnoreCase));
  105. var probe = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), probeFilename, StringComparison.OrdinalIgnoreCase));
  106. if (!string.IsNullOrWhiteSpace(encoder) &&
  107. !string.IsNullOrWhiteSpace(probe))
  108. {
  109. return new FFMpegInfo
  110. {
  111. EncoderPath = encoder,
  112. ProbePath = probe,
  113. Version = Path.GetFileName(_fileSystem.GetDirectoryName(probe))
  114. };
  115. }
  116. }
  117. return null;
  118. }
  119. }
  120. }