@ -337,9 +337,9 @@ namespace MediaBrowser.Api.Playback
/// Gets the video bitrate to specify on the command line
/// </summary>
/// <param name="state">The state.</param>
/// <param name="video Codec ">The video codec.</param>
/// <param name="video Encoder ">The video codec.</param>
/// <returns>System.String.</returns>
protected string GetVideoQualityParam ( StreamState state , string video Codec )
protected string GetVideoQualityParam ( StreamState state , string video Encoder )
{
var param = string . Empty ;
@ -348,7 +348,7 @@ namespace MediaBrowser.Api.Playback
var encodingOptions = ApiEntryPoint . Instance . GetEncodingOptions ( ) ;
if ( string . Equals ( video Codec , "libx264" , StringComparison . OrdinalIgnoreCase ) )
if ( string . Equals ( video Encoder , "libx264" , StringComparison . OrdinalIgnoreCase ) )
{
if ( ! string . IsNullOrWhiteSpace ( encodingOptions . H264Preset ) )
{
@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Playback
}
}
else if ( string . Equals ( video Codec , "libx265" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "libx265" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-preset fast" ;
@ -377,20 +377,20 @@ namespace MediaBrowser.Api.Playback
}
// h264 (h264_qsv)
else if ( string . Equals ( video Codec , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-preset 7 -look_ahead 0" ;
}
// h264 (h264_nvenc)
else if ( string . Equals ( video Codec , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-preset default" ;
}
// webm
else if ( string . Equals ( video Codec , "libvpx" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "libvpx" , StringComparison . OrdinalIgnoreCase ) )
{
// Values 0-3, 0 being highest quality but slower
var profileScore = 0 ;
@ -417,23 +417,23 @@ namespace MediaBrowser.Api.Playback
qmax ) ;
}
else if ( string . Equals ( video Codec , "mpeg4" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "mpeg4" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2" ;
}
// asf/wmv
else if ( string . Equals ( video Codec , "wmv2" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "wmv2" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-qmin 2" ;
}
else if ( string . Equals ( video Codec , "msmpeg4" , StringComparison . OrdinalIgnoreCase ) )
else if ( string . Equals ( video Encoder , "msmpeg4" , StringComparison . OrdinalIgnoreCase ) )
{
param + = "-mbd 2" ;
}
param + = GetVideoBitrateParam ( state , video Codec ) ;
param + = GetVideoBitrateParam ( state , video Encoder ) ;
var framerate = GetFramerateParam ( state ) ;
if ( framerate . HasValue )
@ -448,8 +448,8 @@ namespace MediaBrowser.Api.Playback
if ( ! string . IsNullOrEmpty ( state . VideoRequest . Profile ) )
{
if ( ! string . Equals ( video Codec , "h264_omx" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Codec , "h264_vaapi" , StringComparison . OrdinalIgnoreCase ) )
if ( ! string . Equals ( video Encoder , "h264_omx" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Encoder , "h264_vaapi" , StringComparison . OrdinalIgnoreCase ) )
{
// not supported by h264_omx
param + = " -profile:v " + state . VideoRequest . Profile ;
@ -458,11 +458,13 @@ namespace MediaBrowser.Api.Playback
if ( ! string . IsNullOrEmpty ( state . VideoRequest . Level ) )
{
var level = NormalizeTranscodingLevel ( state . OutputVideoCodec , state . VideoRequest . Level ) ;
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
if ( string . Equals ( videoCodec , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) | |
string . Equals ( video Codec , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) )
if ( string . Equals ( video Encoder , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) | |
string . Equals ( video Encoder , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) )
{
switch ( state. VideoRequest . L evel)
switch ( l evel)
{
case "30" :
param + = " -level 3" ;
@ -492,20 +494,20 @@ namespace MediaBrowser.Api.Playback
param + = " -level 5.2" ;
break ;
default :
param + = " -level " + state. VideoRequest . L evel;
param + = " -level " + l evel;
break ;
}
}
else if ( ! string . Equals ( video Codec , "h264_omx" , StringComparison . OrdinalIgnoreCase ) )
else if ( ! string . Equals ( video Encoder , "h264_omx" , StringComparison . OrdinalIgnoreCase ) )
{
param + = " -level " + state. VideoRequest . L evel;
param + = " -level " + l evel;
}
}
if ( ! string . Equals ( video Codec , "h264_omx" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Codec , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Codec , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Codec , "h264_vaapi" , StringComparison . OrdinalIgnoreCase ) )
if ( ! string . Equals ( video Encoder , "h264_omx" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Encoder , "h264_qsv" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Encoder , "h264_nvenc" , StringComparison . OrdinalIgnoreCase ) & &
! string . Equals ( video Encoder , "h264_vaapi" , StringComparison . OrdinalIgnoreCase ) )
{
param = "-pix_fmt yuv420p " + param ;
}
@ -513,6 +515,25 @@ namespace MediaBrowser.Api.Playback
return param ;
}
private string NormalizeTranscodingLevel ( string videoCodec , string level )
{
double requestLevel ;
// Clients may direct play higher than level 41, but there's no reason to transcode higher
if ( double . TryParse ( level , NumberStyles . Any , UsCulture , out requestLevel ) )
{
if ( string . Equals ( videoCodec , "h264" , StringComparison . OrdinalIgnoreCase ) )
{
if ( requestLevel > 41 )
{
return "41" ;
}
}
}
return level ;
}
protected string GetAudioFilterParam ( StreamState state , bool isHls )
{
var volParam = string . Empty ;
@ -1176,17 +1197,21 @@ namespace MediaBrowser.Api.Playback
await Task . Delay ( 100 , cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
}
if ( state . IsInputVideo & & transcodingJob . Type = = TranscodingJobType . Progressive )
if ( state . IsInputVideo & & transcodingJob . Type = = TranscodingJobType . Progressive & & ! transcodingJob . HasExited )
{
await Task . Delay ( 1000 , cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
if ( state . ReadInputAtNativeFramerate )
if ( state . ReadInputAtNativeFramerate & & ! transcodingJob . HasExited )
{
await Task . Delay ( 1500 , cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
}
}
StartThrottler ( state , transcodingJob ) ;
if ( ! transcodingJob . HasExited )
{
StartThrottler ( state , transcodingJob ) ;
}
ReportUsage ( state ) ;
return transcodingJob ;