@ -191,7 +191,11 @@ typedef struct VideoState {
AVPacket audio_pkt_temp ;
AVPacket audio_pkt ;
int audio_pkt_temp_serial ;
int audio_last_serial ;
struct AudioParams audio_src ;
# if CONFIG_AVFILTER
struct AudioParams audio_filter_src ;
# endif
struct AudioParams audio_tgt ;
struct SwrContext * swr_ctx ;
double audio_current_pts ;
@ -253,6 +257,9 @@ typedef struct VideoState {
# if CONFIG_AVFILTER
AVFilterContext * in_video_filter ; // the first filter in the video chain
AVFilterContext * out_video_filter ; // the last filter in the video chain
AVFilterContext * in_audio_filter ; // the first filter in the audio chain
AVFilterContext * out_audio_filter ; // the last filter in the audio chain
AVFilterGraph * agraph ; // audio filter graph
# endif
int last_video_stream , last_audio_stream , last_subtitle_stream ;
@ -309,6 +316,7 @@ static int64_t cursor_last_shown;
static int cursor_hidden = 0 ;
# if CONFIG_AVFILTER
static char * vfilters = NULL ;
static char * afilters = NULL ;
# endif
/* current context */
@ -322,6 +330,26 @@ static AVPacket flush_pkt;
static SDL_Surface * screen ;
static inline
int cmp_audio_fmts ( enum AVSampleFormat fmt1 , int64_t channel_count1 ,
enum AVSampleFormat fmt2 , int64_t channel_count2 )
{
/* If channel count == 1, planar and non-planar formats are the same */
if ( channel_count1 = = 1 & & channel_count2 = = 1 )
return av_get_packed_sample_fmt ( fmt1 ) ! = av_get_packed_sample_fmt ( fmt2 ) ;
else
return channel_count1 ! = channel_count2 | | fmt1 ! = fmt2 ;
}
static inline
int64_t get_valid_channel_layout ( int64_t channel_layout , int channels )
{
if ( channel_layout & & av_get_channel_layout_nb_channels ( channel_layout ) = = channels )
return channel_layout ;
else
return 0 ;
}
static int packet_queue_put ( PacketQueue * q , AVPacket * pkt ) ;
static int packet_queue_put_private ( PacketQueue * q , AVPacket * pkt )
@ -1781,6 +1809,71 @@ fail:
return ret ;
}
static int configure_audio_filters ( VideoState * is , const char * afilters , int force_output_format )
{
static const enum AVSampleFormat sample_fmts [ ] = { AV_SAMPLE_FMT_S16 , PIX_FMT_NONE } ;
int sample_rates [ 2 ] = { 0 , - 1 } ;
int64_t channel_layouts [ 2 ] = { 0 , - 1 } ;
int channels [ 2 ] = { 0 , - 1 } ;
AVFilterContext * filt_asrc = NULL , * filt_asink = NULL ;
char asrc_args [ 256 ] ;
AVABufferSinkParams * asink_params = NULL ;
int ret ;
avfilter_graph_free ( & is - > agraph ) ;
if ( ! ( is - > agraph = avfilter_graph_alloc ( ) ) )
return AVERROR ( ENOMEM ) ;
ret = snprintf ( asrc_args , sizeof ( asrc_args ) ,
" sample_rate=%d:sample_fmt=%s:channels=%d " ,
is - > audio_filter_src . freq , av_get_sample_fmt_name ( is - > audio_filter_src . fmt ) ,
is - > audio_filter_src . channels ) ;
if ( is - > audio_filter_src . channel_layout )
snprintf ( asrc_args + ret , sizeof ( asrc_args ) - ret ,
" :channel_layout=0x% " PRIx64 , is - > audio_filter_src . channel_layout ) ;
ret = avfilter_graph_create_filter ( & filt_asrc ,
avfilter_get_by_name ( " abuffer " ) , " ffplay_abuffer " ,
asrc_args , NULL , is - > agraph ) ;
if ( ret < 0 )
goto end ;
if ( ! ( asink_params = av_abuffersink_params_alloc ( ) ) ) {
ret = AVERROR ( ENOMEM ) ;
goto end ;
}
asink_params - > sample_fmts = sample_fmts ;
asink_params - > all_channel_counts = 1 ;
if ( force_output_format ) {
channel_layouts [ 0 ] = is - > audio_tgt . channel_layout ;
asink_params - > channel_layouts = channel_layouts ;
asink_params - > all_channel_counts = 0 ;
channels [ 0 ] = is - > audio_tgt . channels ;
asink_params - > channel_counts = channels ;
asink_params - > all_channel_counts = 0 ;
sample_rates [ 0 ] = is - > audio_tgt . freq ;
asink_params - > sample_rates = sample_rates ;
}
ret = avfilter_graph_create_filter ( & filt_asink ,
avfilter_get_by_name ( " abuffersink " ) , " ffplay_abuffersink " ,
NULL , asink_params , is - > agraph ) ;
if ( ret < 0 )
goto end ;
if ( ( ret = configure_filtergraph ( is - > agraph , afilters , filt_asrc , filt_asink ) ) < 0 )
goto end ;
is - > in_audio_filter = filt_asrc ;
is - > out_audio_filter = filt_asink ;
end :
av_freep ( & asink_params ) ;
if ( ret < 0 )
avfilter_graph_free ( & is - > agraph ) ;
return ret ;
}
# endif /* CONFIG_AVFILTER */
static int video_thread ( void * arg )
@ -2049,13 +2142,14 @@ static int audio_decode_frame(VideoState *is)
AVPacket * pkt_temp = & is - > audio_pkt_temp ;
AVPacket * pkt = & is - > audio_pkt ;
AVCodecContext * dec = is - > audio_st - > codec ;
int len1 , len2 , data_size , resampled_data_size ;
int len1 , data_size , resampled_data_size ;
int64_t dec_channel_layout ;
int got_frame ;
av_unused double audio_clock0 ;
int new_packet = 0 ;
int flush_complete = 0 ;
int wanted_nb_samples ;
AVRational tb ;
for ( ; ; ) {
/* NOTE: the audio packet can contain several frames */
@ -2063,8 +2157,10 @@ static int audio_decode_frame(VideoState *is)
if ( ! is - > frame ) {
if ( ! ( is - > frame = avcodec_alloc_frame ( ) ) )
return AVERROR ( ENOMEM ) ;
} else
} else {
av_frame_unref ( is - > frame ) ;
avcodec_get_frame_defaults ( is - > frame ) ;
}
if ( is - > audioq . serial ! = is - > audio_pkt_temp_serial )
break ;
@ -2091,6 +2187,55 @@ static int audio_decode_frame(VideoState *is)
flush_complete = 1 ;
continue ;
}
if ( is - > frame - > pts = = AV_NOPTS_VALUE & & pkt_temp - > pts ! = AV_NOPTS_VALUE )
is - > frame - > pts = av_rescale_q ( pkt_temp - > pts , is - > audio_st - > time_base , dec - > time_base ) ;
if ( pkt_temp - > pts ! = AV_NOPTS_VALUE )
pkt_temp - > pts + = ( double ) is - > frame - > nb_samples / is - > frame - > sample_rate / av_q2d ( is - > audio_st - > time_base ) ;
tb = dec - > time_base ;
# if CONFIG_AVFILTER
{
int ret ;
int reconfigure ;
dec_channel_layout = get_valid_channel_layout ( is - > frame - > channel_layout , av_frame_get_channels ( is - > frame ) ) ;
reconfigure =
cmp_audio_fmts ( is - > audio_filter_src . fmt , is - > audio_filter_src . channels ,
is - > frame - > format , av_frame_get_channels ( is - > frame ) ) | |
is - > audio_filter_src . channel_layout ! = dec_channel_layout | |
is - > audio_filter_src . freq ! = is - > frame - > sample_rate | |
is - > audio_pkt_temp_serial ! = is - > audio_last_serial ;
if ( reconfigure ) {
char buf1 [ 1024 ] , buf2 [ 1024 ] ;
av_get_channel_layout_string ( buf1 , sizeof ( buf1 ) , - 1 , is - > audio_filter_src . channel_layout ) ;
av_get_channel_layout_string ( buf2 , sizeof ( buf2 ) , - 1 , dec_channel_layout ) ;
av_log ( NULL , AV_LOG_DEBUG ,
" Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d \n " ,
is - > audio_filter_src . freq , is - > audio_filter_src . channels , av_get_sample_fmt_name ( is - > audio_filter_src . fmt ) , buf1 , is - > audio_last_serial ,
is - > frame - > sample_rate , av_frame_get_channels ( is - > frame ) , av_get_sample_fmt_name ( is - > frame - > format ) , buf2 , is - > audio_pkt_temp_serial ) ;
is - > audio_filter_src . fmt = is - > frame - > format ;
is - > audio_filter_src . channels = av_frame_get_channels ( is - > frame ) ;
is - > audio_filter_src . channel_layout = dec_channel_layout ;
is - > audio_filter_src . freq = is - > frame - > sample_rate ;
is - > audio_last_serial = is - > audio_pkt_temp_serial ;
if ( ( ret = configure_audio_filters ( is , afilters , 1 ) ) < 0 )
return ret ;
}
if ( ( ret = av_buffersrc_add_frame ( is - > in_audio_filter , is - > frame ) ) < 0 )
return ret ;
av_frame_unref ( is - > frame ) ;
if ( ( ret = av_buffersink_get_frame_flags ( is - > out_audio_filter , is - > frame , 0 ) ) < 0 )
return ret ;
tb = is - > out_audio_filter - > inputs [ 0 ] - > time_base ;
}
# endif
data_size = av_samples_get_buffer_size ( NULL , av_frame_get_channels ( is - > frame ) ,
is - > frame - > nb_samples ,
is - > frame - > format , 1 ) ;
@ -2126,6 +2271,7 @@ static int audio_decode_frame(VideoState *is)
uint8_t * * out = & is - > audio_buf1 ;
int out_count = ( int64_t ) wanted_nb_samples * is - > audio_tgt . freq / is - > frame - > sample_rate + 256 ;
int out_size = av_samples_get_buffer_size ( NULL , is - > audio_tgt . channels , out_count , is - > audio_tgt . fmt , 0 ) ;
int len2 ;
if ( wanted_nb_samples ! = is - > frame - > nb_samples ) {
if ( swr_set_compensation ( is - > swr_ctx , ( wanted_nb_samples - is - > frame - > nb_samples ) * is - > audio_tgt . freq / is - > frame - > sample_rate ,
wanted_nb_samples * is - > audio_tgt . freq / is - > frame - > sample_rate ) < 0 ) {
@ -2153,8 +2299,11 @@ static int audio_decode_frame(VideoState *is)
}
audio_clock0 = is - > audio_clock ;
is - > audio_clock + = ( double ) data_size /
( av_frame_get_channels ( is - > frame ) * is - > frame - > sample_rate * av_get_bytes_per_sample ( is - > frame - > format ) ) ;
/* update the audio clock with the pts */
if ( is - > frame - > pts ! = AV_NOPTS_VALUE ) {
is - > audio_clock = is - > frame - > pts * av_q2d ( tb ) + ( double ) is - > frame - > nb_samples / is - > frame - > sample_rate ;
is - > audio_clock_serial = is - > audio_pkt_temp_serial ;
}
# ifdef DEBUG
{
static double last_clock ;
@ -2189,12 +2338,6 @@ static int audio_decode_frame(VideoState *is)
}
* pkt_temp = * pkt ;
/* if update the audio clock with the pts */
if ( pkt - > pts ! = AV_NOPTS_VALUE ) {
is - > audio_clock = av_q2d ( is - > audio_st - > time_base ) * pkt - > pts ;
is - > audio_clock_serial = is - > audio_pkt_temp_serial ;
}
}
}
@ -2302,6 +2445,9 @@ static int stream_component_open(VideoState *is, int stream_index)
const char * forced_codec_name = NULL ;
AVDictionary * opts ;
AVDictionaryEntry * t = NULL ;
int sample_rate , nb_channels ;
int64_t channel_layout ;
int ret ;
if ( stream_index < 0 | | stream_index > = ic - > nb_streams )
return - 1 ;
@ -2344,7 +2490,7 @@ static int stream_component_open(VideoState *is, int stream_index)
opts = filter_codec_opts ( codec_opts , avctx - > codec_id , ic , ic - > streams [ stream_index ] , codec ) ;
if ( ! av_dict_get ( opts , " threads " , NULL , 0 ) )
av_dict_set ( & opts , " threads " , " auto " , 0 ) ;
if ( avctx - > codec_type = = AVMEDIA_TYPE_VIDEO )
if ( avctx - > codec_type = = AVMEDIA_TYPE_VIDEO | | avctx - > codec_type = = AVMEDIA_TYPE_AUDIO )
av_dict_set ( & opts , " refcounted_frames " , " 1 " , 0 ) ;
if ( avcodec_open2 ( avctx , codec , & opts ) < 0 )
return - 1 ;
@ -2353,20 +2499,35 @@ static int stream_component_open(VideoState *is, int stream_index)
return AVERROR_OPTION_NOT_FOUND ;
}
/* prepare audio output */
if ( avctx - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
int audio_hw_buf_size = audio_open ( is , avctx - > channel_layout , avctx - > channels , avctx - > sample_rate , & is - > audio_src ) ;
if ( audio_hw_buf_size < 0 )
return - 1 ;
is - > audio_hw_buf_size = audio_hw_buf_size ;
is - > audio_tgt = is - > audio_src ;
}
ic - > streams [ stream_index ] - > discard = AVDISCARD_DEFAULT ;
switch ( avctx - > codec_type ) {
case AVMEDIA_TYPE_AUDIO :
is - > audio_stream = stream_index ;
is - > audio_st = ic - > streams [ stream_index ] ;
# if CONFIG_AVFILTER
{
AVFilterLink * link ;
is - > audio_filter_src . freq = avctx - > sample_rate ;
is - > audio_filter_src . channels = avctx - > channels ;
is - > audio_filter_src . channel_layout = get_valid_channel_layout ( avctx - > channel_layout , avctx - > channels ) ;
is - > audio_filter_src . fmt = avctx - > sample_fmt ;
if ( ( ret = configure_audio_filters ( is , afilters , 0 ) ) < 0 )
return ret ;
link = is - > out_audio_filter - > inputs [ 0 ] ;
sample_rate = link - > sample_rate ;
nb_channels = link - > channels ;
channel_layout = link - > channel_layout ;
}
# else
sample_rate = avctx - > sample_rate ;
nb_channels = avctx - > channels ;
channel_layout = avctx - > channel_layout ;
# endif
/* prepare audio output */
if ( ( ret = audio_open ( is , channel_layout , nb_channels , sample_rate , & is - > audio_tgt ) ) < 0 )
return ret ;
is - > audio_hw_buf_size = ret ;
is - > audio_src = is - > audio_tgt ;
is - > audio_buf_size = 0 ;
is - > audio_buf_index = 0 ;
@ -2379,6 +2540,10 @@ static int stream_component_open(VideoState *is, int stream_index)
memset ( & is - > audio_pkt , 0 , sizeof ( is - > audio_pkt ) ) ;
memset ( & is - > audio_pkt_temp , 0 , sizeof ( is - > audio_pkt_temp ) ) ;
is - > audio_stream = stream_index ;
is - > audio_st = ic - > streams [ stream_index ] ;
packet_queue_start ( & is - > audioq ) ;
SDL_PauseAudio ( 0 ) ;
break ;
@ -2423,7 +2588,7 @@ static void stream_component_close(VideoState *is, int stream_index)
av_freep ( & is - > audio_buf1 ) ;
is - > audio_buf1_size = 0 ;
is - > audio_buf = NULL ;
avcodec_free_fram e ( & is - > frame ) ;
av_frame_fre e ( & is - > frame ) ;
if ( is - > rdft ) {
av_rdft_end ( is - > rdft ) ;
@ -2431,6 +2596,9 @@ static void stream_component_close(VideoState *is, int stream_index)
is - > rdft = NULL ;
is - > rdft_bits = 0 ;
}
# if CONFIG_AVFILTER
avfilter_graph_free ( & is - > agraph ) ;
# endif
break ;
case AVMEDIA_TYPE_VIDEO :
packet_queue_abort ( & is - > videoq ) ;
@ -2820,6 +2988,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
is - > video_current_pts_drift = is - > audio_current_pts_drift ;
is - > audio_clock_serial = - 1 ;
is - > video_clock_serial = - 1 ;
is - > audio_last_serial = - 1 ;
is - > av_sync_type = av_sync_type ;
is - > read_tid = SDL_CreateThread ( read_thread , is ) ;
if ( ! is - > read_tid ) {
@ -3228,6 +3397,7 @@ static const OptionDef options[] = {
{ " window_title " , OPT_STRING | HAS_ARG , { & window_title } , " set window title " , " window title " } ,
# if CONFIG_AVFILTER
{ " vf " , OPT_STRING | HAS_ARG , { & vfilters } , " set video filters " , " filter_graph " } ,
{ " af " , OPT_STRING | HAS_ARG , { & afilters } , " set audio filters " , " filter_graph " } ,
# endif
{ " rdftspeed " , OPT_INT | HAS_ARG | OPT_AUDIO | OPT_EXPERT , { & rdftspeed } , " rdft speed " , " msecs " } ,
{ " showmode " , HAS_ARG , { . func_arg = opt_show_mode } , " select show mode (0 = video, 1 = waves, 2 = RDFT) " , " mode " } ,