@ -135,9 +135,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var inputFiles = MediaEncoderHelpers . GetInputArgument ( FileSystem , request . InputPath , request . Protocol , request . MountedIso , request . PlayableStreamFileNames ) ;
var extractKeyFrameInterval = request . ExtractKeyFrameInterval & & request . Protocol = = MediaProtocol . File & & request . VideoType = = VideoType . VideoFile ;
return GetMediaInfoInternal ( GetInputArgument ( inputFiles , request . Protocol ) , request . InputPath , request . Protocol , extractChapters , extractKeyFrameInterval ,
return GetMediaInfoInternal ( GetInputArgument ( inputFiles , request . Protocol ) , request . InputPath , request . Protocol , extractChapters ,
GetProbeSizeArgument ( inputFiles , request . Protocol ) , request . MediaType = = DlnaProfileType . Audio , request . VideoType , cancellationToken ) ;
}
@ -171,18 +169,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <param name="primaryPath">The primary path.</param>
/// <param name="protocol">The protocol.</param>
/// <param name="extractChapters">if set to <c>true</c> [extract chapters].</param>
/// <param name="extractKeyFrameInterval">if set to <c>true</c> [extract key frame interval].</param>
/// <param name="probeSizeArgument">The probe size argument.</param>
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
/// <param name="videoType">Type of the video.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{MediaInfoResult}.</returns>
/// <exception cref="System.ApplicationException"> </exception>
/// <exception cref="System.ApplicationException"> ffprobe failed - streams and format are both null. </exception>
private async Task < Model . MediaInfo . MediaInfo > GetMediaInfoInternal ( string inputPath ,
string primaryPath ,
MediaProtocol protocol ,
bool extractChapters ,
bool extractKeyFrameInterval ,
string probeSizeArgument ,
bool isAudio ,
VideoType videoType ,
@ -262,42 +258,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
var mediaInfo = new ProbeResultNormalizer ( _logger , FileSystem ) . GetMediaInfo ( result , videoType , isAudio , primaryPath , protocol ) ;
var videoStream = mediaInfo . MediaStreams . FirstOrDefault ( i = > i . Type = = MediaStreamType . Video ) ;
//var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video) ;
if ( videoStream ! = null )
{
var isInterlaced = await DetectInterlaced ( mediaInfo , videoStream , inputPath , probeSizeArgument ) . ConfigureAwait ( false ) ;
//if (videoStream != null )
// {
// var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false);
if ( isInterlaced )
{
videoStream . IsInterlaced = true ;
}
}
if ( extractKeyFrameInterval & & mediaInfo . RunTimeTicks . HasValue )
{
if ( ConfigurationManager . Configuration . EnableVideoFrameByFrameAnalysis & & mediaInfo . Size . HasValue )
{
foreach ( var stream in mediaInfo . MediaStreams )
{
if ( EnableKeyframeExtraction ( mediaInfo , stream ) )
{
try
{
stream . KeyFrames = await GetKeyFrames ( inputPath , stream . Index , cancellationToken ) . ConfigureAwait ( false ) ;
}
catch ( OperationCanceledException )
{
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error getting key frame interval" , ex ) ;
}
}
}
}
}
// if (isInterlaced)
// {
// videoStream.IsInterlaced = true;
// }
//}
return mediaInfo ;
}
@ -312,8 +283,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
_ffProbeResourcePool . Release ( ) ;
}
}
throw new ApplicationException ( string . Format ( "FFProbe failed for {0}" , inputPath ) ) ;
}
private async Task < bool > DetectInterlaced ( MediaSourceInfo video , MediaStream videoStream , string inputPath , string probeSizeArgument )
@ -326,7 +295,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
var formats = ( video . Container ? ? string . Empty ) . Split ( ',' ) . ToList ( ) ;
// Take a shortcut and limit this to containers that are likely to have interlaced content
if ( ! formats . Contains ( "ts" , StringComparer . OrdinalIgnoreCase ) & &
if ( ! formats . Contains ( "vob" , StringComparer . OrdinalIgnoreCase ) & &
! formats . Contains ( "m2ts" , StringComparer . OrdinalIgnoreCase ) & &
! formats . Contains ( "ts" , StringComparer . OrdinalIgnoreCase ) & &
! formats . Contains ( "mpegts" , StringComparer . OrdinalIgnoreCase ) & &
! formats . Contains ( "wtv" , StringComparer . OrdinalIgnoreCase ) )
{
@ -356,7 +327,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
EnableRaisingEvents = true
} ;
_logger . Info ( "{0} {1}" , process . StartInfo . FileName , process . StartInfo . Arguments ) ;
_logger . Debug ( "{0} {1}" , process . StartInfo . FileName , process . StartInfo . Arguments ) ;
var idetFoundInterlaced = false ;
using ( var processWrapper = new ProcessWrapper ( process , this , _logger ) )
@ -493,128 +464,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
return 0 ;
}
private bool EnableKeyframeExtraction ( MediaSourceInfo mediaSource , MediaStream videoStream )
{
if ( videoStream . Type = = MediaStreamType . Video & & string . Equals ( videoStream . Codec , "h264" , StringComparison . OrdinalIgnoreCase ) & &
! videoStream . IsInterlaced & &
! ( videoStream . IsAnamorphic ? ? false ) )
{
var audioStreams = mediaSource . MediaStreams . Where ( i = > i . Type = = MediaStreamType . Audio ) . ToList ( ) ;
// If it has aac audio then it will probably direct stream anyway, so don't bother with this
if ( audioStreams . Count = = 1 & & string . Equals ( audioStreams [ 0 ] . Codec , "aac" , StringComparison . OrdinalIgnoreCase ) )
{
return false ;
}
return true ;
}
return false ;
}
private async Task < List < int > > GetKeyFrames ( string inputPath , int videoStreamIndex , CancellationToken cancellationToken )
{
inputPath = inputPath . Split ( new [ ] { ':' } , 2 ) . Last ( ) . Trim ( '"' ) ;
const string args = "-show_packets -print_format compact -select_streams v:{1} -show_entries packet=flags -show_entries packet=pts_time \"{0}\"" ;
var process = new Process
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true ,
UseShellExecute = false ,
// Must consume both or ffmpeg may hang due to deadlocks. See comments below.
RedirectStandardOutput = true ,
RedirectStandardError = true ,
FileName = FFProbePath ,
Arguments = string . Format ( args , inputPath , videoStreamIndex . ToString ( CultureInfo . InvariantCulture ) ) . Trim ( ) ,
WindowStyle = ProcessWindowStyle . Hidden ,
ErrorDialog = false
} ,
EnableRaisingEvents = true
} ;
_logger . Info ( "{0} {1}" , process . StartInfo . FileName , process . StartInfo . Arguments ) ;
using ( process )
{
var start = DateTime . UtcNow ;
process . Start ( ) ;
var lines = new List < int > ( ) ;
try
{
process . BeginErrorReadLine ( ) ;
await StartReadingOutput ( process . StandardOutput . BaseStream , lines , cancellationToken ) . ConfigureAwait ( false ) ;
}
catch ( OperationCanceledException )
{
if ( cancellationToken . IsCancellationRequested )
{
throw ;
}
}
process . WaitForExit ( ) ;
_logger . Info ( "Keyframe extraction took {0} seconds" , ( DateTime . UtcNow - start ) . TotalSeconds ) ;
//_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray()));
return lines ;
}
}
private async Task StartReadingOutput ( Stream source , List < int > keyframes , CancellationToken cancellationToken )
{
try
{
using ( var reader = new StreamReader ( source ) )
{
var text = await reader . ReadToEndAsync ( ) . ConfigureAwait ( false ) ;
var lines = StringHelper . RegexSplit ( text , "[\r\n]+" ) ;
foreach ( var line in lines )
{
if ( string . IsNullOrWhiteSpace ( line ) )
{
continue ;
}
var values = line . Split ( '|' )
. Where ( i = > ! string . IsNullOrWhiteSpace ( i ) )
. Select ( i = > i . Split ( '=' ) )
. Where ( i = > i . Length = = 2 )
. ToDictionary ( i = > i [ 0 ] , i = > i [ 1 ] ) ;
string flags ;
if ( values . TryGetValue ( "flags" , out flags ) & & string . Equals ( flags , "k" , StringComparison . OrdinalIgnoreCase ) )
{
string pts_time ;
double frameSeconds ;
if ( values . TryGetValue ( "pts_time" , out pts_time ) & & double . TryParse ( pts_time , NumberStyles . Any , CultureInfo . InvariantCulture , out frameSeconds ) )
{
var ms = frameSeconds * 1000 ;
keyframes . Add ( Convert . ToInt32 ( ms ) ) ;
}
}
}
}
}
catch ( OperationCanceledException )
{
throw ;
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error reading ffprobe output" , ex ) ;
}
}
/// <summary>
/// The us culture
/// </summary>