mirror of https://github.com/jellyfin/jellyfin.git
Implement hardware filters for videotoolbox, use Apple AAC encoder when available (#7807)
This commit is contained in:
parent
0b1475af30
commit
ef4ae9a2dd
|
@ -559,6 +559,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
// Use Apple's aac encoder if available as it provides best audio quality
|
||||||
|
if (_mediaEncoder.SupportsEncoder("aac_at"))
|
||||||
|
{
|
||||||
|
return "aac_at";
|
||||||
|
}
|
||||||
|
|
||||||
// Use libfdk_aac for better audio quality if using custom build of FFmpeg which has fdk_aac support
|
// Use libfdk_aac for better audio quality if using custom build of FFmpeg which has fdk_aac support
|
||||||
if (_mediaEncoder.SupportsEncoder("libfdk_aac"))
|
if (_mediaEncoder.SupportsEncoder("libfdk_aac"))
|
||||||
{
|
{
|
||||||
|
@ -2814,6 +2820,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
return "deinterlace_qsv=mode=2";
|
return "deinterlace_qsv=mode=2";
|
||||||
}
|
}
|
||||||
|
else if (hwDeintSuffix.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"yadif_videotoolbox={0}:-1:0",
|
||||||
|
doubleRateDeint ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -4450,6 +4463,75 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
return (mainFilters, subFilters, overlayFilters);
|
return (mainFilters, subFilters, overlayFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parameter of Apple VideoToolBox filter chain.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Encoding state.</param>
|
||||||
|
/// <param name="options">Encoding options.</param>
|
||||||
|
/// <param name="vidEncoder">Video encoder to use.</param>
|
||||||
|
/// <returns>The tuple contains three lists: main, sub and overlay filters.</returns>
|
||||||
|
public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetAppleVidFilterChain(
|
||||||
|
EncodingJobInfo state,
|
||||||
|
EncodingOptions options,
|
||||||
|
string vidEncoder)
|
||||||
|
{
|
||||||
|
if (!string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return (null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var swFilterChain = GetSwVidFilterChain(state, options, vidEncoder);
|
||||||
|
|
||||||
|
if (!options.EnableHardwareEncoding)
|
||||||
|
{
|
||||||
|
return swFilterChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mediaEncoder.EncoderVersion.CompareTo(new Version("5.0.0")) < 0)
|
||||||
|
{
|
||||||
|
// All features used here requires ffmpeg 5.0 or later, fallback to software filters if using an old ffmpeg
|
||||||
|
return swFilterChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
||||||
|
var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
||||||
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
|
var inW = state.VideoStream?.Width;
|
||||||
|
var inH = state.VideoStream?.Height;
|
||||||
|
var reqW = state.BaseRequest.Width;
|
||||||
|
var reqH = state.BaseRequest.Height;
|
||||||
|
var reqMaxW = state.BaseRequest.MaxWidth;
|
||||||
|
var reqMaxH = state.BaseRequest.MaxHeight;
|
||||||
|
var threeDFormat = state.MediaSource.Video3DFormat;
|
||||||
|
var newfilters = new List<string>();
|
||||||
|
var noOverlay = swFilterChain.OverlayFilters.Count == 0;
|
||||||
|
var supportsHwDeint = _mediaEncoder.SupportsFilter("yadif_videotoolbox");
|
||||||
|
// fallback to software filters if we are using filters not supported by hardware yet.
|
||||||
|
var useHardwareFilters = noOverlay && (!doDeintH2645 || supportsHwDeint);
|
||||||
|
|
||||||
|
if (!useHardwareFilters)
|
||||||
|
{
|
||||||
|
return swFilterChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ffmpeg cannot use videotoolbox to scale
|
||||||
|
var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH);
|
||||||
|
newfilters.Add(swScaleFilter);
|
||||||
|
|
||||||
|
// hwupload on videotoolbox encoders can automatically convert AVFrame into its CVPixelBuffer equivalent
|
||||||
|
// videotoolbox will automatically convert the CVPixelBuffer to a pixel format the encoder supports, so we don't have to set a pixel format explicitly here
|
||||||
|
// This will reduce CPU usage significantly on UHD videos with 10 bit colors because we bypassed the ffmpeg pixel format conversion
|
||||||
|
newfilters.Add("hwupload");
|
||||||
|
|
||||||
|
if (doDeintH2645)
|
||||||
|
{
|
||||||
|
var deintFilter = GetHwDeinterlaceFilter(state, options, "videotoolbox");
|
||||||
|
newfilters.Add(deintFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (newfilters, swFilterChain.SubFilters, swFilterChain.OverlayFilters);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter of video processing filters.
|
/// Gets the parameter of video processing filters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -4492,6 +4574,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
(mainFilters, subFilters, overlayFilters) = GetAmdVidFilterChain(state, options, outputVideoCodec);
|
(mainFilters, subFilters, overlayFilters) = GetAmdVidFilterChain(state, options, outputVideoCodec);
|
||||||
}
|
}
|
||||||
|
else if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
(mainFilters, subFilters, overlayFilters) = GetAppleVidFilterChain(state, options, outputVideoCodec);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(mainFilters, subFilters, overlayFilters) = GetSwVidFilterChain(state, options, outputVideoCodec);
|
(mainFilters, subFilters, overlayFilters) = GetSwVidFilterChain(state, options, outputVideoCodec);
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
"libvpx",
|
"libvpx",
|
||||||
"libvpx-vp9",
|
"libvpx-vp9",
|
||||||
"aac",
|
"aac",
|
||||||
|
"aac_at",
|
||||||
"libfdk_aac",
|
"libfdk_aac",
|
||||||
"ac3",
|
"ac3",
|
||||||
"libmp3lame",
|
"libmp3lame",
|
||||||
|
@ -106,7 +107,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
// vulkan
|
// vulkan
|
||||||
"libplacebo",
|
"libplacebo",
|
||||||
"scale_vulkan",
|
"scale_vulkan",
|
||||||
"overlay_vulkan"
|
"overlay_vulkan",
|
||||||
|
"hwupload_vaapi",
|
||||||
|
// videotoolbox
|
||||||
|
"yadif_videotoolbox"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly IReadOnlyDictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
private static readonly IReadOnlyDictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
||||||
|
|
Loading…
Reference in New Issue