aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs')
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs237
1 files changed, 233 insertions, 4 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 80b9cc154..b7b31509c 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -154,6 +154,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return "mpegts";
}
+
// For these need to find out the ffmpeg names
if (string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
{
@@ -163,6 +164,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return null;
}
+ if (string.Equals(container, "mts", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
if (string.Equals(container, "vob", StringComparison.OrdinalIgnoreCase))
{
return null;
@@ -179,12 +184,23 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return null;
}
+ if (string.Equals(container, "dvr-ms", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
// Seeing reported failures here, not sure yet if this is related to specfying input format
if (string.Equals(container, "m4v", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+ // obviously don't do this for strm files
+ if (string.Equals(container, "strm", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
return container;
}
@@ -661,9 +677,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var level = NormalizeTranscodingLevel(state.OutputVideoCodec, request.Level);
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
- // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
+ // 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 (level)
@@ -700,10 +715,15 @@ namespace MediaBrowser.Controller.MediaEncoding
break;
}
}
+ // nvenc doesn't decode with param -level set ?!
+ if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)){
+ param += "";
+ }
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
param += " -level " + level;
}
+
}
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
@@ -727,12 +747,18 @@ namespace MediaBrowser.Controller.MediaEncoding
if (videoStream.IsInterlaced)
{
- return false;
+ if (request.DeInterlace)
+ {
+ return false;
+ }
}
if (videoStream.IsAnamorphic ?? false)
{
- return false;
+ if (request.RequireNonAnamorphic)
+ {
+ return false;
+ }
}
// Can't stream copy if we're burning in subtitles
@@ -1561,6 +1587,15 @@ namespace MediaBrowser.Controller.MediaEncoding
MediaSourceInfo mediaSource,
string requestedUrl)
{
+ if (state == null)
+ {
+ throw new ArgumentNullException("state");
+ }
+ if (mediaSource == null)
+ {
+ throw new ArgumentNullException("mediaSource");
+ }
+
state.MediaPath = mediaSource.Path;
state.InputProtocol = mediaSource.Protocol;
state.InputContainer = mediaSource.Container;
@@ -1670,9 +1705,21 @@ namespace MediaBrowser.Controller.MediaEncoding
case "h264":
if (_mediaEncoder.SupportsDecoder("h264_qsv"))
{
+ // qsv decoder does not support 10-bit input
+ if ((state.VideoStream.BitDepth ?? 8) > 8)
+ {
+ return null;
+ }
return "-c:v h264_qsv ";
}
break;
+ //case "hevc":
+ //case "h265":
+ // if (_mediaEncoder.SupportsDecoder("hevc_qsv"))
+ // {
+ // return "-c:v hevc_qsv ";
+ // }
+ // break;
case "mpeg2video":
if (_mediaEncoder.SupportsDecoder("mpeg2_qsv"))
{
@@ -1715,5 +1762,187 @@ namespace MediaBrowser.Controller.MediaEncoding
return threads;
}
+
+ public string GetSubtitleEmbedArguments(EncodingJobInfo state)
+ {
+ if (state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Embed)
+ {
+ return string.Empty;
+ }
+
+ var format = state.SupportedSubtitleCodecs.FirstOrDefault();
+ string codec;
+
+ if (string.IsNullOrWhiteSpace(format) || string.Equals(format, state.SubtitleStream.Codec, StringComparison.OrdinalIgnoreCase))
+ {
+ codec = "copy";
+ }
+ else
+ {
+ codec = format;
+ }
+
+ // Muxing in dvbsub via either copy or -codec dvbsub does not seem to work
+ // It doesn't throw any errors but vlc on android will not render them
+ // They will need to be converted to an alternative format
+ // TODO: This is incorrectly assuming that dvdsub will be supported by the player
+ // The api will need to be expanded to accomodate this.
+ if (string.Equals(state.SubtitleStream.Codec, "DVBSUB", StringComparison.OrdinalIgnoreCase))
+ {
+ codec = "dvdsub";
+ }
+
+ var args = " -codec:s:0 " + codec;
+
+ args += " -disposition:s:0 default";
+
+ return args;
+ }
+
+ public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultH264Preset)
+ {
+ // Get the output codec name
+ var videoCodec = GetVideoEncoder(state, encodingOptions);
+
+ var format = string.Empty;
+ var keyFrame = string.Empty;
+
+ if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase) &&
+ state.BaseRequest.Context == EncodingContext.Streaming)
+ {
+ // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
+ format = " -f mp4 -movflags frag_keyframe+empty_moov";
+ }
+
+ var threads = GetNumberOfThreads(state, encodingOptions, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
+
+ var inputModifier = GetInputModifier(state, encodingOptions);
+
+ return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"",
+ inputModifier,
+ GetInputArgument(state, encodingOptions),
+ keyFrame,
+ GetMapArgs(state),
+ GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultH264Preset),
+ threads,
+ GetProgressiveVideoAudioArguments(state, encodingOptions),
+ GetSubtitleEmbedArguments(state),
+ format,
+ outputPath
+ ).Trim();
+ }
+
+ public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultH264Preset)
+ {
+ var args = "-codec:v:0 " + videoCodec;
+
+ if (state.EnableMpegtsM2TsMode)
+ {
+ args += " -mpegts_m2ts_mode 1";
+ }
+
+ if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ if (state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
+ {
+ args += " -bsf:v h264_mp4toannexb";
+ }
+
+ if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
+ {
+ args += " -copyts -avoid_negative_ts disabled -start_at_zero";
+ }
+
+ if (!state.RunTimeTicks.HasValue)
+ {
+ args += " -flags -global_header -fflags +genpts";
+ }
+
+ return args;
+ }
+
+ var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
+ 5.ToString(_usCulture));
+
+ args += keyFrameArg;
+
+ var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.BaseRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
+
+ var hasCopyTs = false;
+ // Add resolution params, if specified
+ if (!hasGraphicalSubs)
+ {
+ var outputSizeParam = GetOutputSizeParam(state, videoCodec);
+ args += outputSizeParam;
+ hasCopyTs = outputSizeParam.IndexOf("copyts", StringComparison.OrdinalIgnoreCase) != -1;
+ }
+
+ if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
+ {
+ if (!hasCopyTs)
+ {
+ args += " -copyts";
+ }
+ args += " -avoid_negative_ts disabled -start_at_zero";
+ }
+
+ var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset);
+
+ if (!string.IsNullOrEmpty(qualityParam))
+ {
+ args += " " + qualityParam.Trim();
+ }
+
+ // This is for internal graphical subs
+ if (hasGraphicalSubs)
+ {
+ args += GetGraphicalSubtitleParam(state, videoCodec);
+ }
+
+ if (!state.RunTimeTicks.HasValue)
+ {
+ args += " -flags -global_header";
+ }
+
+ return args;
+ }
+
+ public string GetProgressiveVideoAudioArguments(EncodingJobInfo state, EncodingOptions encodingOptions)
+ {
+ // If the video doesn't have an audio stream, return a default.
+ if (state.AudioStream == null && state.VideoStream != null)
+ {
+ return string.Empty;
+ }
+
+ // Get the output codec name
+ var codec = GetAudioEncoder(state);
+
+ var args = "-codec:a:0 " + codec;
+
+ if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return args;
+ }
+
+ // Add the number of audio channels
+ var channels = state.OutputAudioChannels;
+
+ if (channels.HasValue)
+ {
+ args += " -ac " + channels.Value;
+ }
+
+ var bitrate = state.OutputAudioBitrate;
+
+ if (bitrate.HasValue)
+ {
+ args += " -ab " + bitrate.Value.ToString(_usCulture);
+ }
+
+ args += " " + GetAudioFilterParam(state, encodingOptions, false);
+
+ return args;
+ }
}
}