FFMpegLoader.cs 4.8 KB

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