aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs120
1 files changed, 53 insertions, 67 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index ad84ffee8..5c3345008 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -24,6 +24,7 @@ using CommonIO;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
namespace MediaBrowser.MediaEncoding.Encoder
@@ -79,11 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly Func<IMediaSourceManager> MediaSourceManager;
private readonly IHttpClient _httpClient;
private readonly IZipClient _zipClient;
+ private readonly IMemoryStreamProvider _memoryStreamProvider;
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
private readonly bool _hasExternalEncoder;
+ private string _originalFFMpegPath;
+ private string _originalFFProbePath;
- public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient)
+ public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamProvider memoryStreamProvider)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
@@ -98,8 +102,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
MediaSourceManager = mediaSourceManager;
_httpClient = httpClient;
_zipClient = zipClient;
+ _memoryStreamProvider = memoryStreamProvider;
FFProbePath = ffProbePath;
FFMpegPath = ffMpegPath;
+ _originalFFProbePath = ffProbePath;
+ _originalFFMpegPath = ffMpegPath;
_hasExternalEncoder = hasExternalEncoder;
}
@@ -108,11 +115,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
get
{
- if (_hasExternalEncoder)
- {
- return "External";
- }
-
if (string.IsNullOrWhiteSpace(FFMpegPath))
{
return null;
@@ -177,12 +179,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
ConfigureEncoderPaths();
- if (_hasExternalEncoder)
- {
- LogPaths();
- return;
- }
-
// If the path was passed in, save it into config now.
var encodingOptions = GetEncodingOptions();
var appPath = encodingOptions.EncoderAppPath;
@@ -207,11 +203,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
public async Task UpdateEncoderPath(string path, string pathType)
{
- if (_hasExternalEncoder)
- {
- return;
- }
-
Tuple<string, string> newPaths;
if (string.Equals(pathType, "system", StringComparison.OrdinalIgnoreCase))
@@ -247,6 +238,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
throw new ResourceNotFoundException("ffprobe not found");
}
+ path = newPaths.Item1;
+
+ if (!ValidateVersion(path))
+ {
+ throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required.");
+ }
+
var config = GetEncodingOptions();
config.EncoderAppPath = path;
ConfigurationManager.SaveConfiguration("encoding", config);
@@ -254,13 +252,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
Init();
}
- private void ConfigureEncoderPaths()
+ private bool ValidateVersion(string path)
{
- if (_hasExternalEncoder)
- {
- return;
- }
+ return new EncoderValidator(_logger).ValidateVersion(path);
+ }
+ private void ConfigureEncoderPaths()
+ {
var appPath = GetEncodingOptions().EncoderAppPath;
if (string.IsNullOrWhiteSpace(appPath))
@@ -308,45 +306,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
string encoderPath = null;
string probePath = null;
- if (TestSystemInstalled("ffmpeg"))
+ if (_hasExternalEncoder && ValidateVersion(_originalFFMpegPath))
{
- encoderPath = "ffmpeg";
+ encoderPath = _originalFFMpegPath;
+ probePath = _originalFFProbePath;
}
- if (TestSystemInstalled("ffprobe"))
- {
- probePath = "ffprobe";
- }
-
- return new Tuple<string, string>(encoderPath, probePath);
- }
- private bool TestSystemInstalled(string app)
- {
- try
+ if (string.IsNullOrWhiteSpace(encoderPath))
{
- var startInfo = new ProcessStartInfo
+ if (ValidateVersion("ffmpeg") && ValidateVersion("ffprobe"))
{
- FileName = app,
- Arguments = "-v",
- UseShellExecute = false,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- ErrorDialog = false
- };
-
- using (var process = Process.Start(startInfo))
- {
- process.WaitForExit();
+ encoderPath = "ffmpeg";
+ probePath = "ffprobe";
}
-
- _logger.Debug("System app installed: " + app);
- return true;
- }
- catch
- {
- _logger.Debug("System app not installed: " + app);
- return false;
}
+
+ return new Tuple<string, string>(encoderPath, probePath);
}
private Tuple<string, string> GetPathsFromDirectory(string path)
@@ -451,8 +426,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
+ var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol);
+
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
- GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
+ probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
}
/// <summary>
@@ -572,7 +549,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+ var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem, _memoryStreamProvider).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
@@ -799,20 +776,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken)
{
- return ExtractImage(new[] { path }, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken);
+ return ExtractImage(new[] { path }, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken);
}
- public Task<string> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
+ public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
{
- return ExtractImage(inputFiles, null, protocol, false, threedFormat, offset, cancellationToken);
+ return ExtractImage(inputFiles, container, null, protocol, false, threedFormat, offset, cancellationToken);
}
- public Task<string> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken)
+ public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken)
{
- return ExtractImage(inputFiles, imageStreamIndex, protocol, false, null, null, cancellationToken);
+ return ExtractImage(inputFiles, container, imageStreamIndex, protocol, false, null, null, cancellationToken);
}
- private async Task<string> ExtractImage(string[] inputFiles, int? imageStreamIndex, MediaProtocol protocol, bool isAudio,
+ private async Task<string> ExtractImage(string[] inputFiles, string container, int? imageStreamIndex, MediaProtocol protocol, bool isAudio,
Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
{
var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool;
@@ -831,7 +808,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
try
{
- return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
+ return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
}
catch (ArgumentException)
{
@@ -843,10 +820,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
+ return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
}
- private async Task<string> ExtractImageInternal(string inputPath, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
+ private async Task<string> ExtractImageInternal(string inputPath, string container, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(inputPath))
{
@@ -887,8 +864,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
+ var enableThumbnail = !new List<string> { "wtv" }.Contains(container ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ var thumbnail = enableThumbnail ? ",thumbnail=30" : string.Empty;
+
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
- var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg) :
+ var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
@@ -928,7 +908,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
StartProcess(processWrapper);
- ranToCompletion = process.WaitForExit(10000);
+ var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
+ if (timeoutMs <= 0)
+ {
+ timeoutMs = Environment.Is64BitOperatingSystem ? (Environment.ProcessorCount > 2 ? 14000 : 20000) : 40000;
+ }
+
+ ranToCompletion = process.WaitForExit(timeoutMs);
if (!ranToCompletion)
{