Merge pull request #1433 from fhriley/h265
Add support for encoding with libx265 and hevc_nvenc
This commit is contained in:
commit
1bce9a89b6
|
@ -28,6 +28,7 @@
|
||||||
- [DrPandemic](https://github.com/drpandemic)
|
- [DrPandemic](https://github.com/drpandemic)
|
||||||
- [joern-h](https://github.com/joern-h)
|
- [joern-h](https://github.com/joern-h)
|
||||||
- [Khinenw](https://github.com/HelloWorld017)
|
- [Khinenw](https://github.com/HelloWorld017)
|
||||||
|
- [fhriley](https://github.com/fhriley)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
return Path.Combine(folder, filename + ext);
|
return Path.Combine(folder, filename + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string GetDefaultH264Preset() => "superfast";
|
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
|
protected virtual string GetDefaultEncoderPreset()
|
||||||
|
{
|
||||||
|
return "superfast";
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
|
private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
|
||||||
{
|
{
|
||||||
|
|
|
@ -304,7 +304,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetDefaultH264Preset()
|
protected override string GetDefaultEncoderPreset()
|
||||||
{
|
{
|
||||||
return "veryfast";
|
return "veryfast";
|
||||||
}
|
}
|
||||||
|
|
|
@ -895,9 +895,13 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
// See if we can save come cpu cycles by avoiding encoding
|
// See if we can save come cpu cycles by avoiding encoding
|
||||||
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && EncodingHelper.IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
if (state.VideoStream != null && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
string bitStreamArgs = EncodingHelper.GetBitStreamArgs(state.VideoStream);
|
||||||
|
if (!string.IsNullOrEmpty(bitStreamArgs))
|
||||||
|
{
|
||||||
|
args += " " + bitStreamArgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//args += " -flags -global_header";
|
//args += " -flags -global_header";
|
||||||
|
@ -909,7 +913,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||||
|
|
||||||
args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
|
args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultEncoderPreset()) + keyFrameArg;
|
||||||
|
|
||||||
//args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
|
//args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
|
||||||
|
|
||||||
|
|
|
@ -92,10 +92,14 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
|
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
// if h264_mp4toannexb is ever added, do not use it for live tv
|
// if h264_mp4toannexb is ever added, do not use it for live tv
|
||||||
if (state.VideoStream != null && EncodingHelper.IsH264(state.VideoStream) &&
|
if (state.VideoStream != null &&
|
||||||
!string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
!string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
string bitStreamArgs = EncodingHelper.GetBitStreamArgs(state.VideoStream);
|
||||||
|
if (!string.IsNullOrEmpty(bitStreamArgs))
|
||||||
|
{
|
||||||
|
args += " " + bitStreamArgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -105,7 +109,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||||
|
|
||||||
args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
|
args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultEncoderPreset()) + keyFrameArg;
|
||||||
|
|
||||||
// Add resolution params, if specified
|
// Add resolution params, if specified
|
||||||
if (!hasGraphicalSubs)
|
if (!hasGraphicalSubs)
|
||||||
|
|
|
@ -77,7 +77,8 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
{
|
{
|
||||||
var videoCodec = state.VideoRequest.VideoCodec;
|
var videoCodec = state.VideoRequest.VideoCodec;
|
||||||
|
|
||||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(videoCodec, "h265", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return ".ts";
|
return ".ts";
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
|
|
||||||
protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
|
protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
|
||||||
{
|
{
|
||||||
return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, GetDefaultH264Preset());
|
return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, GetDefaultEncoderPreset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,16 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||||
{
|
{
|
||||||
var defaultEncoder = "libx264";
|
return GetH264OrH265Encoder("libx264", "h264", state, encodingOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetH265Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||||
|
{
|
||||||
|
return GetH264OrH265Encoder("libx265", "hevc", state, encodingOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetH264OrH265Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||||
|
{
|
||||||
// Only use alternative encoders for video files.
|
// Only use alternative encoders for video files.
|
||||||
// When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
|
// When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
|
||||||
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
|
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
|
||||||
|
@ -45,14 +53,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
{"qsv", "h264_qsv"},
|
{"qsv", hwEncoder + "_qsv"},
|
||||||
{"h264_qsv", "h264_qsv"},
|
{hwEncoder + "_qsv", hwEncoder + "_qsv"},
|
||||||
{"nvenc", "h264_nvenc"},
|
{"nvenc", hwEncoder + "_nvenc"},
|
||||||
{"amf", "h264_amf"},
|
{"amf", hwEncoder + "_amf"},
|
||||||
{"omx", "h264_omx"},
|
{"omx", hwEncoder + "_omx"},
|
||||||
{"h264_v4l2m2m", "h264_v4l2m2m"},
|
{hwEncoder + "_v4l2m2m", hwEncoder + "_v4l2m2m"},
|
||||||
{"mediacodec", "h264_mediacodec"},
|
{"mediacodec", hwEncoder + "_mediacodec"},
|
||||||
{"vaapi", "h264_vaapi"}
|
{"vaapi", hwEncoder + "_vaapi"}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(hwType)
|
if (!string.IsNullOrEmpty(hwType)
|
||||||
|
@ -119,6 +127,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(codec))
|
if (!string.IsNullOrEmpty(codec))
|
||||||
{
|
{
|
||||||
|
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return GetH265Encoder(state, encodingOptions);
|
||||||
|
}
|
||||||
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return GetH264Encoder(state, encodingOptions);
|
return GetH264Encoder(state, encodingOptions);
|
||||||
|
@ -476,6 +489,30 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
|
codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsH265(MediaStream stream)
|
||||||
|
{
|
||||||
|
var codec = stream.Codec ?? string.Empty;
|
||||||
|
|
||||||
|
return codec.IndexOf("265", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
|
codec.IndexOf("hevc", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetBitStreamArgs(MediaStream stream)
|
||||||
|
{
|
||||||
|
if (IsH264(stream))
|
||||||
|
{
|
||||||
|
return "-bsf:v h264_mp4toannexb";
|
||||||
|
}
|
||||||
|
else if (IsH265(stream))
|
||||||
|
{
|
||||||
|
return "-bsf:v hevc_mp4toannexb";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string GetVideoBitrateParam(EncodingJobInfo state, string videoCodec)
|
public string GetVideoBitrateParam(EncodingJobInfo state, string videoCodec)
|
||||||
{
|
{
|
||||||
var bitrate = state.OutputVideoBitrate;
|
var bitrate = state.OutputVideoBitrate;
|
||||||
|
@ -494,7 +531,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
return string.Format(" -b:v {0}", bitrate.Value.ToString(_usCulture));
|
return string.Format(" -b:v {0}", bitrate.Value.ToString(_usCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
// h264
|
// h264
|
||||||
return string.Format(" -maxrate {0} -bufsize {1}",
|
return string.Format(" -maxrate {0} -bufsize {1}",
|
||||||
|
@ -515,8 +553,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
// Clients may direct play higher than level 41, but there's no reason to transcode higher
|
// Clients may direct play higher than level 41, but there's no reason to transcode higher
|
||||||
if (double.TryParse(level, NumberStyles.Any, _usCulture, out double requestLevel)
|
if (double.TryParse(level, NumberStyles.Any, _usCulture, out double requestLevel)
|
||||||
&& string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)
|
&& requestLevel > 41
|
||||||
&& requestLevel > 41)
|
&& (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(videoCodec, "h265", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(videoCodec, "hevc", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
return "41";
|
return "41";
|
||||||
}
|
}
|
||||||
|
@ -620,39 +660,43 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the video bitrate to specify on the command line
|
/// Gets the video bitrate to specify on the command line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultH264Preset)
|
public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultPreset)
|
||||||
{
|
{
|
||||||
var param = string.Empty;
|
var param = string.Empty;
|
||||||
|
|
||||||
var isVc1 = state.VideoStream != null &&
|
var isVc1 = state.VideoStream != null &&
|
||||||
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
|
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
|
||||||
|
var isLibX265 = string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) || isLibX265)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(encodingOptions.H264Preset))
|
if (!string.IsNullOrEmpty(encodingOptions.EncoderPreset))
|
||||||
{
|
{
|
||||||
param += "-preset " + encodingOptions.H264Preset;
|
param += "-preset " + encodingOptions.EncoderPreset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
param += "-preset " + defaultH264Preset;
|
param += "-preset " + defaultPreset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encodingOptions.H264Crf >= 0 && encodingOptions.H264Crf <= 51)
|
int encodeCrf = encodingOptions.H264Crf;
|
||||||
|
if (isLibX265)
|
||||||
{
|
{
|
||||||
param += " -crf " + encodingOptions.H264Crf.ToString(CultureInfo.InvariantCulture);
|
encodeCrf = encodingOptions.H265Crf;
|
||||||
|
}
|
||||||
|
if (encodeCrf >= 0 && encodeCrf <= 51)
|
||||||
|
{
|
||||||
|
param += " -crf " + encodeCrf.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
param += " -crf 23";
|
string defaultCrf = "23";
|
||||||
}
|
if (isLibX265)
|
||||||
}
|
|
||||||
|
|
||||||
else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
param += "-preset fast";
|
defaultCrf = "28";
|
||||||
|
}
|
||||||
param += " -crf 28";
|
param += " -crf " + defaultCrf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// h264 (h264_qsv)
|
// h264 (h264_qsv)
|
||||||
|
@ -660,9 +704,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
string[] valid_h264_qsv = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" };
|
string[] valid_h264_qsv = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" };
|
||||||
|
|
||||||
if (valid_h264_qsv.Contains(encodingOptions.H264Preset, StringComparer.OrdinalIgnoreCase))
|
if (valid_h264_qsv.Contains(encodingOptions.EncoderPreset, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
param += "-preset " + encodingOptions.H264Preset;
|
param += "-preset " + encodingOptions.EncoderPreset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -674,9 +718,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
}
|
}
|
||||||
|
|
||||||
// h264 (h264_nvenc)
|
// h264 (h264_nvenc)
|
||||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
switch (encodingOptions.H264Preset)
|
switch (encodingOptions.EncoderPreset)
|
||||||
{
|
{
|
||||||
case "veryslow":
|
case "veryslow":
|
||||||
|
|
||||||
|
@ -790,7 +835,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
|
// 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) ||
|
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
|
string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
switch (level)
|
switch (level)
|
||||||
{
|
{
|
||||||
|
@ -827,9 +873,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// nvenc doesn't decode with param -level set ?!
|
// nvenc doesn't decode with param -level set ?!
|
||||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
//param += "";
|
// todo param += "";
|
||||||
}
|
}
|
||||||
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -842,6 +889,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
param += " -x264opts:0 subme=0:me_range=4:rc_lookahead=10:me=dia:no_chroma_me:8x8dct=0:partitions=none";
|
param += " -x264opts:0 subme=0:me_range=4:rc_lookahead=10:me=dia:no_chroma_me:8x8dct=0:partitions=none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
|
||||||
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
!string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
|
||||||
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
|
!string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
@ -1743,7 +1795,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
var videoStream = state.VideoStream;
|
var videoStream = state.VideoStream;
|
||||||
|
|
||||||
if (state.DeInterlace("h264", true) && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) &&
|
||||||
|
!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var inputFramerate = videoStream == null ? null : videoStream.RealFrameRate;
|
var inputFramerate = videoStream == null ? null : videoStream.RealFrameRate;
|
||||||
|
|
||||||
|
@ -2404,7 +2457,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultH264Preset)
|
public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultPreset)
|
||||||
{
|
{
|
||||||
// Get the output codec name
|
// Get the output codec name
|
||||||
var videoCodec = GetVideoEncoder(state, encodingOptions);
|
var videoCodec = GetVideoEncoder(state, encodingOptions);
|
||||||
|
@ -2428,7 +2481,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
GetInputArgument(state, encodingOptions),
|
GetInputArgument(state, encodingOptions),
|
||||||
keyFrame,
|
keyFrame,
|
||||||
GetMapArgs(state),
|
GetMapArgs(state),
|
||||||
GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultH264Preset),
|
GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultPreset),
|
||||||
threads,
|
threads,
|
||||||
GetProgressiveVideoAudioArguments(state, encodingOptions),
|
GetProgressiveVideoAudioArguments(state, encodingOptions),
|
||||||
GetSubtitleEmbedArguments(state),
|
GetSubtitleEmbedArguments(state),
|
||||||
|
@ -2453,7 +2506,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultH264Preset)
|
public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultPreset)
|
||||||
{
|
{
|
||||||
var args = "-codec:v:0 " + videoCodec;
|
var args = "-codec:v:0 " + videoCodec;
|
||||||
|
|
||||||
|
@ -2464,11 +2517,15 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (state.VideoStream != null && IsH264(state.VideoStream) &&
|
if (state.VideoStream != null &&
|
||||||
string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) &&
|
string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) &&
|
||||||
!string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
!string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
args += " -bsf:v h264_mp4toannexb";
|
string bitStreamArgs = GetBitStreamArgs(state.VideoStream);
|
||||||
|
if (!string.IsNullOrEmpty(bitStreamArgs))
|
||||||
|
{
|
||||||
|
args += " " + bitStreamArgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
|
if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
|
||||||
|
@ -2514,7 +2571,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
|
args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset);
|
var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultPreset);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(qualityParam))
|
if (!string.IsNullOrEmpty(qualityParam))
|
||||||
{
|
{
|
||||||
|
|
|
@ -118,14 +118,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// Gets or sets the profile.
|
/// Gets or sets the profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The profile.</value>
|
/// <value>The profile.</value>
|
||||||
[ApiMember(Name = "Profile", Description = "Optional. Specify a specific h264 profile, e.g. main, baseline, high.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Profile", Description = "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string Profile { get; set; }
|
public string Profile { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the level.
|
/// Gets or sets the level.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The level.</value>
|
/// <value>The level.</value>
|
||||||
[ApiMember(Name = "Level", Description = "Optional. Specify a level for the h264 profile, e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Level", Description = "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string Level { get; set; }
|
public string Level { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -212,7 +212,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// Gets or sets the video codec.
|
/// Gets or sets the video codec.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The video codec.</value>
|
/// <value>The video codec.</value>
|
||||||
[ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
|
|
||||||
public string SubtitleCodec { get; set; }
|
public string SubtitleCodec { get; set; }
|
||||||
|
|
|
@ -18,7 +18,8 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public string EncoderAppPathDisplay { get; set; }
|
public string EncoderAppPathDisplay { get; set; }
|
||||||
public string VaapiDevice { get; set; }
|
public string VaapiDevice { get; set; }
|
||||||
public int H264Crf { get; set; }
|
public int H264Crf { get; set; }
|
||||||
public string H264Preset { get; set; }
|
public int H265Crf { get; set; }
|
||||||
|
public string EncoderPreset { get; set; }
|
||||||
public string DeinterlaceMethod { get; set; }
|
public string DeinterlaceMethod { get; set; }
|
||||||
public bool EnableHardwareEncoding { get; set; }
|
public bool EnableHardwareEncoding { get; set; }
|
||||||
public bool EnableSubtitleExtraction { get; set; }
|
public bool EnableSubtitleExtraction { get; set; }
|
||||||
|
@ -34,6 +35,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
// This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything
|
// This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything
|
||||||
VaapiDevice = "/dev/dri/renderD128";
|
VaapiDevice = "/dev/dri/renderD128";
|
||||||
H264Crf = 23;
|
H264Crf = 23;
|
||||||
|
H265Crf = 28;
|
||||||
EnableHardwareEncoding = true;
|
EnableHardwareEncoding = true;
|
||||||
EnableSubtitleExtraction = true;
|
EnableSubtitleExtraction = true;
|
||||||
HardwareDecodingCodecs = new string[] { "h264", "vc1" };
|
HardwareDecodingCodecs = new string[] { "h264", "vc1" };
|
||||||
|
|
Loading…
Reference in New Issue
Block a user