aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/MediaEncoding
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding')
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs817
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs54
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs51
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs13
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/JobLogger.cs3
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs6
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs23
12 files changed, 575 insertions, 402 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 91a03e647..feb5883e5 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -10,8 +12,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
@@ -27,9 +27,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private static readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IMediaEncoder _mediaEncoder;
- private readonly IFileSystem _fileSystem;
private readonly ISubtitleEncoder _subtitleEncoder;
- private readonly IConfiguration _configuration;
private static readonly string[] _videoProfiles = new[]
{
@@ -44,14 +42,10 @@ namespace MediaBrowser.Controller.MediaEncoding
public EncodingHelper(
IMediaEncoder mediaEncoder,
- IFileSystem fileSystem,
- ISubtitleEncoder subtitleEncoder,
- IConfiguration configuration)
+ ISubtitleEncoder subtitleEncoder)
{
_mediaEncoder = mediaEncoder;
- _fileSystem = fileSystem;
_subtitleEncoder = subtitleEncoder;
- _configuration = configuration;
}
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
@@ -112,14 +106,57 @@ namespace MediaBrowser.Controller.MediaEncoding
return _mediaEncoder.SupportsHwaccel("vaapi");
}
+ private bool IsCudaSupported()
+ {
+ return _mediaEncoder.SupportsHwaccel("cuda")
+ && _mediaEncoder.SupportsFilter("scale_cuda", null)
+ && _mediaEncoder.SupportsFilter("yadif_cuda", null);
+ }
+
private bool IsTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
{
var videoStream = state.VideoStream;
return IsColorDepth10(state)
&& _mediaEncoder.SupportsHwaccel("opencl")
&& options.EnableTonemapping
- && !string.IsNullOrEmpty(videoStream.VideoRange)
- && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase);
+ && string.Equals(videoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase);
+ }
+
+ private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
+ {
+ var videoStream = state.VideoStream;
+ if (videoStream == null)
+ {
+ // Remote stream doesn't have media info, disable vpp tonemapping.
+ return false;
+ }
+
+ var codec = videoStream.Codec;
+ if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
+ {
+ // Limited to HEVC for now since the filter doesn't accept master data from VP9.
+ return IsColorDepth10(state)
+ && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ && _mediaEncoder.SupportsHwaccel("vaapi")
+ && options.EnableVppTonemapping
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Hybrid VPP tonemapping for QSV with VAAPI
+ var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+ if (isLinux && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ // Limited to HEVC for now since the filter doesn't accept master data from VP9.
+ return IsColorDepth10(state)
+ && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ && _mediaEncoder.SupportsHwaccel("vaapi")
+ && _mediaEncoder.SupportsHwaccel("qsv")
+ && options.EnableVppTonemapping
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Native VPP tonemapping may come to QSV in the future.
+ return false;
}
/// <summary>
@@ -270,6 +307,12 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
+ // ISO files don't have an ffmpeg format
+ if (string.Equals(container, "iso", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
return container;
}
@@ -458,11 +501,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions);
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions);
if (!IsCopyCodec(outputVideoCodec))
{
@@ -472,7 +517,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (isVaapiDecoder)
{
- if (isTonemappingSupported)
+ if (isTonemappingSupported && !isVppTonemappingSupported)
{
arg.Append("-init_hw_device vaapi=va:")
.Append(encodingOptions.VaapiDevice)
@@ -496,6 +541,8 @@ namespace MediaBrowser.Controller.MediaEncoding
.Append(encodingOptions.VaapiDevice)
.Append(' ');
}
+
+ arg.Append("-autorotate 0 ");
}
if (state.IsVideoRequest
@@ -526,16 +573,38 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// While using SW decoder
- else
+ else if (isSwDecoder)
{
arg.Append("-init_hw_device qsv=hw -filter_hw_device hw ");
}
+
+ // Hybrid VPP tonemapping with VAAPI
+ else if (isVaapiDecoder && isVppTonemappingSupported)
+ {
+ arg.Append("-init_hw_device vaapi=va:")
+ .Append(encodingOptions.VaapiDevice)
+ .Append(' ')
+ .Append("-init_hw_device qsv@va ")
+ .Append("-hwaccel_output_format vaapi ");
+ }
+
+ arg.Append("-autorotate 0 ");
}
}
if (state.IsVideoRequest
- && (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
- || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
+ && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
+ && isNvdecDecoder)
+ {
+ // Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562
+ arg.Append("-hwaccel_output_format cuda -extra_hw_frames 3 -autorotate 0 ");
+ }
+
+ if (state.IsVideoRequest
+ && ((string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
+ && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder))
+ || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
+ && (isD3d11vaDecoder || isSwDecoder))))
{
if (isTonemappingSupported)
{
@@ -922,18 +991,23 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var videoStream = state.VideoStream;
var isColorDepth10 = IsColorDepth10(state);
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
- if (isColorDepth10
- && _mediaEncoder.SupportsHwaccel("opencl")
- && encodingOptions.EnableTonemapping
- && !string.IsNullOrEmpty(videoStream.VideoRange)
- && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
- {
- param += " -pix_fmt nv12";
- }
- else
+ if (!isNvdecDecoder)
{
- param += " -pix_fmt yuv420p";
+ if (isColorDepth10
+ && _mediaEncoder.SupportsHwaccel("opencl")
+ && encodingOptions.EnableTonemapping
+ && !string.IsNullOrEmpty(videoStream.VideoRange)
+ && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
+ {
+ param += " -pix_fmt nv12";
+ }
+ else
+ {
+ param += " -pix_fmt yuv420p";
+ }
}
}
@@ -997,7 +1071,6 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
{
- // following preset will be deprecated in ffmpeg 4.4, use p1~p7 instead.
switch (encodingOptions.EncoderPreset)
{
case "veryslow":
@@ -1127,13 +1200,25 @@ namespace MediaBrowser.Controller.MediaEncoding
targetVideoCodec = "hevc";
}
- var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault();
- profile = Regex.Replace(profile, @"\s+", String.Empty);
+ var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault() ?? string.Empty;
+ profile = Regex.Replace(profile, @"\s+", string.Empty);
+
+ // We only transcode to HEVC 8-bit for now, force Main Profile.
+ if (profile.Contains("main10", StringComparison.OrdinalIgnoreCase)
+ || profile.Contains("mainstill", StringComparison.OrdinalIgnoreCase))
+ {
+ profile = "main";
+ }
+
+ // Extended Profile is not supported by any known h264 encoders, force Main Profile.
+ if (profile.Contains("extended", StringComparison.OrdinalIgnoreCase))
+ {
+ profile = "main";
+ }
// Only libx264 support encoding H264 High 10 Profile, otherwise force High Profile.
if (!string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)
- && profile != null
- && profile.IndexOf("high 10", StringComparison.OrdinalIgnoreCase) != -1)
+ && profile.Contains("high10", StringComparison.OrdinalIgnoreCase))
{
profile = "high";
}
@@ -1141,8 +1226,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// h264_vaapi does not support Baseline profile, force Constrained Baseline in this case,
// which is compatible (and ugly).
if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
- && profile != null
- && profile.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) != -1)
+ && profile.Contains("baseline", StringComparison.OrdinalIgnoreCase))
{
profile = "constrained_baseline";
}
@@ -1151,16 +1235,36 @@ namespace MediaBrowser.Controller.MediaEncoding
if ((string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
- && profile != null
- && profile.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) != -1)
+ && profile.Contains("baseline", StringComparison.OrdinalIgnoreCase))
{
profile = "baseline";
}
+ // libx264, h264_qsv, h264_nvenc and h264_vaapi does not support Constrained High profile, force High in this case.
+ if ((string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ && profile.Contains("high", StringComparison.OrdinalIgnoreCase))
+ {
+ profile = "high";
+ }
+
+ if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
+ && profile.Contains("baseline", StringComparison.OrdinalIgnoreCase))
+ {
+ profile = "constrained_baseline";
+ }
+
+ if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
+ && profile.Contains("constrainedhigh", StringComparison.OrdinalIgnoreCase))
+ {
+ profile = "constrained_high";
+ }
+
// Currently hevc_amf only support encoding HEVC Main Profile, otherwise force Main Profile.
- if (!string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)
- && profile != null
- && profile.IndexOf("main 10", StringComparison.OrdinalIgnoreCase) != -1)
+ if (string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)
+ && profile.Contains("main10", StringComparison.OrdinalIgnoreCase))
{
profile = "main";
}
@@ -1287,7 +1391,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var requestedProfile = requestedProfiles[0];
// strip spaces because they may be stripped out on the query string as well
- if (!string.IsNullOrEmpty(videoStream.Profile) && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", ""), StringComparer.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(videoStream.Profile)
+ && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", "", StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase))
{
var currentScore = GetVideoProfileScore(videoStream.Profile);
var requestedScore = GetVideoProfileScore(requestedProfile);
@@ -1616,7 +1721,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (filters.Count > 0)
{
- return " -af \"" + string.Join(",", filters) + "\"";
+ return " -af \"" + string.Join(',', filters) + "\"";
}
return string.Empty;
@@ -1691,6 +1796,16 @@ namespace MediaBrowser.Controller.MediaEncoding
: transcoderChannelLimit.Value;
}
+ // Avoid transcoding to audio channels other than 1ch, 2ch, 6ch (5.1 layout) and 8ch (7.1 layout).
+ // https://developer.apple.com/documentation/http_live_streaming/hls_authoring_specification_for_apple_devices
+ if (isTranscodingAudio
+ && state.TranscodingType != TranscodingJobType.Progressive
+ && resultChannels.HasValue
+ && (resultChannels.Value > 2 && resultChannels.Value < 6 || resultChannels.Value == 7))
+ {
+ resultChannels = 2;
+ }
+
return resultChannels;
}
@@ -1871,12 +1986,18 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
+ var isQsvH264Encoder = outputVideoCodec.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
+ var isQsvHevcEncoder = outputVideoCodec.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
var isTonemappingSupported = IsTonemappingSupported(state, options);
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
// Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
// But it's still in ffmpeg mailing list. Disable it for now.
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+ if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{
return GetOutputSizeParam(state, options, outputVideoCodec);
}
@@ -1899,11 +2020,15 @@ namespace MediaBrowser.Controller.MediaEncoding
height.Value);
}
- // For QSV, feed it into hardware encoder now
- if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
- || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
+ if (!string.IsNullOrEmpty(videoSizeParam)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
- videoSizeParam += ",hwupload=extra_hw_frames=64";
+ // For QSV, feed it into hardware encoder now
+ if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
+ {
+ videoSizeParam += ",hwupload=extra_hw_frames=64";
+ }
}
}
@@ -1930,7 +2055,9 @@ namespace MediaBrowser.Controller.MediaEncoding
[sub]: SW scaling subtitle to FixedOutputSize
[base][sub]: SW overlay
*/
- retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
@@ -1943,7 +2070,9 @@ namespace MediaBrowser.Controller.MediaEncoding
[sub]: SW scaling subtitle to FixedOutputSize
[base][sub]: SW overlay
*/
- retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"";
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
}
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
@@ -1954,13 +2083,23 @@ namespace MediaBrowser.Controller.MediaEncoding
with fixed frame size.
Currently only supports linux.
*/
- if (isLinux)
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
+ {
+ retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload,format=nv12[base];[base][sub]overlay\"";
+ }
+ else if (isLinux)
{
retStr = !outputSizeParam.IsEmpty
? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\""
: " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
}
}
+ else if (isNvdecDecoder && isNvencEncoder)
+ {
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"";
+ }
return string.Format(
CultureInfo.InvariantCulture,
@@ -2051,17 +2190,28 @@ namespace MediaBrowser.Controller.MediaEncoding
|| state.DeInterlace("h265", true)
|| state.DeInterlace("hevc", true);
+ var isVaapiDecoder = videoDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
+ var isVaapiH264Encoder = videoEncoder.Contains("h264_vaapi", StringComparison.OrdinalIgnoreCase);
+ var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase);
+ var isQsvH264Encoder = videoEncoder.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
+ var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
var isTonemappingSupported = IsTonemappingSupported(state, options);
- var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && !qsv_or_vaapi;
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
+ var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)&& isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
+ var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
- var outputPixFmt = string.Empty;
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+
+ var outputPixFmt = "format=nv12";
+ if (isP010PixFmtRequired)
{
- outputPixFmt = "format=p010:out_range=limited";
+ outputPixFmt = "format=p010";
}
- else
+
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
{
- outputPixFmt = "format=nv12";
+ qsv_or_vaapi = false;
}
if (!videoWidth.HasValue
@@ -2081,7 +2231,9 @@ namespace MediaBrowser.Controller.MediaEncoding
":" + outputPixFmt,
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
}
- else
+
+ // Assert 10-bit is P010 so as we can avoid the extra scaler to get a bit more fps on high res HDR videos.
+ else if (!isP010PixFmtRequired)
{
filters.Add(
string.Format(
@@ -2092,6 +2244,49 @@ namespace MediaBrowser.Controller.MediaEncoding
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
}
}
+ else if ((videoDecoder ?? string.Empty).Contains("cuda", StringComparison.OrdinalIgnoreCase)
+ && width.HasValue
+ && height.HasValue)
+ {
+ var outputWidth = width.Value;
+ var outputHeight = height.Value;
+
+ var isTonemappingSupported = IsTonemappingSupported(state, options);
+ var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase);
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
+
+ var outputPixFmt = string.Empty;
+ if (isCudaFormatConversionSupported)
+ {
+ outputPixFmt = "format=nv12";
+ if (isTonemappingSupported && isTonemappingSupportedOnNvenc)
+ {
+ outputPixFmt = "format=p010";
+ }
+ }
+
+ if (!videoWidth.HasValue
+ || outputWidth != videoWidth.Value
+ || !videoHeight.HasValue
+ || outputHeight != videoHeight.Value)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale_cuda=w={0}:h={1}{2}",
+ outputWidth,
+ outputHeight,
+ isCudaFormatConversionSupported ? (":" + outputPixFmt) : string.Empty));
+ }
+ else if (isCudaFormatConversionSupported)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale_cuda={0}",
+ outputPixFmt));
+ }
+ }
else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1
&& width.HasValue
&& height.HasValue)
@@ -2326,28 +2521,36 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvHevcEncoder = outputVideoCodec.IndexOf("hevc_qsv", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
+ var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase);
+ var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isColorDepth10 = IsColorDepth10(state);
var isTonemappingSupported = IsTonemappingSupported(state, options);
- var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder;
- var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder;
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
+ var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder);
+ var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
+ var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
- var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
+ var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.AverageFrameRate ?? 60) <= 30;
var isScalingInAdvance = false;
+ var isCudaDeintInAdvance = false;
+ var isHwuploadCudaRequired = false;
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
- if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || isTonemappingSupportedOnVaapi)
+ // Add OpenCL tonemapping filter for NVENC/AMF/VAAPI.
+ if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported))
{
// Currently only with the use of NVENC decoder can we get a decent performance.
// Currently only the HEVC/H265 format is supported with NVDEC decoder.
@@ -2387,15 +2590,17 @@ namespace MediaBrowser.Controller.MediaEncoding
filters.Add("format=p010");
}
- if (isNvdecHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ if ((isDeinterlaceH264 || isDeinterlaceHevc) && isNvdecDecoder)
{
- // Upload the HDR10 or HLG data to the OpenCL device,
- // use tonemap_opencl filter for tone mapping,
- // and then download the SDR data to memory.
- filters.Add("hwupload");
+ isCudaDeintInAdvance = true;
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif_cuda={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
- if (isVaapiDecoder)
+ if (isVaapiDecoder || isNvdecDecoder)
{
isScalingInAdvance = true;
filters.AddRange(
@@ -2411,11 +2616,28 @@ namespace MediaBrowser.Controller.MediaEncoding
request.Height,
request.MaxWidth,
request.MaxHeight));
+ }
- // hwmap the HDR data to opencl device by cl-va p010 interop.
+ // hwmap the HDR data to opencl device by cl-va p010 interop.
+ if (isVaapiDecoder)
+ {
filters.Add("hwmap");
}
+ // convert cuda device data to p010 host data.
+ if (isNvdecDecoder)
+ {
+ filters.Add("hwdownload,format=p010");
+ }
+
+ if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ {
+ // Upload the HDR10 or HLG data to the OpenCL device,
+ // use tonemap_opencl filter for tone mapping,
+ // and then download the SDR data to memory.
+ filters.Add("hwupload");
+ }
+
filters.Add(
string.Format(
CultureInfo.InvariantCulture,
@@ -2427,21 +2649,15 @@ namespace MediaBrowser.Controller.MediaEncoding
options.TonemappingParam,
options.TonemappingRange));
- if (isNvdecHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
{
filters.Add("hwdownload");
+ filters.Add("format=nv12");
}
- if (isSwDecoder || isD3d11vaDecoder)
+ if (isNvdecDecoder && isNvencEncoder)
{
- if (isLibX264Encoder
- || isLibX265Encoder
- || hasGraphicalSubs
- || (isNvdecHevcDecoder && isDeinterlaceHevc)
- || (!isNvdecHevcDecoder && isDeinterlaceH264 || isDeinterlaceHevc))
- {
- filters.Add("format=nv12");
- }
+ isHwuploadCudaRequired = true;
}
if (isVaapiDecoder)
@@ -2453,22 +2669,25 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// When the input may or may not be hardware VAAPI decodable.
- if ((isVaapiH264Encoder || isVaapiHevcEncoder) && !isTonemappingSupported && !isTonemappingSupportedOnVaapi)
+ if ((isVaapiH264Encoder || isVaapiHevcEncoder)
+ && !(isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)))
{
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
// When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context.
- else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder))
+ else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
filters.Add("hwupload=extra_hw_frames=64");
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first.
- else if (IsVaapiSupported(state) && isVaapiDecoder && (isLibX264Encoder || isLibX265Encoder))
+ else if ((IsVaapiSupported(state) && isVaapiDecoder) && (isLibX264Encoder || isLibX265Encoder)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
- var codec = videoStream.Codec.ToLowerInvariant();
+ var codec = videoStream.Codec;
// Assert 10-bit hardware VAAPI decodable
if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
@@ -2493,9 +2712,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Add hardware deinterlace filter before scaling filter.
- if (isDeinterlaceH264)
+ if (isDeinterlaceH264 || isDeinterlaceHevc)
{
- if (isVaapiH264Encoder)
+ if (isVaapiEncoder
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
filters.Add(
string.Format(
@@ -2503,6 +2723,14 @@ namespace MediaBrowser.Controller.MediaEncoding
"deinterlace_vaapi=rate={0}",
doubleRateDeinterlace ? "field" : "frame"));
}
+ else if (isNvdecDecoder && !isCudaDeintInAdvance)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif_cuda={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
+ }
}
// Add software deinterlace filter before scaling filter.
@@ -2511,7 +2739,8 @@ namespace MediaBrowser.Controller.MediaEncoding
&& !isVaapiHevcEncoder
&& !isQsvH264Encoder
&& !isQsvHevcEncoder
- && !isNvdecH264Decoder)
+ && !isNvdecDecoder
+ && !isCuvidH264Decoder)
{
if (string.Equals(options.DeinterlaceMethod, "bwdif", StringComparison.OrdinalIgnoreCase))
{
@@ -2549,14 +2778,76 @@ namespace MediaBrowser.Controller.MediaEncoding
request.MaxHeight));
}
+ // Add VPP tonemapping filter for VAAPI.
+ // Full hardware based video post processing, faster than OpenCL but lacks fine tuning options.
+ if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv)
+ && isVppTonemappingSupported)
+ {
+ filters.Add("tonemap_vaapi=format=nv12:transfer=bt709:matrix=bt709:primaries=bt709");
+ }
+
+ // Another case is when using Nvenc decoder.
+ if (isNvdecDecoder && !isTonemappingSupported)
+ {
+ var codec = videoStream.Codec;
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
+
+ // Assert 10-bit hardware decodable
+ if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
+ {
+ if (isCudaFormatConversionSupported)
+ {
+ if (isLibX264Encoder || isLibX265Encoder || hasSubs)
+ {
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
+
+ filters.Add("hwdownload");
+ filters.Add("format=nv12");
+ }
+ }
+ else
+ {
+ // Download data from GPU to CPU as p010 format.
+ filters.Add("hwdownload");
+ filters.Add("format=p010");
+
+ // Cuda lacks of a pixel format converter.
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ filters.Add("format=yuv420p");
+ }
+ }
+ }
+
+ // Assert 8-bit hardware decodable
+ else if (!isColorDepth10 && (isLibX264Encoder || isLibX265Encoder || hasSubs))
+ {
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
+
+ filters.Add("hwdownload");
+ filters.Add("format=nv12");
+ }
+ }
+
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
- if (isVaapiH264Encoder || isVaapiHevcEncoder)
+ if (isVaapiH264Encoder
+ || isVaapiHevcEncoder
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
if (hasTextSubs)
{
// Convert hw context from ocl to va.
// For tonemapping and text subs burn-in.
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+ if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{
filters.Add("scale_vaapi");
}
@@ -2567,8 +2858,6 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- var output = string.Empty;
-
if (hasTextSubs)
{
var subParam = GetTextSubtitleParam(state);
@@ -2577,18 +2866,40 @@ namespace MediaBrowser.Controller.MediaEncoding
// Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API
// Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI
- if (isVaapiH264Encoder)
+ if (isVaapiH264Encoder || isVaapiHevcEncoder)
{
filters.Add("hwmap");
}
+
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
+ {
+ filters.Add("hwmap,format=vaapi");
+ }
+
+ if (isNvdecDecoder && isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
+ }
+
+ // Interop the VAAPI data to QSV for hybrid tonemapping
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported && !hasGraphicalSubs)
+ {
+ filters.Add("hwmap=derive_device=qsv,scale_qsv");
}
+ if (isHwuploadCudaRequired && !hasGraphicalSubs)
+ {
+ filters.Add("hwupload_cuda");
+ }
+
+ var output = string.Empty;
if (filters.Count > 0)
{
output += string.Format(
CultureInfo.InvariantCulture,
"{0}",
- string.Join(",", filters));
+ string.Join(',', filters));
}
return output;
@@ -2614,7 +2925,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (threads <= 0)
{
return 0;
- }
+ }
else if (threads >= Environment.ProcessorCount)
{
return Environment.ProcessorCount;
@@ -2622,6 +2933,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return threads;
}
+
#nullable disable
public void TryStreamCopy(EncodingJobInfo state)
{
@@ -2780,7 +3092,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
inputModifier += " -deint 1";
- if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.RealFrameRate ?? 60) > 30)
+ if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.AverageFrameRate ?? 60) > 30)
{
inputModifier += " -drop_second_field 1";
}
@@ -3055,63 +3367,32 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
+ // Hybrid VPP tonemapping with VAAPI
+ if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
+ && IsVppTonemappingSupported(state, encodingOptions))
+ {
+ // Since tonemap_vaapi only support HEVC for now, no need to check the codec again.
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
+ }
+
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- // qsv decoder does not support 10-bit input
- if ((videoStream.BitDepth ?? 8) > 8)
- {
- encodingOptions.HardwareDecodingCodecs = Array.Empty<string>();
- return null;
- }
-
- return "-c:v h264_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_qsv", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_qsv", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_qsv", "mpeg2video", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_qsv", "vc1", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_qsv", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_qsv", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
@@ -3120,57 +3401,34 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "h264", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "h264_cuvid", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "hevc_cuvid", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "mpeg2_cuvid", "mpeg2video", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vc1_cuvid", "vc1", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "mpeg4", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "mpeg4_cuvid", "mpeg4", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vp8", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vp8_cuvid", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vp9_cuvid", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "mediacodec", StringComparison.OrdinalIgnoreCase))
@@ -3179,50 +3437,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_mediacodec", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_mediacodec", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_mediacodec", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_mediacodec", "mpeg4", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_mediacodec", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_mediacodec", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase))
@@ -3231,33 +3457,13 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_mmal", "h264", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_mmal", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_mmal", "mpeg4", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_mmal", "vc1", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
@@ -3266,20 +3472,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- return GetHwaccelType(state, encodingOptions, "h264");
+ return GetHwaccelType(state, encodingOptions, "h264", isColorDepth10);
case "hevc":
case "h265":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc");
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
case "mpeg2video":
- return GetHwaccelType(state, encodingOptions, "mpeg2video");
+ return GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10);
case "vc1":
- return GetHwaccelType(state, encodingOptions, "vc1");
+ return GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10);
case "mpeg4":
- return GetHwaccelType(state, encodingOptions, "mpeg4");
+ return GetHwaccelType(state, encodingOptions, "mpeg4", isColorDepth10);
case "vp9":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9");
+ return GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
@@ -3288,20 +3492,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- return GetHwaccelType(state, encodingOptions, "h264");
+ return GetHwaccelType(state, encodingOptions, "h264", isColorDepth10);
case "hevc":
case "h265":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc");
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
case "mpeg2video":
- return GetHwaccelType(state, encodingOptions, "mpeg2video");
+ return GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10);
case "vc1":
- return GetHwaccelType(state, encodingOptions, "vc1");
+ return GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10);
case "vp8":
- return GetHwaccelType(state, encodingOptions, "vp8");
+ return GetHwaccelType(state, encodingOptions, "vp8", isColorDepth10);
case "vp9":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9");
+ return GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
@@ -3310,57 +3512,20 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_opencl", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_opencl", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_opencl", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_opencl", "mpeg4", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_opencl", "vc1", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_opencl", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_opencl", "vp9", isColorDepth10);
}
}
}
@@ -3384,14 +3549,42 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
+ /// Gets a hw decoder name
+ /// </summary>
+ public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10)
+ {
+ var isCodecAvailable = _mediaEncoder.SupportsDecoder(decoder) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase);
+ if (isColorDepth10 && isCodecAvailable)
+ {
+ if ((options.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Hevc)
+ || (options.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Vp9))
+ {
+ return null;
+ }
+ }
+
+ return isCodecAvailable ? ("-c:v " + decoder) : null;
+ }
+
+ /// <summary>
/// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system
/// </summary>
- public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec)
+ public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10)
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1);
var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va");
+ var isCodecAvailable = options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase);
+
+ if (isColorDepth10 && isCodecAvailable)
+ {
+ if ((options.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Hevc)
+ || (options.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Vp9))
+ {
+ return null;
+ }
+ }
if (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
{
@@ -3410,7 +3603,9 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
+ && IsVppTonemappingSupported(state, options)))
{
if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
{
@@ -3421,6 +3616,14 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ if (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ if (options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
+ {
+ return "-hwaccel cuda";
+ }
+ }
+
return null;
}
@@ -3673,7 +3876,7 @@ namespace MediaBrowser.Controller.MediaEncoding
GetInputArgument(state, encodingOptions),
threads,
" -vn",
- string.Join(" ", audioTranscodeParams),
+ string.Join(' ', audioTranscodeParams),
outputPath,
string.Empty,
string.Empty,
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index dacd6dea6..30e2ac42f 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -9,7 +11,6 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
@@ -273,6 +274,16 @@ namespace MediaBrowser.Controller.MediaEncoding
public int? GetRequestedAudioChannels(string codec)
{
+ if (!string.IsNullOrEmpty(codec))
+ {
+ var value = BaseRequest.GetOption(codec, "audiochannels");
+ if (!string.IsNullOrEmpty(value)
+ && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ {
+ return result;
+ }
+ }
+
if (BaseRequest.MaxAudioChannels.HasValue)
{
return BaseRequest.MaxAudioChannels;
@@ -288,16 +299,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return BaseRequest.TranscodingMaxAudioChannels;
}
- if (!string.IsNullOrEmpty(codec))
- {
- var value = BaseRequest.GetOption(codec, "audiochannels");
- if (!string.IsNullOrEmpty(value)
- && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
- {
- return result;
- }
- }
-
return null;
}
@@ -429,7 +430,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
- /// Predicts the audio sample rate that will be in the output stream.
+ /// Gets the target video level.
/// </summary>
public double? TargetVideoLevel
{
@@ -452,7 +453,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
- /// Predicts the audio sample rate that will be in the output stream.
+ /// Gets the target video bit depth.
/// </summary>
public int? TargetVideoBitDepth
{
@@ -487,7 +488,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
- /// Predicts the audio sample rate that will be in the output stream.
+ /// Gets the target framerate.
/// </summary>
public float? TargetFramerate
{
@@ -519,7 +520,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
- /// Predicts the audio sample rate that will be in the output stream.
+ /// Gets the target packet length.
/// </summary>
public int? TargetPacketLength
{
@@ -535,7 +536,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
- /// Predicts the audio sample rate that will be in the output stream.
+ /// Gets the target video profile.
/// </summary>
public string TargetVideoProfile
{
@@ -699,25 +700,4 @@ namespace MediaBrowser.Controller.MediaEncoding
Progress.Report(percentComplete.Value);
}
}
-
- /// <summary>
- /// Enum TranscodingJobType.
- /// </summary>
- public enum TranscodingJobType
- {
- /// <summary>
- /// The progressive.
- /// </summary>
- Progressive,
-
- /// <summary>
- /// The HLS.
- /// </summary>
- Hls,
-
- /// <summary>
- /// The dash.
- /// </summary>
- Dash
- }
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 1f3abe8f4..61f3bc771 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -1,60 +1,13 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Controller.MediaEncoding
{
- public class EncodingJobOptions : BaseEncodingJobOptions
- {
- public string OutputDirectory { get; set; }
-
- public string ItemId { get; set; }
-
- public string TempDirectory { get; set; }
-
- public bool ReadInputAtNativeFramerate { get; set; }
-
- /// <summary>
- /// Gets a value indicating whether this instance has fixed resolution.
- /// </summary>
- /// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value>
- public bool HasFixedResolution => Width.HasValue || Height.HasValue;
-
- public DeviceProfile DeviceProfile { get; set; }
-
- public EncodingJobOptions(StreamInfo info, DeviceProfile deviceProfile)
- {
- Container = info.Container;
- StartTimeTicks = info.StartPositionTicks;
- MaxWidth = info.MaxWidth;
- MaxHeight = info.MaxHeight;
- MaxFramerate = info.MaxFramerate;
- Id = info.ItemId;
- MediaSourceId = info.MediaSourceId;
- AudioCodec = info.TargetAudioCodec.FirstOrDefault();
- MaxAudioChannels = info.GlobalMaxAudioChannels;
- AudioBitRate = info.AudioBitrate;
- AudioSampleRate = info.TargetAudioSampleRate;
- DeviceProfile = deviceProfile;
- VideoCodec = info.TargetVideoCodec.FirstOrDefault();
- VideoBitRate = info.VideoBitrate;
- AudioStreamIndex = info.AudioStreamIndex;
- SubtitleMethod = info.SubtitleDeliveryMethod;
- Context = info.Context;
- TranscodingMaxAudioChannels = info.TranscodingMaxAudioChannels;
-
- if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
- {
- SubtitleStreamIndex = info.SubtitleStreamIndex;
- }
-
- StreamOptions = info.StreamOptions;
- }
- }
-
// For now until api and media encoding layers are unified
public class BaseEncodingJobOptions
{
diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
index fbc827534..c38e7ec3b 100644
--- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
index 15a2580af..773547872 100644
--- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 34fe895cc..76a9fd7c7 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -7,7 +9,6 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
@@ -19,7 +20,7 @@ namespace MediaBrowser.Controller.MediaEncoding
public interface IMediaEncoder : ITranscoderSupport
{
/// <summary>
- /// The location of the discovered FFmpeg tool.
+ /// Gets location of the discovered FFmpeg tool.
/// </summary>
FFmpegLocation EncoderLocation { get; }
@@ -51,6 +52,14 @@ namespace MediaBrowser.Controller.MediaEncoding
bool SupportsHwaccel(string hwaccel);
/// <summary>
+ /// Whether given filter is supported.
+ /// </summary>
+ /// <param name="filter">The filter.</param>
+ /// <param name="option">The option.</param>
+ /// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
+ bool SupportsFilter(string filter, string option);
+
+ /// <summary>
/// Extracts the audio image.
/// </summary>
/// <param name="path">The path.</param>
diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
index 6ebf7f159..3fb2c47e1 100644
--- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
index e7b4c8c15..044ba6d33 100644
--- a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.MediaEncoding
diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
index cc8820f39..aa5e2c403 100644
--- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
+++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
@@ -1,9 +1,10 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 281d50372..841e7b287 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,11 +1,5 @@
#pragma warning disable CS1591
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Model.IO;
-
namespace MediaBrowser.Controller.MediaEncoding
{
/// <summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
index 2cb04bdc4..1dd8bcf31 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
diff --git a/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs b/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs
new file mode 100644
index 000000000..66b628371
--- /dev/null
+++ b/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs
@@ -0,0 +1,23 @@
+namespace MediaBrowser.Controller.MediaEncoding
+{
+ /// <summary>
+ /// Enum TranscodingJobType.
+ /// </summary>
+ public enum TranscodingJobType
+ {
+ /// <summary>
+ /// The progressive.
+ /// </summary>
+ Progressive,
+
+ /// <summary>
+ /// The HLS.
+ /// </summary>
+ Hls,
+
+ /// <summary>
+ /// The dash.
+ /// </summary>
+ Dash
+ }
+} \ No newline at end of file