@ -65,6 +65,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly Version _minFFmpegVaapiH26xEncA53CcSei = new Version ( 6 , 0 ) ;
private readonly Version _minFFmpegReadrateOption = new Version ( 5 , 0 ) ;
private readonly Version _minFFmpegWorkingVtHwSurface = new Version ( 7 , 0 , 1 ) ;
private readonly Version _minFFmpegDisplayRotationOption = new Version ( 6 , 0 ) ;
private static readonly Regex _validationRegex = new ( ValidationRegex , RegexOptions . Compiled ) ;
@ -231,6 +232,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" ) ;
}
@ -248,6 +250,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 ( )
@ -258,6 +262,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 ( )
@ -265,7 +271,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 ( )
@ -275,6 +283,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 IsSwTonemapAvailable ( EncodingJobInfo state , EncodingOptions options )
@ -1147,9 +1157,6 @@ namespace MediaBrowser.Controller.MediaEncoding
args . Append ( vidDecoder ) ;
}
// hw transpose filters should be added manually.
args . Append ( " -noautorotate" ) ;
return args . ToString ( ) . Trim ( ) ;
}
@ -2947,8 +2954,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
public static string GetHwScaleFilter (
string hwScalePrefix ,
string hwScaleSuffix ,
string videoFormat ,
bool swapOutputWandH ,
int? videoWidth ,
int? videoHeight ,
int? requestedWidth ,
@ -2970,8 +2979,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 ;
@ -2981,7 +2993,8 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return string . Format (
CultureInfo . InvariantCulture ,
"scale_{0}{1}{2}" ,
"{0}_{1}{2}{3}" ,
hwScalePrefix ? ? "scale" ,
hwScaleSuffix ,
arg1 ,
arg2 ) ;
@ -3384,6 +3397,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>
@ -3418,6 +3443,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 > ( ) ;
@ -3432,7 +3462,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" ;
@ -3481,7 +3511,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" ) ;
}
@ -3555,6 +3585,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 > ( ) ;
@ -3571,10 +3608,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 )
@ -3593,8 +3630,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 ) ;
}
@ -3644,7 +3687,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" ) ;
}
@ -3654,7 +3697,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" ) ;
@ -3669,7 +3712,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" ) ;
}
@ -3745,6 +3788,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 > ( ) ;
@ -3761,10 +3812,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.
@ -3773,7 +3824,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
mainFilters . Add ( "hwupload=derive_device=d3d11va:extra_hw_frames=24" ) ;
mainFilters . Add ( "format=d3d11" ) ;
mainFilters . Add ( "hwmap=derive_device=opencl ") ;
mainFilters . Add ( "hwmap=derive_device=opencl :mode=read ") ;
}
}
@ -3781,12 +3832,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 ) ;
}
@ -3831,7 +3888,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" ) ;
}
@ -3844,7 +3901,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" ) ;
}
@ -3854,7 +3911,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" ) ;
@ -3863,7 +3920,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" ) ;
}
}
@ -3871,7 +3928,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" ) ;
}
@ -3967,6 +4024,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 > ( ) ;
@ -3983,10 +4047,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.
@ -3998,8 +4062,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 )
{
@ -4018,14 +4089,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
@ -4069,7 +4140,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" ) ;
}
@ -4083,7 +4154,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" ) ;
}
@ -4093,7 +4164,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" ) ;
@ -4104,9 +4175,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 ,
@ -4119,7 +4190,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" ) ;
}
@ -4164,6 +4235,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 > ( ) ;
@ -4180,10 +4258,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.
@ -4195,24 +4273,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 ) ;
}
@ -4240,7 +4333,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
@ -4287,7 +4380,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 )
@ -4307,7 +4400,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" ) ;
}
@ -4316,7 +4409,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" ) ;
@ -4327,9 +4420,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 ,
@ -4342,7 +4435,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" ) ;
}
@ -4453,6 +4546,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 > ( ) ;
@ -4469,10 +4569,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.
@ -4492,8 +4592,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 ) )
@ -4515,7 +4621,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
@ -4529,7 +4635,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" ) ;
}
@ -4580,7 +4686,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" ) ;
}
@ -4589,7 +4695,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" ) ;
@ -4598,9 +4704,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 ,
@ -4613,7 +4719,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" ) ;
@ -4658,6 +4764,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 > ( ) ;
@ -4682,7 +4795,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" ) ;
}
@ -4690,7 +4803,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" ) ;
@ -4706,15 +4819,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 ) ;
}
@ -4758,7 +4884,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" ) ;
}
@ -4767,7 +4893,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" ) ;
@ -4839,6 +4965,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 > ( ) ;
@ -4856,7 +4987,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 ) ;
@ -4880,7 +5011,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 ) )
@ -4976,7 +5107,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" ) ;
@ -5030,6 +5161,15 @@ namespace MediaBrowser.Controller.MediaEncoding
string vidDecoder ,
string vidEncoder )
{
var isVtEncoder = vidEncoder . Contains ( "videotoolbox" , StringComparison . OrdinalIgnoreCase ) ;
var isVtDecoder = vidDecoder . 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 ;
@ -5038,9 +5178,6 @@ namespace MediaBrowser.Controller.MediaEncoding
var reqMaxH = state . BaseRequest . MaxHeight ;
var threeDFormat = state . MediaSource . Video3DFormat ;
var isVtEncoder = vidEncoder . Contains ( "videotoolbox" , StringComparison . OrdinalIgnoreCase ) ;
var isVtDecoder = vidDecoder . 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 ;
@ -5048,6 +5185,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var doMetalTonemap = ! doVtTonemap & & IsHwTonemapAvailable ( state , options ) ;
var usingHwSurface = isVtDecoder & & ( _mediaEncoder . EncoderVersion > = _minFFmpegWorkingVtHwSurface ) ;
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 ) )
@ -5065,7 +5209,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 ;
@ -5074,12 +5218,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 > ( ) ;
@ -5090,6 +5228,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" ;
@ -5118,7 +5262,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" ) ;
}
@ -5127,7 +5271,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" ) ;
@ -5229,6 +5373,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 > ( ) ;
@ -5245,7 +5396,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" ;
@ -5253,7 +5404,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.
@ -5268,21 +5419,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 ) ;
}
}
@ -5353,7 +5512,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" ) ;
}
@ -5363,7 +5522,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" ) ;
@ -5380,7 +5539,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" ) ;
}
@ -5795,6 +5954,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 )
@ -5819,13 +5983,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 ) ;
}
}
@ -5833,7 +5997,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 ) ;
}
}
}
@ -5846,12 +6010,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 ) ;
}
}
@ -5860,7 +6024,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 ) ;
}
}
@ -5870,7 +6034,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 ) ;
}
@ -5879,7 +6043,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
@ -5887,7 +6051,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 ;