aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/MediaEncoding
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding')
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs71
1 files changed, 61 insertions, 10 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 11eee1a37..9ebaef171 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -85,6 +85,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly Version _minFFmpegVaapiDeviceVendorId = new Version(7, 0, 1);
private readonly Version _minFFmpegQsvVppScaleModeOption = new Version(6, 0);
private readonly Version _minFFmpegRkmppHevcDecDoviRpu = new Version(7, 1, 1);
+ private readonly Version _minFFmpegReadrateCatchupOption = new Version(8, 0);
private static readonly Regex _containerValidationRegex = new(ContainerValidationRegex, RegexOptions.Compiled);
@@ -1267,6 +1268,20 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ // Use analyzeduration also for subtitle streams to improve resolution detection with streams inside MKS files
+ var analyzeDurationArgument = GetFfmpegAnalyzeDurationArg(state);
+ if (!string.IsNullOrEmpty(analyzeDurationArgument))
+ {
+ arg.Append(' ').Append(analyzeDurationArgument);
+ }
+
+ // Apply probesize, too, if configured
+ var ffmpegProbeSizeArgument = GetFfmpegProbesizeArg();
+ if (!string.IsNullOrEmpty(ffmpegProbeSizeArgument))
+ {
+ arg.Append(' ').Append(ffmpegProbeSizeArgument);
+ }
+
// Also seek the external subtitles stream.
var seekSubParam = GetFastSeekCommandLineParameter(state, options, segmentContainer);
if (!string.IsNullOrEmpty(seekSubParam))
@@ -1552,14 +1567,15 @@ namespace MediaBrowser.Controller.MediaEncoding
int bitrate = state.OutputVideoBitrate.Value;
- // Bit rate under 1000k is not allowed in h264_qsv
+ // Bit rate under 1000k is not allowed in h264_qsv.
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
bitrate = Math.Max(bitrate, 1000);
}
- // Currently use the same buffer size for all encoders
- int bufsize = bitrate * 2;
+ // Currently use the same buffer size for all non-QSV encoders.
+ // Use long arithmetic to prevent int32 overflow for very high bitrate values.
+ int bufsize = (int)Math.Min((long)bitrate * 2, int.MaxValue);
if (string.Equals(videoCodec, "libsvtav1", StringComparison.OrdinalIgnoreCase))
{
@@ -1589,7 +1605,13 @@ namespace MediaBrowser.Controller.MediaEncoding
// Set (maxrate == bitrate + 1) to trigger VBR for better bitrate allocation
// Set (rc_init_occupancy == 2 * bitrate) and (bufsize == 4 * bitrate) to deal with drastic scene changes
- return FormattableString.Invariant($"{mbbrcOpt} -b:v {bitrate} -maxrate {bitrate + 1} -rc_init_occupancy {bitrate * 2} -bufsize {bitrate * 4}");
+ // Use long arithmetic and clamp to int.MaxValue to prevent int32 overflow
+ // (e.g. bitrate * 4 wraps to a negative value for bitrates above ~537 million)
+ int qsvMaxrate = (int)Math.Min((long)bitrate + 1, int.MaxValue);
+ int qsvInitOcc = (int)Math.Min((long)bitrate * 2, int.MaxValue);
+ int qsvBufsize = (int)Math.Min((long)bitrate * 4, int.MaxValue);
+
+ return FormattableString.Invariant($"{mbbrcOpt} -b:v {bitrate} -maxrate {qsvMaxrate} -rc_init_occupancy {qsvInitOcc} -bufsize {qsvBufsize}");
}
if (string.Equals(videoCodec, "h264_amf", StringComparison.OrdinalIgnoreCase)
@@ -7123,9 +7145,8 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions, string segmentContainer)
+ private string GetFfmpegAnalyzeDurationArg(EncodingJobInfo state)
{
- var inputModifier = string.Empty;
var analyzeDurationArgument = string.Empty;
// Apply -analyzeduration as per the environment variable,
@@ -7141,6 +7162,26 @@ namespace MediaBrowser.Controller.MediaEncoding
analyzeDurationArgument = "-analyzeduration " + ffmpegAnalyzeDuration;
}
+ return analyzeDurationArgument;
+ }
+
+ private string GetFfmpegProbesizeArg()
+ {
+ var ffmpegProbeSize = _config.GetFFmpegProbeSize();
+
+ if (!string.IsNullOrEmpty(ffmpegProbeSize))
+ {
+ return $"-probesize {ffmpegProbeSize}";
+ }
+
+ return string.Empty;
+ }
+
+ public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions, string segmentContainer)
+ {
+ var inputModifier = string.Empty;
+ var analyzeDurationArgument = GetFfmpegAnalyzeDurationArg(state);
+
if (!string.IsNullOrEmpty(analyzeDurationArgument))
{
inputModifier += " " + analyzeDurationArgument;
@@ -7149,11 +7190,11 @@ namespace MediaBrowser.Controller.MediaEncoding
inputModifier = inputModifier.Trim();
// Apply -probesize if configured
- var ffmpegProbeSize = _config.GetFFmpegProbeSize();
+ var ffmpegProbeSizeArgument = GetFfmpegProbesizeArg();
- if (!string.IsNullOrEmpty(ffmpegProbeSize))
+ if (!string.IsNullOrEmpty(ffmpegProbeSizeArgument))
{
- inputModifier += $" -probesize {ffmpegProbeSize}";
+ inputModifier += " " + ffmpegProbeSizeArgument;
}
var userAgentParam = GetUserAgentParam(state);
@@ -7193,8 +7234,10 @@ namespace MediaBrowser.Controller.MediaEncoding
inputModifier += GetVideoSyncOption(state.InputVideoSync, _mediaEncoder.EncoderVersion);
}
+ int readrate = 0;
if (state.ReadInputAtNativeFramerate && state.InputProtocol != MediaProtocol.Rtsp)
{
+ readrate = 1;
inputModifier += " -re";
}
else if (encodingOptions.EnableSegmentDeletion
@@ -7205,7 +7248,15 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// Set an input read rate limit 10x for using SegmentDeletion with stream-copy
// to prevent ffmpeg from exiting prematurely (due to fast drive)
- inputModifier += " -readrate 10";
+ readrate = 10;
+ inputModifier += $" -readrate {readrate}";
+ }
+
+ // Set a larger catchup value to revert to the old behavior,
+ // otherwise, remuxing might stall due to this new option
+ if (readrate > 0 && _mediaEncoder.EncoderVersion >= _minFFmpegReadrateCatchupOption)
+ {
+ inputModifier += $" -readrate_catchup {readrate * 100}";
}
var flags = new List<string>();