aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs102
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs24
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs15
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs3
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs120
6 files changed, 172 insertions, 94 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 6bf414dfa..f1e2f7241 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -481,6 +481,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ if (state.IsVideoRequest)
+ {
+ var encodingOptions = GetEncodingOptions();
+ var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions);
+ if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.Options.SubtitleMethod == SubtitleDeliveryMethod.Encode;
+ var hwOutputFormat = "vaapi";
+
+ if (hasGraphicalSubs)
+ {
+ hwOutputFormat = "yuv420p";
+ }
+
+ arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
+ }
+ }
+
return arg.Trim();
}
@@ -555,7 +573,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
outputSizeParam = await GetOutputSizeParam(state, outputVideoCodec).ConfigureAwait(false);
outputSizeParam = outputSizeParam.TrimEnd('"');
- outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase));
+
+ if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ {
+ outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase));
+ }
+ else
+ {
+ outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0)
+ {
+ outputSizeParam = ",format=nv12|vaapi,hwupload";
}
var videoSizeParam = string.Empty;
@@ -585,23 +616,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the video bitrate to specify on the command line
/// </summary>
/// <param name="state">The state.</param>
- /// <param name="videoCodec">The video codec.</param>
+ /// <param name="videoEncoder">The video codec.</param>
/// <returns>System.String.</returns>
- protected string GetVideoQualityParam(EncodingJob state, string videoCodec)
+ protected string GetVideoQualityParam(EncodingJob state, string videoEncoder)
{
var param = string.Empty;
var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
- if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
{
param = "-preset superfast";
param += " -crf 23";
}
- else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
{
param = "-preset fast";
@@ -609,20 +640,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// h264 (h264_qsv)
- else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
param = "-preset 7 -look_ahead 0";
}
// h264 (h264_nvenc)
- else if (string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
param = "-preset llhq";
}
// webm
- else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
{
// Values 0-3, 0 being highest quality but slower
var profileScore = 0;
@@ -649,23 +680,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
qmax);
}
- else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
}
// asf/wmv
- else if (string.Equals(videoCodec, "wmv2", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
{
param = "-qmin 2";
}
- else if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
param = "-mbd 2";
}
- param += GetVideoBitrateParam(state, videoCodec);
+ param += GetVideoBitrateParam(state, videoEncoder);
var framerate = GetFramerateParam(state);
if (framerate.HasValue)
@@ -680,8 +711,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(state.Options.Profile))
{
- if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.Options.Profile;
@@ -692,14 +723,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(levelString))
{
+ levelString = NormalizeTranscodingLevel(state.OutputVideoCodec, levelString);
+
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
- if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+ // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
+ if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
{
switch (levelString)
{
case "30":
- param += " -level 3";
+ param += " -level 3.0";
break;
case "31":
param += " -level 3.1";
@@ -708,7 +743,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
param += " -level 3.2";
break;
case "40":
- param += " -level 4";
+ param += " -level 4.0";
break;
case "41":
param += " -level 4.1";
@@ -717,7 +752,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
param += " -level 4.2";
break;
case "50":
- param += " -level 5";
+ param += " -level 5.0";
break;
case "51":
param += " -level 5.1";
@@ -730,16 +765,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
break;
}
}
- else if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
+ else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
param += " -level " + levelString;
}
}
- if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@@ -747,6 +782,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
return param;
}
+ private string NormalizeTranscodingLevel(string videoCodec, string level)
+ {
+ double requestLevel;
+
+ // Clients may direct play higher than level 41, but there's no reason to transcode higher
+ if (double.TryParse(level, NumberStyles.Any, UsCulture, out requestLevel))
+ {
+ if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
+ {
+ if (requestLevel > 41)
+ {
+ return "41";
+ }
+ }
+ }
+
+ return level;
+ }
+
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec)
{
var bitrate = state.OutputVideoBitrate;
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index a450097fd..24de4e77e 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -26,6 +26,30 @@ namespace MediaBrowser.MediaEncoding.Encoder
return new Tuple<List<string>, List<string>>(decoders, encoders);
}
+ public bool ValidateVersion(string encoderAppPath)
+ {
+ string output = string.Empty;
+ try
+ {
+ output = GetProcessOutput(encoderAppPath, "-version");
+ }
+ catch
+ {
+ }
+
+ if (string.IsNullOrWhiteSpace(output))
+ {
+ return false;
+ }
+
+ if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
private List<string> GetDecoders(string encoderAppPath)
{
string output = string.Empty;
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 490a51128..0c7ff1b76 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -140,7 +140,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
try
{
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -392,6 +392,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ public bool? IsTargetAVC
+ {
+ get
+ {
+ if (Options.Static)
+ {
+ return VideoStream == null ? null : VideoStream.IsAVC;
+ }
+
+ return false;
+ }
+ }
+
public int? TargetVideoStreamCount
{
get
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index c72532669..b66a3ed96 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -823,7 +823,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.TargetRefFrames,
state.TargetVideoStreamCount,
state.TargetAudioStreamCount,
- state.TargetVideoCodecTag);
+ state.TargetVideoCodecTag,
+ state.IsTargetAVC);
if (mediaProfile != null)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
index b34a4cd38..5d0f1f075 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
@@ -76,7 +76,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public static string GetProbeSizeArgument(bool isDvd)
{
- return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
+ return isDvd ? "-probesize 1G -analyzeduration 200M" : "";
}
}
}
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)
{