"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs" between
jellyfin-10.8.9.tar.gz and jellyfin-10.8.10.tar.gz

About: Jellyfin is a suite of multimedia applications that puts you in control of managing and streaming your digital media.

EncodingHelper.cs  (jellyfin-10.8.9):EncodingHelper.cs  (jellyfin-10.8.10)
skipping to change at line 44 skipping to change at line 44
private readonly IApplicationPaths _appPaths; private readonly IApplicationPaths _appPaths;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly ISubtitleEncoder _subtitleEncoder; private readonly ISubtitleEncoder _subtitleEncoder;
private readonly IConfiguration _config; private readonly IConfiguration _config;
// i915 hang was fixed by linux 6.2 (3f882f2) // i915 hang was fixed by linux 6.2 (3f882f2)
private readonly Version _minKerneli915Hang = new Version(5, 18); private readonly Version _minKerneli915Hang = new Version(5, 18);
private readonly Version _maxKerneli915Hang = new Version(6, 1, 3); private readonly Version _maxKerneli915Hang = new Version(6, 1, 3);
private readonly Version _minFixedKernel60i915Hang = new Version(6, 0, 1 8); private readonly Version _minFixedKernel60i915Hang = new Version(6, 0, 1 8);
private readonly Version _minFFmpegImplictHwaccel = new Version(6, 0);
private readonly Version _minFFmpegHwaUnsafeOutput = new Version(6, 0);
private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1,
3);
private static readonly string[] _videoProfilesH264 = new[] private static readonly string[] _videoProfilesH264 = new[]
{ {
"ConstrainedBaseline", "ConstrainedBaseline",
"Baseline", "Baseline",
"Extended", "Extended",
"Main", "Main",
"High", "High",
"ProgressiveHigh", "ProgressiveHigh",
"ConstrainedHigh", "ConstrainedHigh",
"High10" "High10"
}; };
private static readonly string[] _videoProfilesH265 = new[] private static readonly string[] _videoProfilesH265 = new[]
{ {
"Main", "Main",
"Main10" "Main10"
}; };
public static readonly string[] LosslessAudioCodecs = new string[]
{
"alac",
"ape",
"flac",
"mlp",
"truehd",
"wavpack"
};
public EncodingHelper( public EncodingHelper(
IApplicationPaths appPaths, IApplicationPaths appPaths,
IMediaEncoder mediaEncoder, IMediaEncoder mediaEncoder,
ISubtitleEncoder subtitleEncoder, ISubtitleEncoder subtitleEncoder,
IConfiguration config) IConfiguration config)
{ {
_appPaths = appPaths; _appPaths = appPaths;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_subtitleEncoder = subtitleEncoder; _subtitleEncoder = subtitleEncoder;
_config = config; _config = config;
skipping to change at line 548 skipping to change at line 562
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase) ) if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase) )
{ {
return "libopus"; return "libopus";
} }
if (string.Equals(codec, "flac", StringComparison.OrdinalIgnoreCase) ) if (string.Equals(codec, "flac", StringComparison.OrdinalIgnoreCase) )
{ {
return "flac"; return "flac";
} }
if (string.Equals(codec, "dts", StringComparison.OrdinalIgnoreCase))
{
return "dca";
}
return codec.ToLowerInvariant(); return codec.ToLowerInvariant();
} }
private string GetVideoToolboxDeviceArgs(string alias) private string GetVideoToolboxDeviceArgs(string alias)
{ {
alias ??= VideotoolboxAlias; alias ??= VideotoolboxAlias;
// device selection in vt is not supported. // device selection in vt is not supported.
return " -init_hw_device videotoolbox=" + alias; return " -init_hw_device videotoolbox=" + alias;
} }
skipping to change at line 650 skipping to change at line 669
private string GetFilterHwDeviceArgs(string alias) private string GetFilterHwDeviceArgs(string alias)
{ {
return string.IsNullOrEmpty(alias) return string.IsNullOrEmpty(alias)
? string.Empty ? string.Empty
: " -filter_hw_device " + alias; : " -filter_hw_device " + alias;
} }
public string GetGraphicalSubCanvasSize(EncodingJobInfo state) public string GetGraphicalSubCanvasSize(EncodingJobInfo state)
{ {
// DVBSUB and DVDSUB use the fixed canvas size 720x576
if (state.SubtitleStream != null if (state.SubtitleStream != null
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
&& !state.SubtitleStream.IsTextSubtitleStream) && !state.SubtitleStream.IsTextSubtitleStream
&& !string.Equals(state.SubtitleStream.Codec, "DVBSUB", StringCo
mparison.OrdinalIgnoreCase)
&& !string.Equals(state.SubtitleStream.Codec, "DVDSUB", StringCo
mparison.OrdinalIgnoreCase))
{ {
var inW = state.VideoStream?.Width; var inW = state.VideoStream?.Width;
var inH = state.VideoStream?.Height; var inH = state.VideoStream?.Height;
var reqW = state.BaseRequest.Width; var reqW = state.BaseRequest.Width;
var reqH = state.BaseRequest.Height; var reqH = state.BaseRequest.Height;
var reqMaxW = state.BaseRequest.MaxWidth; var reqMaxW = state.BaseRequest.MaxWidth;
var reqMaxH = state.BaseRequest.MaxHeight; var reqMaxH = state.BaseRequest.MaxHeight;
// setup a relative small canvas_size for overlay_qsv/vaapi to r educe transfer overhead // setup a relative small canvas_size for overlay_qsv/vaapi to r educe transfer overhead
var (overlayW, overlayH) = GetFixedOutputSize(inW, inH, reqW, re qH, reqMaxW, 1080); var (overlayW, overlayH) = GetFixedOutputSize(inW, inH, reqW, re qH, reqMaxW, 1080);
skipping to change at line 1444 skipping to change at line 1466
} }
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison. OrdinalIgnoreCase) // h264 (h264_nvenc) else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison. OrdinalIgnoreCase) // h264 (h264_nvenc)
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparis on.OrdinalIgnoreCase)) // hevc (hevc_nvenc) || string.Equals(videoEncoder, "hevc_nvenc", StringComparis on.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
{ {
switch (encodingOptions.EncoderPreset) switch (encodingOptions.EncoderPreset)
{ {
case "veryslow": case "veryslow":
param += " -preset p7"; param += " -preset p7";
break; break;
case "slow": case "slower":
param += " -preset p6"; param += " -preset p6";
break; break;
case "slower": case "slow":
param += " -preset p5"; param += " -preset p5";
break; break;
case "medium": case "medium":
param += " -preset p4"; param += " -preset p4";
break; break;
case "fast": case "fast":
param += " -preset p3"; param += " -preset p3";
break; break;
skipping to change at line 1481 skipping to change at line 1503
param += " -preset p1"; param += " -preset p1";
break; break;
} }
} }
else if (string.Equals(videoEncoder, "h264_amf", StringComparison.Or dinalIgnoreCase) // h264 (h264_amf) else if (string.Equals(videoEncoder, "h264_amf", StringComparison.Or dinalIgnoreCase) // h264 (h264_amf)
|| string.Equals(videoEncoder, "hevc_amf", StringComparison .OrdinalIgnoreCase)) // hevc (hevc_amf) || string.Equals(videoEncoder, "hevc_amf", StringComparison .OrdinalIgnoreCase)) // hevc (hevc_amf)
{ {
switch (encodingOptions.EncoderPreset) switch (encodingOptions.EncoderPreset)
{ {
case "veryslow": case "veryslow":
case "slow":
case "slower": case "slower":
case "slow":
param += " -quality quality"; param += " -quality quality";
break; break;
case "medium": case "medium":
param += " -quality balanced"; param += " -quality balanced";
break; break;
case "fast": case "fast":
case "faster": case "faster":
case "veryfast": case "veryfast":
skipping to change at line 1955 skipping to change at line 1977
{ {
return false; return false;
} }
if (audioStream.SampleRate.Value > request.AudioSampleRate.Value ) if (audioStream.SampleRate.Value > request.AudioSampleRate.Value )
{ {
return false; return false;
} }
} }
// Video bitrate must fall within requested value // Audio bitrate must fall within requested value
if (request.AudioBitRate.HasValue if (request.AudioBitRate.HasValue
&& audioStream.BitDepth.HasValue && audioStream.BitRate.HasValue
&& audioStream.BitRate.Value > request.AudioBitRate.Value) && audioStream.BitRate.Value > request.AudioBitRate.Value)
{ {
return false; return false;
} }
return request.EnableAutoStreamCopy; return request.EnableAutoStreamCopy;
} }
public int GetVideoBitrateParamValue(BaseEncodingJobOptions request, Med iaStream videoStream, string outputVideoCodec) public int GetVideoBitrateParamValue(BaseEncodingJobOptions request, Med iaStream videoStream, string outputVideoCodec)
{ {
skipping to change at line 2021 skipping to change at line 2043
sourceBitrate *= 2; sourceBitrate *= 2;
} }
var bitrate = Math.Min(sourceBitrate, requestedBitrate); var bitrate = Math.Min(sourceBitrate, requestedBitrate);
return bitrate; return bitrate;
} }
private static double GetVideoBitrateScaleFactor(string codec) private static double GetVideoBitrateScaleFactor(string codec)
{ {
// hevc & vp9 - 40% more efficient than h.264
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCa se) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCa se)
|| string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCas || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCas
e) e))
|| string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCas
e))
{ {
return .6; return .6;
} }
// av1 - 50% more efficient than h.264
if (string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCase))
{
return .5;
}
return 1; return 1;
} }
private static int ScaleBitrate(int bitrate, string inputVideoCodec, str ing outputVideoCodec) private static int ScaleBitrate(int bitrate, string inputVideoCodec, str ing outputVideoCodec)
{ {
var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec); var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec) ; var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec) ;
var scaleFactor = outputScaleFactor / inputScaleFactor;
// Don't scale the real bitrate lower than the requested bitrate
var scaleFactor = Math.Min(outputScaleFactor / inputScaleFactor, 1);
if (bitrate <= 500000) if (bitrate <= 500000)
{ {
scaleFactor = Math.Max(scaleFactor, 4); scaleFactor = Math.Max(scaleFactor, 4);
} }
else if (bitrate <= 1000000) else if (bitrate <= 1000000)
{ {
scaleFactor = Math.Max(scaleFactor, 3); scaleFactor = Math.Max(scaleFactor, 3);
} }
else if (bitrate <= 2000000) else if (bitrate <= 2000000)
skipping to change at line 2058 skipping to change at line 2088
scaleFactor = Math.Max(scaleFactor, 2.5); scaleFactor = Math.Max(scaleFactor, 2.5);
} }
else if (bitrate <= 3000000) else if (bitrate <= 3000000)
{ {
scaleFactor = Math.Max(scaleFactor, 2); scaleFactor = Math.Max(scaleFactor, 2);
} }
return Convert.ToInt32(scaleFactor * bitrate); return Convert.ToInt32(scaleFactor * bitrate);
} }
public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaSt ream audioStream) public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaSt ream audioStream, int? outputAudioChannels)
{ {
return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec , audioStream); return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec , audioStream, outputAudioChannels);
} }
public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, M ediaStream audioStream) public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, M ediaStream audioStream, int? outputAudioChannels)
{ {
if (audioStream == null) if (audioStream == null)
{ {
return null; return null;
} }
if (audioBitRate.HasValue && string.IsNullOrEmpty(audioCodec)) var inputChannels = audioStream.Channels ?? 0;
{ var outputChannels = outputAudioChannels ?? 0;
return Math.Min(384000, audioBitRate.Value); var bitrate = audioBitRate ?? int.MaxValue;
if (string.IsNullOrEmpty(audioCodec)
|| string.Equals(audioCodec, "aac", StringComparison.OrdinalIgno
reCase)
|| string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgno
reCase)
|| string.Equals(audioCodec, "opus", StringComparison.OrdinalIgn
oreCase)
|| string.Equals(audioCodec, "vorbis", StringComparison.OrdinalI
gnoreCase)
|| string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgno
reCase)
|| string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgn
oreCase))
{
return (inputChannels, outputChannels) switch
{
(>= 6, >= 6 or 0) => Math.Min(640000, bitrate),
(> 0, > 0) => Math.Min(outputChannels * 128000, bitrate),
(> 0, _) => Math.Min(inputChannels * 128000, bitrate),
(_, _) => Math.Min(384000, bitrate)
};
} }
if (audioBitRate.HasValue && !string.IsNullOrEmpty(audioCodec)) if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreC
ase)
|| string.Equals(audioCodec, "dca", StringComparison.OrdinalIgno
reCase))
{ {
if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgn return (inputChannels, outputChannels) switch
oreCase)
|| string.Equals(audioCodec, "mp3", StringComparison.Ordinal
IgnoreCase)
|| string.Equals(audioCodec, "opus", StringComparison.Ordina
lIgnoreCase)
|| string.Equals(audioCodec, "vorbis", StringComparison.Ordi
nalIgnoreCase)
|| string.Equals(audioCodec, "ac3", StringComparison.Ordinal
IgnoreCase)
|| string.Equals(audioCodec, "eac3", StringComparison.Ordina
lIgnoreCase))
{
if ((audioStream.Channels ?? 0) >= 6)
{
return Math.Min(640000, audioBitRate.Value);
}
return Math.Min(384000, audioBitRate.Value);
}
if (string.Equals(audioCodec, "flac", StringComparison.OrdinalIg
noreCase)
|| string.Equals(audioCodec, "alac", StringComparison.Ordina
lIgnoreCase))
{ {
if ((audioStream.Channels ?? 0) >= 6) (>= 6, >= 6 or 0) => Math.Min(768000, bitrate),
{ (> 0, > 0) => Math.Min(outputChannels * 136000, bitrate),
return Math.Min(3584000, audioBitRate.Value); (> 0, _) => Math.Min(inputChannels * 136000, bitrate),
} (_, _) => Math.Min(672000, bitrate)
};
return Math.Min(1536000, audioBitRate.Value);
}
} }
// Empty bitrate area is not allow on iOS // Empty bitrate area is not allow on iOS
// Default audio bitrate to 128K if it is not being requested // Default audio bitrate to 128K per channel if we don't have codec specific defaults
// https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options
return 128000; return 128000 * (outputAudioChannels ?? audioStream.Channels ?? 2);
} }
public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions)
{ {
var channels = state.OutputAudioChannels; var channels = state.OutputAudioChannels;
var filters = new List<string>(); var filters = new List<string>();
// Boost volume to 200% when downsampling from 6ch to 2ch // Boost volume to 200% when downsampling from 6ch to 2ch
if (channels.HasValue if (channels.HasValue
skipping to change at line 2401 skipping to change at line 2430
args += string.Format( args += string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
" -map 1:{0} -sn", " -map 1:{0} -sn",
externalSubtitleStreamIndex); externalSubtitleStreamIndex);
} }
return args; return args;
} }
/// <summary> /// <summary>
/// Gets the negative map args by filters.
/// </summary>
/// <param name="state">The state.</param>
/// <param name="videoProcessFilters">The videoProcessFilters.</param>
/// <returns>System.String.</returns>
public string GetNegativeMapArgsByFilters(EncodingJobInfo state, string
videoProcessFilters)
{
string args = string.Empty;
// http://ffmpeg.org/ffmpeg-all.html#toc-Complex-filtergraphs-1
if (state.VideoStream != null && videoProcessFilters.Contains("-filt
er_complex", StringComparison.Ordinal))
{
int videoStreamIndex = FindIndex(state.MediaSource.MediaStreams,
state.VideoStream);
args += string.Format(
CultureInfo.InvariantCulture,
"-map -0:{0} ",
videoStreamIndex);
}
return args;
}
/// <summary>
/// Determines which stream will be used for playback. /// Determines which stream will be used for playback.
/// </summary> /// </summary>
/// <param name="allStream">All stream.</param> /// <param name="allStream">All stream.</param>
/// <param name="desiredIndex">Index of the desired.</param> /// <param name="desiredIndex">Index of the desired.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <param name="returnFirstIfNoIndex">if set to <c>true</c> [return fir st if no index].</param> /// <param name="returnFirstIfNoIndex">if set to <c>true</c> [return fir st if no index].</param>
/// <returns>MediaStream.</returns> /// <returns>MediaStream.</returns>
public MediaStream GetMediaStream(IEnumerable<MediaStream> allStream, in t? desiredIndex, MediaStreamType type, bool returnFirstIfNoIndex = true) public MediaStream GetMediaStream(IEnumerable<MediaStream> allStream, in t? desiredIndex, MediaStreamType type, bool returnFirstIfNoIndex = true)
{ {
var streams = allStream.Where(s => s.Type == type).OrderBy(i => i.In dex).ToList(); var streams = allStream.Where(s => s.Type == type).OrderBy(i => i.In dex).ToList();
skipping to change at line 2770 skipping to change at line 2823
doubleRateDeint ? "field" : "frame"); doubleRateDeint ? "field" : "frame");
} }
else if (hwDeintSuffix.Contains("qsv", StringComparison.OrdinalIgnor eCase)) else if (hwDeintSuffix.Contains("qsv", StringComparison.OrdinalIgnor eCase))
{ {
return "deinterlace_qsv=mode=2"; return "deinterlace_qsv=mode=2";
} }
return string.Empty; return string.Empty;
} }
public static string GetHwTonemapFilter(EncodingOptions options, string hwTonemapSuffix, string videoFormat) public string GetHwTonemapFilter(EncodingOptions options, string hwTonem apSuffix, string videoFormat)
{ {
if (string.IsNullOrEmpty(hwTonemapSuffix)) if (string.IsNullOrEmpty(hwTonemapSuffix))
{ {
return string.Empty; return string.Empty;
} }
var args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709"; var args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709";
if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnore Case)) if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnore Case))
{ {
args += ",procamp_vaapi=b={2}:c={3}:extra_hw_frames=16"; args = "procamp_vaapi=b={2}:c={3}," + args + ":extra_hw_frames=3
2";
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
args, args,
hwTonemapSuffix, hwTonemapSuffix,
videoFormat ?? "nv12", videoFormat ?? "nv12",
options.VppTonemappingBrightness, options.VppTonemappingBrightness,
options.VppTonemappingContrast); options.VppTonemappingContrast);
} }
else else
{ {
args += ":tonemap={2}:peak={3}:desat={4}"; args += ":tonemap={2}:peak={3}:desat={4}";
if (string.Equals(options.TonemappingMode, "max", StringComparis
on.OrdinalIgnoreCase)
|| string.Equals(options.TonemappingMode, "rgb", StringCompa
rison.OrdinalIgnoreCase))
{
if (_mediaEncoder.EncoderVersion >= _minFFmpegOclCuTonemapMo
de)
{
args += ":tonemap_mode={5}";
}
}
if (options.TonemappingParam != 0) if (options.TonemappingParam != 0)
{ {
args += ":param={5}"; args += ":param={6}";
} }
if (!string.Equals(options.TonemappingRange, "auto", StringCompa if (string.Equals(options.TonemappingRange, "tv", StringComparis
rison.OrdinalIgnoreCase)) on.OrdinalIgnoreCase)
|| string.Equals(options.TonemappingRange, "pc", StringCompa
rison.OrdinalIgnoreCase))
{ {
args += ":range={6}"; args += ":range={7}";
} }
} }
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
args, args,
hwTonemapSuffix, hwTonemapSuffix,
videoFormat ?? "nv12", videoFormat ?? "nv12",
options.TonemappingAlgorithm, options.TonemappingAlgorithm,
options.TonemappingPeak, options.TonemappingPeak,
options.TonemappingDesat, options.TonemappingDesat,
options.TonemappingMode,
options.TonemappingParam, options.TonemappingParam,
options.TonemappingRange); options.TonemappingRange);
} }
/// <summary> /// <summary>
/// Gets the parameter of software filter chain. /// Gets the parameter of software filter chain.
/// </summary> /// </summary>
/// <param name="state">Encoding state.</param> /// <param name="state">Encoding state.</param>
/// <param name="options">Encoding options.</param> /// <param name="options">Encoding options.</param>
/// <param name="vidEncoder">Video encoder to use.</param> /// <param name="vidEncoder">Video encoder to use.</param>
skipping to change at line 3217 skipping to change at line 3282
} }
var memoryOutput = false; var memoryOutput = false;
var isUploadForOclTonemap = isSwDecoder && doOclTonemap; var isUploadForOclTonemap = isSwDecoder && doOclTonemap;
if (isD3d11vaDecoder && isSwEncoder) if (isD3d11vaDecoder && isSwEncoder)
{ {
memoryOutput = true; memoryOutput = true;
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl. // prefer hwmap to hwdownload on opencl.
var hwTransferFilter = hasGraphicalSubs ? "hwdownload" : "hwmap" ; var hwTransferFilter = hasGraphicalSubs ? "hwdownload" : "hwmap= mode=read";
mainFilters.Add(hwTransferFilter); mainFilters.Add(hwTransferFilter);
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
// OUTPUT yuv420p surface // OUTPUT yuv420p surface
if (isSwDecoder && isAmfEncoder && !isUploadForOclTonemap) if (isSwDecoder && isAmfEncoder && !isUploadForOclTonemap)
{ {
memoryOutput = true; memoryOutput = true;
} }
skipping to change at line 3460 skipping to change at line 3525
var memoryOutput = false; var memoryOutput = false;
var isUploadForOclTonemap = isSwDecoder && doOclTonemap; var isUploadForOclTonemap = isSwDecoder && doOclTonemap;
var isHwmapUsable = isSwEncoder && doOclTonemap; var isHwmapUsable = isSwEncoder && doOclTonemap;
if ((isHwDecoder && isSwEncoder) || isUploadForOclTonemap) if ((isHwDecoder && isSwEncoder) || isUploadForOclTonemap)
{ {
memoryOutput = true; memoryOutput = true;
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl. // prefer hwmap to hwdownload on opencl.
// qsv hwmap is not fully implemented for the time being. // qsv hwmap is not fully implemented for the time being.
mainFilters.Add(isHwmapUsable ? "hwmap" : "hwdownload"); mainFilters.Add(isHwmapUsable ? "hwmap=mode=read" : "hwdownload" );
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
if (isSwDecoder && isQsvEncoder) if (isSwDecoder && isQsvEncoder)
{ {
memoryOutput = true; memoryOutput = true;
} }
if (memoryOutput) if (memoryOutput)
skipping to change at line 3618 skipping to change at line 3683
// INPUT vaapi/qsv surface(vram) // INPUT vaapi/qsv surface(vram)
// hw deint // hw deint
if (doDeintH2645) if (doDeintH2645)
{ {
var deintFilter = GetHwDeinterlaceFilter(state, options, isV aapiDecoder ? "vaapi" : "qsv"); var deintFilter = GetHwDeinterlaceFilter(state, options, isV aapiDecoder ? "vaapi" : "qsv");
mainFilters.Add(deintFilter); mainFilters.Add(deintFilter);
} }
var outFormat = doTonemap ? string.Empty : "nv12"; var outFormat = doTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter(isVaapiDecoder ? "vaapi" : "qsv", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter(isVaapiDecoder ? "vaapi" : "qsv", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter) && isVaapiDecoder)
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
// vaapi vpp tonemap // vaapi vpp tonemap
if (doVaVppTonemap && isHwDecoder) if (doVaVppTonemap && isHwDecoder)
{ {
if (isQsvDecoder) if (isQsvDecoder)
{ {
// map from qsv to vaapi. // map from qsv to vaapi.
skipping to change at line 3664 skipping to change at line 3736
var memoryOutput = false; var memoryOutput = false;
var isUploadForOclTonemap = isSwDecoder && doOclTonemap; var isUploadForOclTonemap = isSwDecoder && doOclTonemap;
var isHwmapUsable = isSwEncoder && (doOclTonemap || isVaapiDecoder); var isHwmapUsable = isSwEncoder && (doOclTonemap || isVaapiDecoder);
if ((isHwDecoder && isSwEncoder) || isUploadForOclTonemap) if ((isHwDecoder && isSwEncoder) || isUploadForOclTonemap)
{ {
memoryOutput = true; memoryOutput = true;
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl/vaapi. // prefer hwmap to hwdownload on opencl/vaapi.
// qsv hwmap is not fully implemented for the time being. // qsv hwmap is not fully implemented for the time being.
mainFilters.Add(isHwmapUsable ? "hwmap" : "hwdownload"); mainFilters.Add(isHwmapUsable ? "hwmap=mode=read" : "hwdownload" );
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
if (isSwDecoder && isQsvEncoder) if (isSwDecoder && isQsvEncoder)
{ {
memoryOutput = true; memoryOutput = true;
} }
if (memoryOutput) if (memoryOutput)
skipping to change at line 3881 skipping to change at line 3953
// INPUT vaapi surface(vram) // INPUT vaapi surface(vram)
// hw deint // hw deint
if (doDeintH2645) if (doDeintH2645)
{ {
var deintFilter = GetHwDeinterlaceFilter(state, options, "va api"); var deintFilter = GetHwDeinterlaceFilter(state, options, "va api");
mainFilters.Add(deintFilter); mainFilters.Add(deintFilter);
} }
var outFormat = doTonemap ? string.Empty : "nv12"; var outFormat = doTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, in H, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, in H, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter))
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
// vaapi vpp tonemap // vaapi vpp tonemap
if (doVaVppTonemap && isVaapiDecoder) if (doVaVppTonemap && isVaapiDecoder)
{ {
var tonemapFilter = GetHwTonemapFilter(options, "vaapi", "nv12") ; var tonemapFilter = GetHwTonemapFilter(options, "vaapi", "nv12") ;
mainFilters.Add(tonemapFilter); mainFilters.Add(tonemapFilter);
} }
skipping to change at line 3922 skipping to change at line 4001
var memoryOutput = false; var memoryOutput = false;
var isUploadForOclTonemap = isSwDecoder && doOclTonemap; var isUploadForOclTonemap = isSwDecoder && doOclTonemap;
var isHwmapNotUsable = isUploadForOclTonemap && isVaapiEncoder; var isHwmapNotUsable = isUploadForOclTonemap && isVaapiEncoder;
if ((isVaapiDecoder && isSwEncoder) || isUploadForOclTonemap) if ((isVaapiDecoder && isSwEncoder) || isUploadForOclTonemap)
{ {
memoryOutput = true; memoryOutput = true;
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
// prefer hwmap to hwdownload on opencl/vaapi. // prefer hwmap to hwdownload on opencl/vaapi.
mainFilters.Add(isHwmapNotUsable ? "hwdownload" : "hwmap"); mainFilters.Add(isHwmapNotUsable ? "hwdownload" : "hwmap=mode=re ad");
mainFilters.Add("format=nv12"); mainFilters.Add("format=nv12");
} }
// OUTPUT nv12 surface(memory) // OUTPUT nv12 surface(memory)
if (isSwDecoder && isVaapiEncoder) if (isSwDecoder && isVaapiEncoder)
{ {
memoryOutput = true; memoryOutput = true;
} }
if (memoryOutput) if (memoryOutput)
skipping to change at line 4075 skipping to change at line 4154
// INPUT vaapi surface(vram) // INPUT vaapi surface(vram)
// hw deint // hw deint
if (doDeintH2645) if (doDeintH2645)
{ {
var deintFilter = GetHwDeinterlaceFilter(state, options, "va api"); var deintFilter = GetHwDeinterlaceFilter(state, options, "va api");
mainFilters.Add(deintFilter); mainFilters.Add(deintFilter);
} }
outFormat = doOclTonemap ? string.Empty : "nv12"; outFormat = doOclTonemap ? string.Empty : "nv12";
var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, in H, reqW, reqH, reqMaxW, reqMaxH); var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, in H, reqW, reqH, reqMaxW, reqMaxH);
// allocate extra pool sizes for vaapi vpp
if (!string.IsNullOrEmpty(hwScaleFilter))
{
hwScaleFilter += ":extra_hw_frames=24";
}
// hw scale // hw scale
mainFilters.Add(hwScaleFilter); mainFilters.Add(hwScaleFilter);
} }
if (doOclTonemap && isVaapiDecoder) if (doOclTonemap && isVaapiDecoder)
{ {
if (isi965Driver) if (isi965Driver)
{ {
// map from vaapi to opencl via vaapi-opencl interop(Intel o nly). // map from vaapi to opencl via vaapi-opencl interop(Intel o nly).
mainFilters.Add("hwmap=derive_device=opencl"); mainFilters.Add("hwmap=derive_device=opencl");
skipping to change at line 4379 skipping to change at line 4465
protected string GetHardwareVideoDecoder(EncodingJobInfo state, Encoding Options options) protected string GetHardwareVideoDecoder(EncodingJobInfo state, Encoding Options options)
{ {
var videoStream = state.VideoStream; var videoStream = state.VideoStream;
var mediaSource = state.MediaSource; var mediaSource = state.MediaSource;
if (videoStream == null || mediaSource == null) if (videoStream == null || mediaSource == null)
{ {
return null; return null;
} }
// HWA decoders can handle both video files and video folders. // HWA decoders can handle both video files and video folders.
var videoType = mediaSource.VideoType; var videoType = state.VideoType;
if (videoType != VideoType.VideoFile if (videoType != VideoType.VideoFile
&& videoType != VideoType.Iso && videoType != VideoType.Iso
&& videoType != VideoType.Dvd && videoType != VideoType.Dvd
&& videoType != VideoType.BluRay) && videoType != VideoType.BluRay)
{ {
return null; return null;
} }
if (IsCopyCodec(state.OutputVideoCodec)) if (IsCopyCodec(state.OutputVideoCodec))
{ {
skipping to change at line 4520 skipping to change at line 4606
var isWindows = OperatingSystem.IsWindows(); var isWindows = OperatingSystem.IsWindows();
var isLinux = OperatingSystem.IsLinux(); var isLinux = OperatingSystem.IsLinux();
var isMacOS = OperatingSystem.IsMacOS(); var isMacOS = OperatingSystem.IsMacOS();
var isD3d11Supported = isWindows && _mediaEncoder.SupportsHwaccel("d 3d11va"); var isD3d11Supported = isWindows && _mediaEncoder.SupportsHwaccel("d 3d11va");
var isVaapiSupported = isLinux && IsVaapiSupported(state); var isVaapiSupported = isLinux && IsVaapiSupported(state);
var isCudaSupported = (isLinux || isWindows) && IsCudaFullSupported( ); var isCudaSupported = (isLinux || isWindows) && IsCudaFullSupported( );
var isQsvSupported = (isLinux || isWindows) && _mediaEncoder.Support sHwaccel("qsv"); var isQsvSupported = (isLinux || isWindows) && _mediaEncoder.Support sHwaccel("qsv");
var isVideotoolboxSupported = isMacOS && _mediaEncoder.SupportsHwacc el("videotoolbox"); var isVideotoolboxSupported = isMacOS && _mediaEncoder.SupportsHwacc el("videotoolbox");
var isCodecAvailable = options.HardwareDecodingCodecs.Contains(video Codec, StringComparison.OrdinalIgnoreCase); var isCodecAvailable = options.HardwareDecodingCodecs.Contains(video Codec, StringComparison.OrdinalIgnoreCase);
var ffmpegVersion = _mediaEncoder.EncoderVersion;
// Set the av1 codec explicitly to trigger hw accelerator, otherwise libdav1d will be used. // Set the av1 codec explicitly to trigger hw accelerator, otherwise libdav1d will be used.
var isAv1 = string.Equals(videoCodec, "av1", StringComparison.Ordina var isAv1 = ffmpegVersion < _minFFmpegImplictHwaccel
lIgnoreCase); && string.Equals(videoCodec, "av1", StringComparison.OrdinalIgno
reCase);
// Allow profile mismatch if decoding H.264 baseline with d3d11va an
d vaapi hwaccels.
var profileMismatch = string.Equals(videoCodec, "h264", StringCompar
ison.OrdinalIgnoreCase)
&& string.Equals(state.VideoStream?.Profile, "baseline", StringC
omparison.OrdinalIgnoreCase);
// Disable the extra internal copy in nvdec. We already handle it in
filter chain.
var nvdecNoInternalCopy = ffmpegVersion >= _minFFmpegHwaUnsafeOutput
;
if (bitDepth == 10 && isCodecAvailable) if (bitDepth == 10 && isCodecAvailable)
{ {
if (string.Equals(videoCodec, "hevc", StringComparison.OrdinalIg noreCase) if (string.Equals(videoCodec, "hevc", StringComparison.OrdinalIg noreCase)
&& options.HardwareDecodingCodecs.Contains("hevc", StringCom parison.OrdinalIgnoreCase) && options.HardwareDecodingCodecs.Contains("hevc", StringCom parison.OrdinalIgnoreCase)
&& !options.EnableDecodingColorDepth10Hevc) && !options.EnableDecodingColorDepth10Hevc)
{ {
return null; return null;
} }
skipping to change at line 4547 skipping to change at line 4643
} }
} }
// Intel qsv/d3d11va/vaapi // Intel qsv/d3d11va/vaapi
if (string.Equals(options.HardwareAccelerationType, "qsv", StringCom parison.OrdinalIgnoreCase)) if (string.Equals(options.HardwareAccelerationType, "qsv", StringCom parison.OrdinalIgnoreCase))
{ {
if (options.PreferSystemNativeHwDecoder) if (options.PreferSystemNativeHwDecoder)
{ {
if (isVaapiSupported && isCodecAvailable) if (isVaapiSupported && isCodecAvailable)
{ {
return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel
_output_format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); _output_format vaapi" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile
_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
if (isD3d11Supported && isCodecAvailable) if (isD3d11Supported && isCodecAvailable)
{ {
// set -threads 3 to intel d3d11va decoder explicitly. L ower threads may result in dead lock. // set -threads 3 to intel d3d11va decoder explicitly. L ower threads may result in dead lock.
// on newer devices such as Xe, the larger the init_pool _size, the longer the initialization time for opencl to derive from d3d11. // on newer devices such as Xe, the larger the init_pool _size, the longer the initialization time for opencl to derive from d3d11.
return " -hwaccel d3d11va" + (outputHwSurface ? " -hwacc return " -hwaccel d3d11va" + (outputHwSurface ? " -hwacc
el_output_format d3d11" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : el_output_format d3d11" : string.Empty)
string.Empty); + (profileMismatch ? " -hwaccel_flags +allow_profile
_mismatch" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty
);
} }
} }
else else
{ {
if (isQsvSupported && isCodecAvailable) if (isQsvSupported && isCodecAvailable)
{ {
return " -hwaccel qsv" + (outputHwSurface ? " -hwaccel_o utput_format qsv" : string.Empty); return " -hwaccel qsv" + (outputHwSurface ? " -hwaccel_o utput_format qsv" : string.Empty);
} }
} }
} }
// Nvidia cuda // Nvidia cuda
if (string.Equals(options.HardwareAccelerationType, "nvenc", StringC omparison.OrdinalIgnoreCase)) if (string.Equals(options.HardwareAccelerationType, "nvenc", StringC omparison.OrdinalIgnoreCase))
{ {
if (isCudaSupported && isCodecAvailable) if (isCudaSupported && isCodecAvailable)
{ {
if (options.EnableEnhancedNvdecDecoder) if (options.EnableEnhancedNvdecDecoder)
{ {
// set -threads 1 to nvdec decoder explicitly since it d oesn't implement threading support. // set -threads 1 to nvdec decoder explicitly since it d oesn't implement threading support.
return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_ return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_
output_format cuda" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : str output_format cuda" : string.Empty)
ing.Empty); + (nvdecNoInternalCopy ? " -hwaccel_flags +unsafe_ou
tput" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty);
} }
else else
{ {
// cuvid decoder doesn't have threading issue. // cuvid decoder doesn't have threading issue.
return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_ output_format cuda" : string.Empty); return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_ output_format cuda" : string.Empty);
} }
} }
} }
// Amd d3d11va // Amd d3d11va
if (string.Equals(options.HardwareAccelerationType, "amf", StringCom parison.OrdinalIgnoreCase)) if (string.Equals(options.HardwareAccelerationType, "amf", StringCom parison.OrdinalIgnoreCase))
{ {
if (isD3d11Supported && isCodecAvailable) if (isD3d11Supported && isCodecAvailable)
{ {
return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_o return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_o
utput_format d3d11" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); utput_format d3d11" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mis
match" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
} }
// Vaapi // Vaapi
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringC omparison.OrdinalIgnoreCase) if (string.Equals(options.HardwareAccelerationType, "vaapi", StringC omparison.OrdinalIgnoreCase)
&& isVaapiSupported && isVaapiSupported
&& isCodecAvailable) && isCodecAvailable)
{ {
return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_ return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_
format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); format vaapi" : string.Empty)
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatc
h" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty);
} }
// Apple videotoolbox
if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase) if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)
&& isVideotoolboxSupported && isVideotoolboxSupported
&& isCodecAvailable) && isCodecAvailable)
{ {
return " -hwaccel videotoolbox" + (outputHwSurface ? " -hwaccel_ output_format videotoolbox_vld" : string.Empty); return " -hwaccel videotoolbox" + (outputHwSurface ? " -hwaccel_ output_format videotoolbox_vld" : string.Empty);
} }
return null; return null;
} }
skipping to change at line 5216 skipping to change at line 5318
} }
private void ShiftAudioCodecsIfNeeded(List<string> audioCodecs, MediaStr eam audioStream) private void ShiftAudioCodecsIfNeeded(List<string> audioCodecs, MediaStr eam audioStream)
{ {
// No need to shift if there is only one supported audio codec. // No need to shift if there is only one supported audio codec.
if (audioCodecs.Count < 2) if (audioCodecs.Count < 2)
{ {
return; return;
} }
var inputChannels = audioStream == null ? 6 : audioStream.Channels ? var inputChannels = audioStream is null ? 6 : audioStream.Channels ?
? 6; ? 6;
var shiftAudioCodecs = new List<string>();
if (inputChannels >= 6) if (inputChannels >= 6)
{ {
return; // DTS and TrueHD are not supported by HLS
// Keep them in the supported codecs list, but shift them to the
end of the list so that if transcoding happens, another codec is used
shiftAudioCodecs.Add("dca");
shiftAudioCodecs.Add("truehd");
}
else
{
// Transcoding to 2ch ac3 or eac3 almost always causes a playbac
k failure
// Keep them in the supported codecs list, but shift them to the
end of the list so that if transcoding happens, another codec is used
shiftAudioCodecs.Add("ac3");
shiftAudioCodecs.Add("eac3");
} }
// Transcoding to 2ch ac3 almost always causes a playback failure
// Keep it in the supported codecs list, but shift it to the end of
the list so that if transcoding happens, another codec is used
var shiftAudioCodecs = new[] { "ac3", "eac3" };
if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparis on.OrdinalIgnoreCase))) if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparis on.OrdinalIgnoreCase)))
{ {
return; return;
} }
while (shiftAudioCodecs.Contains(audioCodecs[0], StringComparison.Or dinalIgnoreCase)) while (shiftAudioCodecs.Contains(audioCodecs[0], StringComparison.Or dinalIgnoreCase))
{ {
var removed = shiftAudioCodecs[0]; var removed = shiftAudioCodecs[0];
audioCodecs.RemoveAt(0); audioCodecs.RemoveAt(0);
audioCodecs.Add(removed); audioCodecs.Add(removed);
skipping to change at line 5401 skipping to change at line 5511
args += keyFrameArg; args += keyFrameArg;
var hasGraphicalSubs = state.SubtitleStream != null && !state.Su btitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDel iveryMethod.Encode; var hasGraphicalSubs = state.SubtitleStream != null && !state.Su btitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDel iveryMethod.Encode;
var hasCopyTs = false; var hasCopyTs = false;
// video processing filters. // video processing filters.
var videoProcessParam = GetVideoProcessingFilterParam(state, enc odingOptions, videoCodec); var videoProcessParam = GetVideoProcessingFilterParam(state, enc odingOptions, videoCodec);
args += videoProcessParam; var negativeMapArgs = GetNegativeMapArgsByFilters(state, videoPr
ocessParam);
args = negativeMapArgs + args + videoProcessParam;
hasCopyTs = videoProcessParam.Contains("copyts", StringCompariso n.OrdinalIgnoreCase); hasCopyTs = videoProcessParam.Contains("copyts", StringCompariso n.OrdinalIgnoreCase);
if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimesta mps) if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimesta mps)
{ {
if (!hasCopyTs) if (!hasCopyTs)
{ {
args += " -copyts"; args += " -copyts";
} }
skipping to change at line 5466 skipping to change at line 5578
// Add the number of audio channels // Add the number of audio channels
var channels = state.OutputAudioChannels; var channels = state.OutputAudioChannels;
if (channels.HasValue) if (channels.HasValue)
{ {
args += " -ac " + channels.Value; args += " -ac " + channels.Value;
} }
var bitrate = state.OutputAudioBitrate; var bitrate = state.OutputAudioBitrate;
if (bitrate.HasValue) if (bitrate.HasValue && !LosslessAudioCodecs.Contains(codec, StringC omparison.OrdinalIgnoreCase))
{ {
args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCu lture); args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCu lture);
} }
if (state.OutputAudioSampleRate.HasValue) if (state.OutputAudioSampleRate.HasValue)
{ {
args += " -ar " + state.OutputAudioSampleRate.Value.ToString(Cul tureInfo.InvariantCulture); args += " -ar " + state.OutputAudioSampleRate.Value.ToString(Cul tureInfo.InvariantCulture);
} }
args += GetAudioFilterParam(state, encodingOptions); args += GetAudioFilterParam(state, encodingOptions);
return args; return args;
} }
public string GetProgressiveAudioFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath) public string GetProgressiveAudioFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath)
{ {
var audioTranscodeParams = new List<string>(); var audioTranscodeParams = new List<string>();
var bitrate = state.OutputAudioBitrate; var bitrate = state.OutputAudioBitrate;
var channels = state.OutputAudioChannels;
var outputCodec = state.OutputAudioCodec;
if (bitrate.HasValue) if (bitrate.HasValue && !LosslessAudioCodecs.Contains(outputCodec, S tringComparison.OrdinalIgnoreCase))
{ {
audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(Culture Info.InvariantCulture)); audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(Culture Info.InvariantCulture));
} }
if (state.OutputAudioChannels.HasValue) if (state.OutputAudioChannels.HasValue)
{ {
audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Valu e.ToString(CultureInfo.InvariantCulture)); audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Valu e.ToString(CultureInfo.InvariantCulture));
} }
if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison. if (!string.IsNullOrEmpty(outputCodec))
OrdinalIgnoreCase)) {
audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state));
}
if (!string.Equals(outputCodec, "opus", StringComparison.OrdinalIgno
reCase))
{ {
// opus only supports specific sampling rates // opus only supports specific sampling rates
var sampleRate = state.OutputAudioSampleRate; var sampleRate = state.OutputAudioSampleRate;
if (sampleRate.HasValue) if (sampleRate.HasValue)
{ {
var sampleRateValue = sampleRate.Value switch var sampleRateValue = sampleRate.Value switch
{ {
<= 8000 => 8000, <= 8000 => 8000,
<= 12000 => 12000, <= 12000 => 12000,
<= 16000 => 16000, <= 16000 => 16000,
 End of changes. 56 change blocks. 
89 lines changed or deleted 230 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)