@ -123,6 +123,7 @@ const char *const forced_keyframes_const_names[] = {
static void do_video_stats ( OutputStream * ost , int frame_size ) ;
static int64_t getutime ( void ) ;
static int64_t getmaxrss ( void ) ;
static int ifilter_has_all_input_formats ( FilterGraph * fg ) ;
static int run_as_daemon = 0 ;
static int nb_frames_dup = 0 ;
@ -472,6 +473,13 @@ static void ffmpeg_cleanup(int ret)
FilterGraph * fg = filtergraphs [ i ] ;
avfilter_graph_free ( & fg - > graph ) ;
for ( j = 0 ; j < fg - > nb_inputs ; j + + ) {
while ( av_fifo_size ( fg - > inputs [ j ] - > frame_queue ) ) {
AVFrame * frame ;
av_fifo_generic_read ( fg - > inputs [ j ] - > frame_queue , & frame ,
sizeof ( frame ) , NULL ) ;
av_frame_free ( & frame ) ;
}
av_fifo_free ( fg - > inputs [ j ] - > frame_queue ) ;
av_buffer_unref ( & fg - > inputs [ j ] - > hw_frames_ctx ) ;
av_freep ( & fg - > inputs [ j ] - > name ) ;
av_freep ( & fg - > inputs [ j ] ) ;
@ -1377,6 +1385,8 @@ static void do_video_stats(OutputStream *ost, int frame_size)
}
}
static int init_output_stream ( OutputStream * ost , char * error , int error_len ) ;
static void finish_output_stream ( OutputStream * ost )
{
OutputFile * of = output_files [ ost - > file_index ] ;
@ -1409,10 +1419,20 @@ static int reap_filters(int flush)
AVCodecContext * enc = ost - > enc_ctx ;
int ret = 0 ;
if ( ! ost - > filter )
if ( ! ost - > filter | | ! ost - > filter - > graph - > graph )
continue ;
filter = ost - > filter - > filter ;
if ( ! ost - > initialized ) {
char error [ 1024 ] ;
ret = init_output_stream ( ost , error , sizeof ( error ) ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error initializing output stream %d:%d -- %s \n " ,
ost - > file_index , ost - > index , error ) ;
exit_program ( 1 ) ;
}
}
if ( ! ost - > filtered_frame & & ! ( ost - > filtered_frame = av_frame_alloc ( ) ) ) {
return AVERROR ( ENOMEM ) ;
}
@ -1813,6 +1833,54 @@ static void flush_encoders(void)
if ( ! ost - > encoding_needed )
continue ;
// Try to enable encoding with no input frames.
// Maybe we should just let encoding fail instead.
if ( ! ost - > initialized ) {
FilterGraph * fg = ost - > filter - > graph ;
char error [ 1024 ] ;
av_log ( NULL , AV_LOG_WARNING ,
" Finishing stream %d:%d without any data written to it. \n " ,
ost - > file_index , ost - > st - > index ) ;
if ( ost - > filter & & ! fg - > graph ) {
int x ;
for ( x = 0 ; x < fg - > nb_inputs ; x + + ) {
InputFilter * ifilter = fg - > inputs [ x ] ;
if ( ifilter - > format < 0 ) {
AVCodecParameters * par = ifilter - > ist - > st - > codecpar ;
// We never got any input. Set a fake format, which will
// come from libavformat.
ifilter - > format = par - > format ;
ifilter - > sample_rate = par - > sample_rate ;
ifilter - > channels = par - > channels ;
ifilter - > channel_layout = par - > channel_layout ;
ifilter - > width = par - > width ;
ifilter - > height = par - > height ;
ifilter - > sample_aspect_ratio = par - > sample_aspect_ratio ;
}
}
if ( ! ifilter_has_all_input_formats ( fg ) )
continue ;
ret = configure_filtergraph ( fg ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error configuring filter graph \n " ) ;
exit_program ( 1 ) ;
}
finish_output_stream ( ost ) ;
}
ret = init_output_stream ( ost , error , sizeof ( error ) ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error initializing output stream %d:%d -- %s \n " ,
ost - > file_index , ost - > index , error ) ;
exit_program ( 1 ) ;
}
}
if ( enc - > codec_type = = AVMEDIA_TYPE_AUDIO & & enc - > frame_size < = 1 )
continue ;
# if FF_API_LAVF_FMT_RAWPICTURE
@ -2044,6 +2112,102 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
}
}
// Filters can be configured only if the formats of all inputs are known.
static int ifilter_has_all_input_formats ( FilterGraph * fg )
{
int i ;
for ( i = 0 ; i < fg - > nb_inputs ; i + + ) {
if ( fg - > inputs [ i ] - > format < 0 & & ( fg - > inputs [ i ] - > type = = AVMEDIA_TYPE_AUDIO | |
fg - > inputs [ i ] - > type = = AVMEDIA_TYPE_VIDEO ) )
return 0 ;
}
return 1 ;
}
static int ifilter_send_frame ( InputFilter * ifilter , AVFrame * frame )
{
FilterGraph * fg = ifilter - > graph ;
int need_reinit , ret , i ;
/* determine if the parameters for this input changed */
need_reinit = ifilter - > format ! = frame - > format ;
if ( ! ! ifilter - > hw_frames_ctx ! = ! ! frame - > hw_frames_ctx | |
( ifilter - > hw_frames_ctx & & ifilter - > hw_frames_ctx - > data ! = frame - > hw_frames_ctx - > data ) )
need_reinit = 1 ;
switch ( ifilter - > ist - > st - > codecpar - > codec_type ) {
case AVMEDIA_TYPE_AUDIO :
need_reinit | = ifilter - > sample_rate ! = frame - > sample_rate | |
ifilter - > channels ! = frame - > channels | |
ifilter - > channel_layout ! = frame - > channel_layout ;
break ;
case AVMEDIA_TYPE_VIDEO :
need_reinit | = ifilter - > width ! = frame - > width | |
ifilter - > height ! = frame - > height ;
break ;
}
if ( need_reinit ) {
ret = ifilter_parameters_from_frame ( ifilter , frame ) ;
if ( ret < 0 )
return ret ;
}
/* (re)init the graph if possible, otherwise buffer the frame and return */
if ( need_reinit | | ! fg - > graph ) {
for ( i = 0 ; i < fg - > nb_inputs ; i + + ) {
if ( ! ifilter_has_all_input_formats ( fg ) ) {
AVFrame * tmp = av_frame_clone ( frame ) ;
if ( ! tmp )
return AVERROR ( ENOMEM ) ;
av_frame_unref ( frame ) ;
if ( ! av_fifo_space ( ifilter - > frame_queue ) ) {
ret = av_fifo_realloc2 ( ifilter - > frame_queue , 2 * av_fifo_size ( ifilter - > frame_queue ) ) ;
if ( ret < 0 )
return ret ;
}
av_fifo_generic_write ( ifilter - > frame_queue , & tmp , sizeof ( tmp ) , NULL ) ;
return 0 ;
}
}
ret = reap_filters ( 1 ) ;
if ( ret < 0 & & ret ! = AVERROR_EOF ) {
char errbuf [ 128 ] ;
av_strerror ( ret , errbuf , sizeof ( errbuf ) ) ;
av_log ( NULL , AV_LOG_ERROR , " Error while filtering: %s \n " , errbuf ) ;
return ret ;
}
ret = configure_filtergraph ( fg ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error reinitializing filters! \n " ) ;
return ret ;
}
for ( i = 0 ; i < fg - > nb_inputs ; i + + ) {
while ( av_fifo_size ( fg - > inputs [ i ] - > frame_queue ) ) {
AVFrame * tmp ;
av_fifo_generic_read ( fg - > inputs [ i ] - > frame_queue , & tmp , sizeof ( tmp ) , NULL ) ;
ret = av_buffersrc_add_frame ( fg - > inputs [ i ] - > filter , tmp ) ;
av_frame_free ( & tmp ) ;
if ( ret < 0 )
return ret ;
}
}
}
ret = av_buffersrc_add_frame_flags ( ifilter - > filter , frame , AV_BUFFERSRC_FLAG_PUSH ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error while filtering \n " ) ;
return ret ;
}
return 0 ;
}
// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
// There is the following difference: if you got a frame, you must call
// it again with pkt=NULL. pkt==NULL is treated differently from pkt.size==0
@ -2085,8 +2249,7 @@ static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
break ;
} else
f = decoded_frame ;
ret = av_buffersrc_add_frame_flags ( ist - > filters [ i ] - > filter , f ,
AV_BUFFERSRC_FLAG_PUSH ) ;
ret = ifilter_send_frame ( ist - > filters [ i ] , f ) ;
if ( ret = = AVERROR_EOF )
ret = 0 ; /* ignore */
if ( ret < 0 ) {
@ -2102,7 +2265,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
{
AVFrame * decoded_frame ;
AVCodecContext * avctx = ist - > dec_ctx ;
int i , ret , err = 0 , resample_changed ;
int ret , err = 0 ;
AVRational decoded_frame_tb ;
if ( ! ist - > decoded_frame & & ! ( ist - > decoded_frame = av_frame_alloc ( ) ) )
@ -2138,59 +2301,6 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
avctx - > sample_rate ;
# endif
resample_changed = ist - > resample_sample_fmt ! = decoded_frame - > format | |
ist - > resample_channels ! = avctx - > channels | |
ist - > resample_channel_layout ! = decoded_frame - > channel_layout | |
ist - > resample_sample_rate ! = decoded_frame - > sample_rate ;
if ( resample_changed ) {
char layout1 [ 64 ] , layout2 [ 64 ] ;
if ( ! guess_input_channel_layout ( ist ) ) {
av_log ( NULL , AV_LOG_FATAL , " Unable to find default channel "
" layout for Input Stream #%d.%d \n " , ist - > file_index ,
ist - > st - > index ) ;
exit_program ( 1 ) ;
}
decoded_frame - > channel_layout = avctx - > channel_layout ;
av_get_channel_layout_string ( layout1 , sizeof ( layout1 ) , ist - > resample_channels ,
ist - > resample_channel_layout ) ;
av_get_channel_layout_string ( layout2 , sizeof ( layout2 ) , avctx - > channels ,
decoded_frame - > channel_layout ) ;
av_log ( NULL , AV_LOG_INFO ,
" Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s \n " ,
ist - > file_index , ist - > st - > index ,
ist - > resample_sample_rate , av_get_sample_fmt_name ( ist - > resample_sample_fmt ) ,
ist - > resample_channels , layout1 ,
decoded_frame - > sample_rate , av_get_sample_fmt_name ( decoded_frame - > format ) ,
avctx - > channels , layout2 ) ;
ist - > resample_sample_fmt = decoded_frame - > format ;
ist - > resample_sample_rate = decoded_frame - > sample_rate ;
ist - > resample_channel_layout = decoded_frame - > channel_layout ;
ist - > resample_channels = avctx - > channels ;
for ( i = 0 ; i < ist - > nb_filters ; i + + ) {
err = ifilter_parameters_from_frame ( ist - > filters [ i ] , decoded_frame ) ;
if ( err < 0 ) {
av_log ( NULL , AV_LOG_ERROR ,
" Error reconfiguring input stream %d:%d filter %d \n " ,
ist - > file_index , ist - > st - > index , i ) ;
goto fail ;
}
}
for ( i = 0 ; i < nb_filtergraphs ; i + + )
if ( ist_in_filtergraph ( filtergraphs [ i ] , ist ) ) {
FilterGraph * fg = filtergraphs [ i ] ;
if ( configure_filtergraph ( fg ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , " Error reinitializing filters! \n " ) ;
exit_program ( 1 ) ;
}
}
}
if ( decoded_frame - > pts ! = AV_NOPTS_VALUE ) {
decoded_frame_tb = ist - > st - > time_base ;
} else if ( pkt & & pkt - > pts ! = AV_NOPTS_VALUE ) {
@ -2206,9 +2316,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
( AVRational ) { 1 , avctx - > sample_rate } ) ;
ist - > nb_samples = decoded_frame - > nb_samples ;
err = send_frame_to_filters ( ist , decoded_frame ) ;
decoded_frame - > pts = AV_NOPTS_VALUE ;
fail :
av_frame_unref ( ist - > filter_frame ) ;
av_frame_unref ( decoded_frame ) ;
return err < 0 ? err : ret ;
@ -2217,7 +2325,7 @@ fail:
static int decode_video ( InputStream * ist , AVPacket * pkt , int * got_output , int eof )
{
AVFrame * decoded_frame ;
int i , ret = 0 , err = 0 , resample_changed ;
int i , ret = 0 , err = 0 ;
int64_t best_effort_timestamp ;
int64_t dts = AV_NOPTS_VALUE ;
AVPacket avpkt ;
@ -2332,39 +2440,6 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int eo
if ( ist - > st - > sample_aspect_ratio . num )
decoded_frame - > sample_aspect_ratio = ist - > st - > sample_aspect_ratio ;
resample_changed = ist - > resample_width ! = decoded_frame - > width | |
ist - > resample_height ! = decoded_frame - > height | |
ist - > resample_pix_fmt ! = decoded_frame - > format ;
if ( resample_changed ) {
av_log ( NULL , AV_LOG_INFO ,
" Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s \n " ,
ist - > file_index , ist - > st - > index ,
ist - > resample_width , ist - > resample_height , av_get_pix_fmt_name ( ist - > resample_pix_fmt ) ,
decoded_frame - > width , decoded_frame - > height , av_get_pix_fmt_name ( decoded_frame - > format ) ) ;
ist - > resample_width = decoded_frame - > width ;
ist - > resample_height = decoded_frame - > height ;
ist - > resample_pix_fmt = decoded_frame - > format ;
for ( i = 0 ; i < ist - > nb_filters ; i + + ) {
err = ifilter_parameters_from_frame ( ist - > filters [ i ] , decoded_frame ) ;
if ( err < 0 ) {
av_log ( NULL , AV_LOG_ERROR ,
" Error reconfiguring input stream %d:%d filter %d \n " ,
ist - > file_index , ist - > st - > index , i ) ;
goto fail ;
}
}
for ( i = 0 ; i < nb_filtergraphs ; i + + ) {
if ( ist_in_filtergraph ( filtergraphs [ i ] , ist ) & & ist - > reinit_filters & &
configure_filtergraph ( filtergraphs [ i ] ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , " Error reinitializing filters! \n " ) ;
exit_program ( 1 ) ;
}
}
}
err = send_frame_to_filters ( ist , decoded_frame ) ;
fail :
@ -2434,11 +2509,18 @@ out:
static int send_filter_eof ( InputStream * ist )
{
int i , ret ;
int i , j , ret ;
for ( i = 0 ; i < ist - > nb_filters ; i + + ) {
if ( ist - > filters [ i ] - > filter ) {
ret = av_buffersrc_add_frame ( ist - > filters [ i ] - > filter , NULL ) ;
if ( ret < 0 )
return ret ;
} else {
// the filtergraph was never configured
FilterGraph * fg = ist - > filters [ i ] - > graph ;
for ( j = 0 ; j < fg - > nb_outputs ; j + + )
finish_output_stream ( fg - > outputs [ j ] - > ost ) ;
}
}
return 0 ;
}
@ -2544,6 +2626,9 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
break ;
}
if ( got_output )
ist - > got_output = 1 ;
if ( ! got_output )
break ;
@ -2721,17 +2806,9 @@ static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
static int init_input_stream ( int ist_index , char * error , int error_len )
{
int i , ret ;
int ret ;
InputStream * ist = input_streams [ ist_index ] ;
for ( i = 0 ; i < ist - > nb_filters ; i + + ) {
ret = ifilter_parameters_from_decoder ( ist - > filters [ i ] , ist - > dec_ctx ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_FATAL , " Error initializing filter input \n " ) ;
return ret ;
}
}
if ( ist - > decoding_needed ) {
AVCodec * codec = ist - > dec ;
if ( ! codec ) {
@ -3125,17 +3202,6 @@ static int init_output_stream_encode(OutputStream *ost)
ost - > st - > disposition = AV_DISPOSITION_DEFAULT ;
}
if ( ( enc_ctx - > codec_type = = AVMEDIA_TYPE_VIDEO | |
enc_ctx - > codec_type = = AVMEDIA_TYPE_AUDIO ) & &
filtergraph_is_simple ( ost - > filter - > graph ) ) {
FilterGraph * fg = ost - > filter - > graph ;
if ( configure_filtergraph ( fg ) ) {
av_log ( NULL , AV_LOG_FATAL , " Error opening filters! \n " ) ;
exit_program ( 1 ) ;
}
}
if ( enc_ctx - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
if ( ! ost - > frame_rate . num )
ost - > frame_rate = av_buffersink_get_frame_rate ( ost - > filter - > filter ) ;
@ -3475,10 +3541,6 @@ static int transcode_init(void)
ost = output_streams [ i ] ;
if ( ! ost - > stream_copy ) {
# if CONFIG_LIBMFX
if ( qsv_transcode_init ( ost ) )
exit_program ( 1 ) ;
# endif
# if CONFIG_CUVID
if ( cuvid_transcode_init ( ost ) )
@ -3499,6 +3561,10 @@ static int transcode_init(void)
/* open each encoder */
for ( i = 0 ; i < nb_output_streams ; i + + ) {
// skip streams fed from filtergraphs until we have a frame for them
if ( output_streams [ i ] - > filter )
continue ;
ret = init_output_stream ( output_streams [ i ] , error , sizeof ( error ) ) ;
if ( ret < 0 )
goto dump_format ;
@ -3669,6 +3735,9 @@ static OutputStream *choose_output(void)
if ( ost - > st - > cur_dts = = AV_NOPTS_VALUE )
av_log ( NULL , AV_LOG_DEBUG , " cur_dts is invalid (this is harmless if it occurs once at the start per stream) \n " ) ;
if ( ! ost - > initialized & & ! ost - > inputs_done )
return ost ;
if ( ! ost - > finished & & opts < opts_min ) {
opts_min = opts ;
ost_min = ost - > unavailable ? NULL : ost ;
@ -4326,7 +4395,7 @@ static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)
static int transcode_step ( void )
{
OutputStream * ost ;
InputStream * ist ;
InputStream * ist = NULL ;
int ret ;
ost = choose_output ( ) ;
@ -4340,11 +4409,34 @@ static int transcode_step(void)
return AVERROR_EOF ;
}
if ( ost - > filter ) {
if ( ost - > filter & & ! ost - > filter - > graph - > graph ) {
if ( ifilter_has_all_input_formats ( ost - > filter - > graph ) ) {
ret = configure_filtergraph ( ost - > filter - > graph ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error reinitializing filters! \n " ) ;
return ret ;
}
}
}
if ( ost - > filter & & ost - > filter - > graph - > graph ) {
if ( ( ret = transcode_from_filter ( ost - > filter - > graph , & ist ) ) < 0 )
return ret ;
if ( ! ist )
return 0 ;
} else if ( ost - > filter ) {
int i ;
for ( i = 0 ; i < ost - > filter - > graph - > nb_inputs ; i + + ) {
InputFilter * ifilter = ost - > filter - > graph - > inputs [ i ] ;
if ( ! ifilter - > ist - > got_output & & ! input_files [ ifilter - > ist - > file_index ] - > eof_reached ) {
ist = ifilter - > ist ;
break ;
}
}
if ( ! ist ) {
ost - > inputs_done = 1 ;
return 0 ;
}
} else {
av_assert0 ( ost - > source_index > = 0 ) ;
ist = input_streams [ ost - > source_index ] ;