@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly Version _minFFmpegSvtAv1Params = new Version ( 5 , 1 ) ;
private readonly Version _minFFmpegVaapiH26xEncA53CcSei = new Version ( 6 , 0 ) ;
private readonly Version _minFFmpegReadrateOption = new Version ( 5 , 0 ) ;
private readonly Version _minFFmpegDisplayRotationOption = new Version ( 6 , 0 ) ;
private static readonly Regex _validationRegex = new ( ValidationRegex , RegexOptions . Compiled ) ;
@ -228,6 +229,7 @@ namespace MediaBrowser.Controller.MediaEncoding
& & _mediaEncoder . SupportsFilter ( "tonemap_vaapi" )
& & _mediaEncoder . SupportsFilter ( "procamp_vaapi" )
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . OverlayVaapiFrameSync )
& & _mediaEncoder . SupportsFilter ( "transpose_vaapi" )
& & _mediaEncoder . SupportsFilter ( "hwupload_vaapi" ) ;
}
@ -245,6 +247,8 @@ namespace MediaBrowser.Controller.MediaEncoding
& & _mediaEncoder . SupportsFilter ( "scale_opencl" )
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . TonemapOpenclBt2390 )
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . OverlayOpenclFrameSync ) ;
// Let transpose_opencl optional for the time being.
}
private bool IsCudaFullSupported ( )
@ -255,6 +259,8 @@ namespace MediaBrowser.Controller.MediaEncoding
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . TonemapCudaName )
& & _mediaEncoder . SupportsFilter ( "overlay_cuda" )
& & _mediaEncoder . SupportsFilter ( "hwupload_cuda" ) ;
// Let transpose_cuda optional for the time being.
}
private bool IsVulkanFullSupported ( )
@ -262,7 +268,9 @@ namespace MediaBrowser.Controller.MediaEncoding
return _mediaEncoder . SupportsHwaccel ( "vulkan" )
& & _mediaEncoder . SupportsFilter ( "libplacebo" )
& & _mediaEncoder . SupportsFilter ( "scale_vulkan" )
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . OverlayVulkanFrameSync ) ;
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . OverlayVulkanFrameSync )
& & _mediaEncoder . SupportsFilter ( "transpose_vulkan" )
& & _mediaEncoder . SupportsFilter ( "flip_vulkan" ) ;
}
private bool IsVideoToolboxFullSupported ( )
@ -272,6 +280,8 @@ namespace MediaBrowser.Controller.MediaEncoding
& & _mediaEncoder . SupportsFilter ( "overlay_videotoolbox" )
& & _mediaEncoder . SupportsFilter ( "tonemap_videotoolbox" )
& & _mediaEncoder . SupportsFilter ( "scale_vt" ) ;
// Let transpose_vt optional for the time being.
}
private bool IsHwTonemapAvailable ( EncodingJobInfo state , EncodingOptions options )
@ -1164,9 +1174,6 @@ namespace MediaBrowser.Controller.MediaEncoding
args . Append ( vidDecoder ) ;
}
// hw transpose filters should be added manually.
args . Append ( " -noautorotate" ) ;
return args . ToString ( ) . Trim ( ) ;
}
@ -3037,8 +3044,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
public static string GetHwScaleFilter (
string hwScalePrefix ,
string hwScaleSuffix ,
string videoFormat ,
bool swapOutputWandH ,
int? videoWidth ,
int? videoHeight ,
int? requestedWidth ,
@ -3060,8 +3069,11 @@ namespace MediaBrowser.Controller.MediaEncoding
| | ! videoHeight . HasValue
| | outHeight . Value ! = videoHeight . Value ;
var arg1 = isSizeFixed ? ( "=w=" + outWidth . Value + ":h=" + outHeight . Value ) : string . Empty ;
var arg2 = isFormatFixed ? ( "format=" + videoFormat ) : string . Empty ;
var swpOutW = swapOutputWandH ? outHeight . Value : outWidth . Value ;
var swpOutH = swapOutputWandH ? outWidth . Value : outHeight . Value ;
var arg1 = isSizeFixed ? $"=w={swpOutW}:h={swpOutH}" : string . Empty ;
var arg2 = isFormatFixed ? $"format={videoFormat}" : string . Empty ;
if ( isFormatFixed )
{
arg2 = ( isSizeFixed ? ':' : '=' ) + arg2 ;
@ -3071,7 +3083,8 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return string . Format (
CultureInfo . InvariantCulture ,
"scale_{0}{1}{2}" ,
"{0}_{1}{2}{3}" ,
hwScalePrefix ? ? "scale" ,
hwScaleSuffix ,
arg1 ,
arg2 ) ;
@ -3467,6 +3480,18 @@ namespace MediaBrowser.Controller.MediaEncoding
tonemapArg ) ;
}
public string GetVideoTransposeDirection ( EncodingJobInfo state )
{
return ( state . VideoStream ? . Rotation ? ? 0 ) switch
{
90 = > "cclock" ,
180 = > "reversal" ,
- 90 = > "clock" ,
- 180 = > "reversal" ,
_ = > string . Empty
} ;
}
/// <summary>
/// Gets the parameter of software filter chain.
/// </summary>
@ -3500,6 +3525,11 @@ namespace MediaBrowser.Controller.MediaEncoding
var hasTextSubs = hasSubs & & state . SubtitleStream . IsTextSubtitleStream ;
var hasGraphicalSubs = hasSubs & & ! state . SubtitleStream . IsTextSubtitleStream ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var swapWAndH = Math . Abs ( rotation ) = = 90 ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -3514,7 +3544,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = isSwDecoder ? "yuv420p" : "nv12" ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
if ( isVaapiEncoder )
{
outFormat = "nv12" ;
@ -3543,7 +3573,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -3617,6 +3647,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doCuTranspose = ! string . IsNullOrEmpty ( tranposeDir ) & & _mediaEncoder . SupportsFilter ( "transpose_cuda" ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( isNvDecoder & & doCuTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -3633,10 +3670,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doCuTonemap ? "yuv420p10le" : "yuv420p" ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// sw => hw
if ( doCuTonemap )
@ -3655,8 +3692,14 @@ namespace MediaBrowser.Controller.MediaEncoding
mainFilters . Add ( deintFilter ) ;
}
// hw transpose
if ( doCuTranspose )
{
mainFilters . Add ( $"transpose_cuda=dir={tranposeDir}" ) ;
}
var outFormat = doCuTonemap ? string . Empty : "yuv420p" ;
var hwScaleFilter = GetHwScaleFilter ( "cuda" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", "cuda" , outFormat , false , swpInW , swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
// hw scale
mainFilters . Add ( hwScaleFilter ) ;
}
@ -3706,7 +3749,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=yuva420p" ) ;
}
@ -3716,7 +3759,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
// alphasrc=s=1280x720:r=10:start=0,format=yuva420p,subtitles,hwupload
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=yuva420p" ) ;
@ -3731,7 +3774,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -3807,6 +3850,14 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doOclTranspose = ! string . IsNullOrEmpty ( tranposeDir )
& & _mediaEncoder . SupportsFilterWithOption ( FilterOptionType . TransposeOpenclReversal ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( isD3d11vaDecoder & & doOclTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -3823,10 +3874,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doOclTonemap ? "yuv420p10le" : "yuv420p" ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// keep video at memory except ocl tonemap,
// since the overhead caused by hwupload >>> using sw filter.
@ -3835,7 +3886,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
mainFilters . Add ( "hwupload=derive_device=d3d11va:extra_hw_frames=16" ) ;
mainFilters . Add ( "format=d3d11" ) ;
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
}
}
@ -3843,12 +3894,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// INPUT d3d11 surface(vram)
// map from d3d11va to opencl via d3d11-opencl interop.
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
// hw deint <= TODO: finsh the 'yadif_opencl' filter
// hw transpose
if ( doOclTranspose )
{
mainFilters . Add ( $"transpose_opencl=dir={tranposeDir}" ) ;
}
var outFormat = doOclTonemap ? string . Empty : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( "opencl" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", " opencl", outFormat , false , swpInW , swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
// hw scale
mainFilters . Add ( hwScaleFilter ) ;
}
@ -3893,7 +3950,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// OUTPUT d3d11(nv12) surface(vram)
// reverse-mapping via d3d11-opencl interop.
mainFilters . Add ( "hwmap=derive_device=d3d11va: reverse=1") ;
mainFilters . Add ( "hwmap=derive_device=d3d11va: mode=write: reverse=1") ;
mainFilters . Add ( "format=d3d11" ) ;
}
@ -3906,7 +3963,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=yuva420p" ) ;
}
@ -3916,7 +3973,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
// alphasrc=s=1280x720:r=10:start=0,format=yuva420p,subtitles,hwupload
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=yuva420p" ) ;
@ -3925,7 +3982,7 @@ namespace MediaBrowser.Controller.MediaEncoding
subFilters . Add ( "hwupload=derive_device=opencl" ) ;
overlayFilters . Add ( "overlay_opencl=eof_action=pass:repeatlast=0" ) ;
overlayFilters . Add ( "hwmap=derive_device=d3d11va: reverse=1") ;
overlayFilters . Add ( "hwmap=derive_device=d3d11va: mode=write: reverse=1") ;
overlayFilters . Add ( "format=d3d11" ) ;
}
}
@ -3933,7 +3990,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -4029,6 +4086,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doVppTranspose = ! string . IsNullOrEmpty ( tranposeDir ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( ( isD3d11vaDecoder | | isQsvDecoder ) & & doVppTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -4045,10 +4109,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doOclTonemap ? "yuv420p10le" : ( hasGraphicalSubs ? "yuv420p" : "nv12" ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// keep video at memory except ocl tonemap,
// since the overhead caused by hwupload >>> using sw filter.
@ -4060,8 +4124,15 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else if ( isD3d11vaDecoder | | isQsvDecoder )
{
var outFormat = doOclTonemap ? string . Empty : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( "qsv" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var outFormat = doOclTonemap ? ( doVppTranspose ? "p010" : string . Empty ) : "nv12" ;
var swapOutputWandH = doVppTranspose & & swapWAndH ;
var hwScalePrefix = doVppTranspose ? "vpp" : "scale" ;
var hwScaleFilter = GetHwScaleFilter ( hwScalePrefix , "qsv" , outFormat , swapOutputWandH , swpInW , swpInH , reqW , reqH , reqMaxW , reqMaxH ) ;
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) & & doVppTranspose )
{
hwScaleFilter + = $":transpose={tranposeDir}" ;
}
if ( isD3d11vaDecoder )
{
@ -4080,14 +4151,14 @@ namespace MediaBrowser.Controller.MediaEncoding
mainFilters . Add ( deintFilter ) ;
}
// hw scale
// hw transpose & scale
mainFilters . Add ( hwScaleFilter ) ;
}
if ( doOclTonemap & & isHwDecoder )
{
// map from qsv to opencl via qsv(d3d11)-opencl interop.
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
}
// hw tonemap
@ -4131,7 +4202,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// OUTPUT qsv(nv12) surface(vram)
// reverse-mapping via qsv(d3d11)-opencl interop.
mainFilters . Add ( "hwmap=derive_device=qsv: reverse=1") ;
mainFilters . Add ( "hwmap=derive_device=qsv: mode=write: reverse=1") ;
mainFilters . Add ( "format=qsv" ) ;
}
@ -4145,7 +4216,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( hasGraphicalSubs )
{
// overlay_qsv can handle overlay scaling, setup a smaller height to reduce transfer overhead
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , 1080 ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -4155,7 +4226,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
// alphasrc=s=1280x720:r=10:start=0,format=bgra,subtitles,hwupload
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -4166,9 +4237,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// default to 64 otherwise it will fail on certain iGPU.
subFilters . Add ( "hwupload=derive_device=qsv:extra_hw_frames=64" ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var overlaySize = ( overlayW . HasValue & & overlayH . HasValue )
? ( ":w=" + overlayW . Value + ":h=" + overlayH . Value )
? $":w={overlayW.Value}:h={overlayH.Value}"
: string . Empty ;
var overlayQsvFilter = string . Format (
CultureInfo . InvariantCulture ,
@ -4181,7 +4252,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -4226,6 +4297,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doVppTranspose = ! string . IsNullOrEmpty ( tranposeDir ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( ( isVaapiDecoder | | isQsvDecoder ) & & doVppTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -4242,10 +4320,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doOclTonemap ? "yuv420p10le" : ( hasGraphicalSubs ? "yuv420p" : "nv12" ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// keep video at memory except ocl tonemap,
// since the overhead caused by hwupload >>> using sw filter.
@ -4257,24 +4335,39 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else if ( isVaapiDecoder | | isQsvDecoder )
{
var hwFilterSuffix = isVaapiDecoder ? "vaapi" : "qsv" ;
// INPUT vaapi/qsv surface(vram)
// hw deint
if ( doDeintH2645 )
{
var deintFilter = GetHwDeinterlaceFilter ( state , options , isVaapiDecoder ? "vaapi" : "qsv" ) ;
var deintFilter = GetHwDeinterlaceFilter ( state , options , hwFilterSuffix ) ;
mainFilters . Add ( deintFilter ) ;
}
var outFormat = doTonemap ? string . Empty : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( isVaapiDecoder ? "vaapi" : "qsv" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
// hw transpose(vaapi vpp)
if ( isVaapiDecoder & & doVppTranspose )
{
mainFilters . Add ( $"transpose_vaapi=dir={tranposeDir}" ) ;
}
// allocate extra pool sizes for vaapi vpp
var outFormat = doOclTonemap ? ( ( isQsvDecoder & & doVppTranspose ) ? "p010" : string . Empty ) : "nv12" ;
var swapOutputWandH = isQsvDecoder & & doVppTranspose & & swapWAndH ;
var hwScalePrefix = ( isQsvDecoder & & doVppTranspose ) ? "vpp" : "scale" ;
var hwScaleFilter = GetHwScaleFilter ( hwScalePrefix , hwFilterSuffix , outFormat , swapOutputWandH , swpInW , swpInH , reqW , reqH , reqMaxW , reqMaxH ) ;
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) & & isQsvDecoder & & doVppTranspose )
{
hwScaleFilter + = $":transpose={tranposeDir}" ;
}
// allocate extra pool sizes for vaapi vpp scale
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) & & isVaapiDecoder )
{
hwScaleFilter + = ":extra_hw_frames=24" ;
}
// hw scale
// hw transpose(qsv vpp) & scale
mainFilters . Add ( hwScaleFilter ) ;
}
@ -4300,7 +4393,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( doOclTonemap & & isHwDecoder )
{
// map from qsv to opencl via qsv(vaapi)-opencl interop.
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
}
// ocl tonemap
@ -4347,7 +4440,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// OUTPUT qsv(nv12) surface(vram)
// reverse-mapping via qsv(vaapi)-opencl interop.
// add extra pool size to avoid the 'cannot allocate memory' error on hevc_qsv.
mainFilters . Add ( "hwmap=derive_device=qsv: reverse=1:extra_hw_frames=16") ;
mainFilters . Add ( "hwmap=derive_device=qsv: mode=write: reverse=1:extra_hw_frames=16") ;
mainFilters . Add ( "format=qsv" ) ;
}
else if ( isVaapiDecoder )
@ -4367,7 +4460,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( hasGraphicalSubs )
{
// overlay_qsv can handle overlay scaling, setup a smaller height to reduce transfer overhead
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , 1080 ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -4376,7 +4469,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var framerate = state . VideoStream ? . RealFrameRate ;
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -4387,9 +4480,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// default to 64 otherwise it will fail on certain iGPU.
subFilters . Add ( "hwupload=derive_device=qsv:extra_hw_frames=64" ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var overlaySize = ( overlayW . HasValue & & overlayH . HasValue )
? ( ":w=" + overlayW . Value + ":h=" + overlayH . Value )
? $":w={overlayW.Value}:h={overlayH.Value}"
: string . Empty ;
var overlayQsvFilter = string . Format (
CultureInfo . InvariantCulture ,
@ -4402,7 +4495,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -4512,6 +4605,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doVaVppTranspose = ! string . IsNullOrEmpty ( tranposeDir ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( isVaapiDecoder & & doVaVppTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -4528,10 +4628,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doOclTonemap ? "yuv420p10le" : "nv12" ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// keep video at memory except ocl tonemap,
// since the overhead caused by hwupload >>> using sw filter.
@ -4551,8 +4651,14 @@ namespace MediaBrowser.Controller.MediaEncoding
mainFilters . Add ( deintFilter ) ;
}
// hw transpose
if ( doVaVppTranspose )
{
mainFilters . Add ( $"transpose_vaapi=dir={tranposeDir}" ) ;
}
var outFormat = doTonemap ? string . Empty : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( "vaapi" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", " vaapi", outFormat , false , swpInW , swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
// allocate extra pool sizes for vaapi vpp
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) )
@ -4574,7 +4680,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( doOclTonemap & & isVaapiDecoder )
{
// map from vaapi to opencl via vaapi-opencl interop(Intel only).
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
}
// ocl tonemap
@ -4588,7 +4694,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// OUTPUT vaapi(nv12) surface(vram)
// reverse-mapping via vaapi-opencl interop.
mainFilters . Add ( "hwmap=derive_device=vaapi: reverse=1") ;
mainFilters . Add ( "hwmap=derive_device=vaapi: mode=write: reverse=1") ;
mainFilters . Add ( "format=vaapi" ) ;
}
@ -4639,7 +4745,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( hasGraphicalSubs )
{
// overlay_vaapi can handle overlay scaling, setup a smaller height to reduce transfer overhead
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , 1080 ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -4648,7 +4754,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var framerate = state . VideoStream ? . RealFrameRate ;
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , 1080 , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -4657,9 +4763,9 @@ namespace MediaBrowser.Controller.MediaEncoding
subFilters . Add ( "hwupload=derive_device=vaapi" ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var ( overlayW , overlayH ) = GetFixedOutputSize ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var overlaySize = ( overlayW . HasValue & & overlayH . HasValue )
? ( ":w=" + overlayW . Value + ":h=" + overlayH . Value )
? $":w={overlayW.Value}:h={overlayH.Value}"
: string . Empty ;
var overlayVaapiFilter = string . Format (
CultureInfo . InvariantCulture ,
@ -4672,7 +4778,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
@ -4717,6 +4823,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doVkTranspose = isVaapiDecoder & & ! string . IsNullOrEmpty ( tranposeDir ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( isVaapiDecoder & & doVkTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -4741,7 +4854,7 @@ namespace MediaBrowser.Controller.MediaEncoding
else
{
// sw scale
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=nv12" ) ;
}
@ -4749,7 +4862,7 @@ namespace MediaBrowser.Controller.MediaEncoding
else if ( isVaapiDecoder )
{
// INPUT vaapi surface(vram)
if ( doVkT onemap | | hasSubs )
if ( doVkT ranspose | | doVkT onemap | | hasSubs )
{
// map from vaapi to vulkan/drm via interop (Polaris/gfx8+).
mainFilters . Add ( "hwmap=derive_device=vulkan" ) ;
@ -4765,15 +4878,28 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// hw scale
var hwScaleFilter = GetHwScaleFilter ( " vaapi", "nv12" , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", " vaapi", "nv12" , false , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
mainFilters . Add ( hwScaleFilter ) ;
}
}
// vk transpose
if ( doVkTranspose )
{
if ( string . Equals ( tranposeDir , "reversal" , StringComparison . OrdinalIgnoreCase ) )
{
mainFilters . Add ( "flip_vulkan" ) ;
}
else
{
mainFilters . Add ( $"transpose_vulkan=dir={tranposeDir}" ) ;
}
}
// vk libplacebo
if ( doVkTonemap | | hasSubs )
{
var libplaceboFilter = GetLibplaceboFilter ( options , "bgra" , doVkTonemap , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var libplaceboFilter = GetLibplaceboFilter ( options , "bgra" , doVkTonemap , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
mainFilters . Add ( libplaceboFilter ) ;
}
@ -4817,7 +4943,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -4826,7 +4952,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var framerate = state . VideoStream ? . RealFrameRate ;
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -4898,6 +5024,11 @@ namespace MediaBrowser.Controller.MediaEncoding
var hasTextSubs = hasSubs & & state . SubtitleStream . IsTextSubtitleStream ;
var hasGraphicalSubs = hasSubs & & ! state . SubtitleStream . IsTextSubtitleStream ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & isSwDecoder ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -4915,7 +5046,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
outFormat = doOclTonemap ? "yuv420p10le" : "nv12" ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
@ -4939,7 +5070,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
outFormat = doOclTonemap ? string . Empty : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( " vaapi", outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", " vaapi", outFormat , false , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
// allocate extra pool sizes for vaapi vpp
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) )
@ -5035,7 +5166,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
@ -5089,6 +5220,14 @@ namespace MediaBrowser.Controller.MediaEncoding
string vidDecoder ,
string vidEncoder )
{
var isVtEncoder = vidEncoder . Contains ( "videotoolbox" , StringComparison . OrdinalIgnoreCase ) ;
if ( ! isVtEncoder )
{
// should not happen.
return ( null , null , null ) ;
}
var inW = state . VideoStream ? . Width ;
var inH = state . VideoStream ? . Height ;
var reqW = state . BaseRequest . Width ;
@ -5097,14 +5236,19 @@ namespace MediaBrowser.Controller.MediaEncoding
var reqMaxH = state . BaseRequest . MaxHeight ;
var threeDFormat = state . MediaSource . Video3DFormat ;
var isVtEncoder = vidEncoder . Contains ( "videotoolbox" , StringComparison . OrdinalIgnoreCase ) ;
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 doVtTonemap = IsVideoToolboxTonemapAvailable ( state , options ) ;
var doMetalTonemap = ! doVtTonemap & & IsHwTonemapAvailable ( state , options ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doVtTranspose = ! string . IsNullOrEmpty ( tranposeDir ) & & _mediaEncoder . SupportsFilter ( "transpose_vt" ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & doVtTranspose ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
var scaleFormat = string . Empty ;
// Use P010 for Metal tone mapping, otherwise force an 8bit output.
if ( ! string . Equals ( state . VideoStream . PixelFormat , "yuv420p" , StringComparison . OrdinalIgnoreCase ) )
@ -5122,7 +5266,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
var hwScaleFilter = GetHwScaleFilter ( " vt", scaleFormat , inW , i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter = GetHwScaleFilter ( " scale", "vt" , scaleFormat , false , swpInW , swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var hasSubs = state . SubtitleStream is not null & & state . SubtitleDeliveryMethod = = SubtitleDeliveryMethod . Encode ;
var hasTextSubs = hasSubs & & state . SubtitleStream . IsTextSubtitleStream ;
@ -5131,12 +5275,6 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
if ( ! isVtEncoder )
{
// should not happen.
return ( null , null , null ) ;
}
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -5147,6 +5285,12 @@ namespace MediaBrowser.Controller.MediaEncoding
mainFilters . Add ( deintFilter ) ;
}
// hw transpose
if ( doVtTranspose )
{
mainFilters . Add ( $"transpose_vt=dir={tranposeDir}" ) ;
}
if ( doVtTonemap )
{
const string VtTonemapArgs = "color_matrix=bt709:color_primaries=bt709:color_transfer=bt709" ;
@ -5175,7 +5319,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -5184,7 +5328,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var framerate = state . VideoStream ? . RealFrameRate ;
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -5284,6 +5428,13 @@ namespace MediaBrowser.Controller.MediaEncoding
& & ( string . Equals ( state . SubtitleStream . Codec , "ass" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( state . SubtitleStream . Codec , "ssa" , StringComparison . OrdinalIgnoreCase ) ) ;
var rotation = state . VideoStream ? . Rotation ? ? 0 ;
var tranposeDir = rotation = = 0 ? string . Empty : GetVideoTransposeDirection ( state ) ;
var doRkVppTranspose = ! string . IsNullOrEmpty ( tranposeDir ) ;
var swapWAndH = Math . Abs ( rotation ) = = 90 & & ( isSwDecoder | | ( isRkmppDecoder & & doRkVppTranspose ) ) ;
var swpInW = swapWAndH ? inH : inW ;
var swpInH = swapWAndH ? inW : inH ;
/* Make main filters for video stream */
var mainFilters = new List < string > ( ) ;
@ -5300,7 +5451,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var outFormat = doOclTonemap ? "yuv420p10le" : ( hasGraphicalSubs ? "yuv420p" : "nv12" ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , inW, i nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
var swScaleFilter = GetSwScaleFilter ( state , options , vidEncoder , swpInW, swpI nH, threeDFormat , reqW , reqH , reqMaxW , reqMaxH ) ;
if ( ! string . IsNullOrEmpty ( swScaleFilter ) )
{
swScaleFilter + = ":flags=fast_bilinear" ;
@ -5308,7 +5459,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// sw scale
mainFilters . Add ( swScaleFilter ) ;
mainFilters . Add ( "format=" + outFormat ) ;
mainFilters . Add ( $"format={outFormat}" ) ;
// keep video at memory except ocl tonemap,
// since the overhead caused by hwupload >>> using sw filter.
@ -5323,21 +5474,29 @@ namespace MediaBrowser.Controller.MediaEncoding
// INPUT rkmpp/drm surface(gem/dma-heap)
var isFullAfbcPipeline = isDrmInDrmOut & & ! doOclTonemap ;
var swapOutputWandH = doRkVppTranspose & & swapWAndH ;
var outFormat = doOclTonemap ? "p010" : "nv12" ;
var hwScaleFilter = GetHwScaleFilter ( "rkrga" , outFormat , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter2 = GetHwScaleFilter ( "rkrga" , string . Empty , inW , inH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScalePrefix = doRkVppTranspose ? "vpp" : "scale" ;
var hwScaleFilter = GetHwScaleFilter ( hwScalePrefix , "rkrga" , outFormat , swapOutputWandH , swpInW , swpInH , reqW , reqH , reqMaxW , reqMaxH ) ;
var hwScaleFilter2 = GetHwScaleFilter ( hwScalePrefix , "rkrga" , string . Empty , swapOutputWandH , swpInW , swpInH , reqW , reqH , reqMaxW , reqMaxH ) ;
if ( ! hasSubs
| | doRkVppTranspose
| | ! isFullAfbcPipeline
| | ! string . IsNullOrEmpty ( hwScaleFilter2 ) )
{
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) & & doRkVppTranspose )
{
hwScaleFilter + = $":transpose={tranposeDir}" ;
}
// try enabling AFBC to save DDR bandwidth
if ( ! string . IsNullOrEmpty ( hwScaleFilter ) & & isFullAfbcPipeline )
{
hwScaleFilter + = ":afbc=1" ;
}
// hw scale
// hw transpose & scale
mainFilters . Add ( hwScaleFilter ) ;
}
}
@ -5408,7 +5567,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
subFilters . Add ( "format=bgra" ) ;
}
@ -5418,7 +5577,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var subFramerate = hasAssSubs ? Math . Min ( framerate ? ? 25 , 60 ) : 10 ;
// alphasrc=s=1280x720:r=10:start=0,format=bgra,subtitles,hwupload
var alphaSrcFilter = GetAlphaSrcFilter ( state , inW, i nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var alphaSrcFilter = GetAlphaSrcFilter ( state , swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH , subFramerate ) ;
var subTextSubtitlesFilter = GetTextSubtitlesFilter ( state , true , true ) ;
subFilters . Add ( alphaSrcFilter ) ;
subFilters . Add ( "format=bgra" ) ;
@ -5435,7 +5594,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( hasGraphicalSubs )
{
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( inW, i nH, reqW , reqH , reqMaxW , reqMaxH ) ;
var subPreProcFilters = GetGraphicalSubPreProcessFilters ( swpInW, swpI nH, reqW , reqH , reqMaxW , reqMaxH ) ;
subFilters . Add ( subPreProcFilters ) ;
overlayFilters . Add ( "overlay=eof_action=pass:repeatlast=0" ) ;
}
@ -5837,6 +5996,11 @@ namespace MediaBrowser.Controller.MediaEncoding
// Disable the extra internal copy in nvdec. We already handle it in filter chain.
var nvdecNoInternalCopy = ffmpegVersion > = _minFFmpegHwaUnsafeOutput ;
// Strip the display rotation side data from the transposed fmp4 output stream.
var stripRotationData = ( state . VideoStream ? . Rotation ? ? 0 ) ! = 0
& & ffmpegVersion > = _minFFmpegDisplayRotationOption ;
var stripRotationDataArgs = stripRotationData ? " -display_rotation 0" : string . Empty ;
if ( bitDepth = = 10 & & isCodecAvailable )
{
if ( string . Equals ( videoCodec , "hevc" , StringComparison . OrdinalIgnoreCase )
@ -5861,13 +6025,13 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( isVaapiSupported & & isCodecAvailable )
{
return " -hwaccel vaapi" + ( outputHwSurface ? " -hwaccel_output_format vaapi " : string . Empty )
return " -hwaccel vaapi" + ( outputHwSurface ? " -hwaccel_output_format vaapi -noautorotate " + stripRotationDataArgs : string . Empty )
+ ( profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string . Empty ) + ( isAv1 ? " -c:v av1" : string . Empty ) ;
}
if ( isD3d11Supported & & isCodecAvailable )
{
return " -hwaccel d3d11va" + ( outputHwSurface ? " -hwaccel_output_format d3d11 " : string . Empty )
return " -hwaccel d3d11va" + ( outputHwSurface ? " -hwaccel_output_format d3d11 -noautorotate " + stripRotationDataArgs : string . Empty )
+ ( profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string . Empty ) + " -threads 2" + ( isAv1 ? " -c:v av1" : string . Empty ) ;
}
}
@ -5875,7 +6039,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( isQsvSupported & & isCodecAvailable )
{
return " -hwaccel qsv" + ( outputHwSurface ? " -hwaccel_output_format qsv " : string . Empty ) ;
return " -hwaccel qsv" + ( outputHwSurface ? " -hwaccel_output_format qsv -noautorotate " + stripRotationDataArgs : string . Empty ) ;
}
}
}
@ -5888,12 +6052,12 @@ namespace MediaBrowser.Controller.MediaEncoding
if ( options . EnableEnhancedNvdecDecoder )
{
// set -threads 1 to nvdec decoder explicitly since it doesn't implement threading support.
return " -hwaccel cuda" + ( outputHwSurface ? " -hwaccel_output_format cuda " : string . Empty )
return " -hwaccel cuda" + ( outputHwSurface ? " -hwaccel_output_format cuda -noautorotate " + stripRotationDataArgs : string . Empty )
+ ( nvdecNoInternalCopy ? " -hwaccel_flags +unsafe_output" : string . Empty ) + " -threads 1" + ( isAv1 ? " -c:v av1" : string . Empty ) ;
}
// 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 -noautorotate " + stripRotationDataArgs : string . Empty ) ;
}
}
@ -5902,7 +6066,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if ( isD3d11Supported & & isCodecAvailable )
{
return " -hwaccel d3d11va" + ( outputHwSurface ? " -hwaccel_output_format d3d11 " : string . Empty )
return " -hwaccel d3d11va" + ( outputHwSurface ? " -hwaccel_output_format d3d11 -noautorotate " + stripRotationDataArgs : string . Empty )
+ ( profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string . Empty ) + ( isAv1 ? " -c:v av1" : string . Empty ) ;
}
}
@ -5912,7 +6076,7 @@ namespace MediaBrowser.Controller.MediaEncoding
& & isVaapiSupported
& & isCodecAvailable )
{
return " -hwaccel vaapi" + ( outputHwSurface ? " -hwaccel_output_format vaapi " : string . Empty )
return " -hwaccel vaapi" + ( outputHwSurface ? " -hwaccel_output_format vaapi -noautorotate " + stripRotationDataArgs : string . Empty )
+ ( profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string . Empty ) + ( isAv1 ? " -c:v av1" : string . Empty ) ;
}
@ -5921,7 +6085,7 @@ namespace MediaBrowser.Controller.MediaEncoding
& & isVideotoolboxSupported
& & isCodecAvailable )
{
return " -hwaccel videotoolbox" + ( outputHwSurface ? " -hwaccel_output_format videotoolbox_vld" : string . Empty ) ;
return " -hwaccel videotoolbox" + ( outputHwSurface ? " -hwaccel_output_format videotoolbox_vld" : string . Empty ) + "-noautorotate" + stripRotationDataArgs ;
}
// Rockchip rkmpp
@ -5929,7 +6093,7 @@ namespace MediaBrowser.Controller.MediaEncoding
& & isRkmppSupported
& & isCodecAvailable )
{
return " -hwaccel rkmpp" + ( outputHwSurface ? " -hwaccel_output_format drm_prime " : string . Empty ) ;
return " -hwaccel rkmpp" + ( outputHwSurface ? " -hwaccel_output_format drm_prime -noautorotate " + stripRotationDataArgs : string . Empty ) ;
}
return null ;