[FFmpeg-devel] [PATCH 9/9] ffplay: add -af option
Stefano Sabatini
stefasab at gmail.com
Fri Jun 22 12:11:23 CEST 2012
---
doc/ffplay.texi | 6 +++
ffplay.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 130 insertions(+), 9 deletions(-)
diff --git a/doc/ffplay.texi b/doc/ffplay.texi
index e2bded7..8ea3b25 100644
--- a/doc/ffplay.texi
+++ b/doc/ffplay.texi
@@ -83,6 +83,12 @@ the input video.
Use the option "-filters" to show all the available filters (including
also sources and sinks).
+ at item -af @var{filter_graph}
+ at var{filter_graph} is a description of the filter graph to apply to
+the input audio.
+Use the option "-filters" to show all the available filters (including
+sources and sinks).
+
@item -i @var{input_file}
Read @var{input_file}.
@end table
diff --git a/ffplay.c b/ffplay.c
index cb234f3..c8663f6 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -110,6 +110,7 @@ typedef struct VideoPicture {
#if CONFIG_AVFILTER
AVFilterBufferRef *picref;
+ AVFilterBufferRef *samplesref;
#endif
} VideoPicture;
@@ -233,6 +234,10 @@ typedef struct VideoState {
AVFilterGraph *graph;
int use_dr1;
FrameBuffer *buffer_pool;
+
+ AVFilterContext *in_audio_filter; ///<the first filter in the audio chain
+ AVFilterContext *out_audio_filter; ///<the last filter in the audio chain
+ AVFilterGraph *agraph;
#endif
int refresh;
@@ -289,6 +294,7 @@ static const char *video_codec_name;
static int rdftspeed = 20;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
+static char *afilters = NULL;
#endif
/* current context */
@@ -1634,6 +1640,65 @@ static int configure_video_filters(VideoState *is, const char *vfilters)
return ret;
}
+static int configure_audio_filters(VideoState *is)
+{
+ static const enum PixelFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, PIX_FMT_NONE };
+ int64_t layouts[] = { 0, PIX_FMT_NONE };
+ AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
+ AVCodecContext *avctx = is->audio_st->codec;
+ char abuffer_args[256];
+ AVABufferSinkParams *abuffersink_params = av_abuffersink_params_alloc();
+ int ret;
+
+ is->agraph = avfilter_graph_alloc();
+
+ if (!avctx->channel_layout)
+ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+ layouts[0] = avctx->channel_layout;
+
+ snprintf(abuffer_args, sizeof(abuffer_args), "sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
+ avctx->sample_rate,
+ av_get_sample_fmt_name(avctx->sample_fmt),
+ avctx->channel_layout);
+ ret = avfilter_graph_create_filter(&filt_asrc,
+ avfilter_get_by_name("abuffer"), "ffplay_abuffer",
+ abuffer_args, NULL, is->agraph);
+ if (ret < 0) goto fail;
+
+ abuffersink_params->sample_fmts = sample_fmts;
+ abuffersink_params->channel_layouts = layouts;
+
+ ret = avfilter_graph_create_filter(&filt_asink,
+ avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
+ NULL, abuffersink_params, is->agraph);
+ if (ret < 0) goto fail;
+
+ if (afilters) {
+ AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
+
+ *inputs = (AVFilterInOut){ av_strdup("out"), filt_asink, 0, NULL };
+ *outputs = (AVFilterInOut){ av_strdup("in" ), filt_asrc, 0, NULL };
+
+ if ((ret = avfilter_graph_parse(is->agraph, afilters, &inputs, &outputs, NULL)) < 0)
+ goto fail;
+ av_freep(&afilters);
+ } else {
+ if ((ret = avfilter_link(filt_asrc, 0, filt_asink, 0)) < 0)
+ goto fail;
+ }
+
+ if ((ret = avfilter_graph_config(is->agraph, NULL)) < 0)
+ goto fail;
+ is->in_audio_filter = filt_asrc;
+ is->out_audio_filter = filt_asink;
+ return 0;
+
+fail:
+ avfilter_graph_free(&is->agraph);
+ return ret;
+}
+
#endif /* CONFIG_AVFILTER */
static int video_thread(void *arg)
@@ -2058,6 +2123,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
VideoState *is = opaque;
int audio_size, len1;
+ AVFilterBufferRef av_unused *samplesref;
int bytes_per_sec;
int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, 1, is->audio_tgt.fmt, 1);
double pts;
@@ -2072,6 +2138,25 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
is->audio_buf = is->silence_buf;
is->audio_buf_size = sizeof(is->silence_buf) / frame_size * frame_size;
} else {
+#if CONFIG_AVFILTER
+ const AVCodecContext *avctx = is->audio_st->codec;
+
+ /* inject the buffer into the filter graph
+ * note that AVFilterBufferRef stores pts with timebase 1/samplerate */
+ av_buffersrc_add_frame(is->in_audio_filter, is->frame, 0);
+
+ if (av_buffersink_get_buffer_ref(is->out_audio_filter,
+ &samplesref, 0) < 0)
+ return;
+
+ pts = samplesref->pts / (double)avctx->sample_rate;
+
+ is->audio_buf = samplesref->data[0];
+ audio_size = samplesref->audio->nb_samples *
+ av_get_channel_layout_nb_channels(samplesref->audio->channel_layout) *
+ av_get_bytes_per_sample(samplesref->format);
+#endif
+
if (is->show_mode != SHOW_MODE_VIDEO)
update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
is->audio_buf_size = audio_size;
@@ -2155,6 +2240,10 @@ static int stream_component_open(VideoState *is, int stream_index)
AVCodec *codec;
AVDictionary *opts;
AVDictionaryEntry *t = NULL;
+ int av_unused ret;
+ int sample_rate, nb_channels;
+ int64_t channel_layout;
+ int audio_hw_buf_size;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return -1;
@@ -2199,15 +2288,6 @@ 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:
@@ -2225,6 +2305,37 @@ 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));
+
+
+ if (avctx->sample_rate <= 0 || avctx->channels <= 0){
+ fprintf(stderr, "Invalid sample rate or channel count\n");
+ return AVERROR(EINVAL);
+ }
+
+#if CONFIG_AVFILTER
+ if ((ret = configure_audio_filters(is)) < 0)
+ return ret;
+#endif
+
+ if (CONFIG_AVFILTER &&
+ is->out_audio_filter && is->out_audio_filter->inputs[0]) {
+ AVFilterLink *link = is->out_audio_filter->inputs[0];
+ sample_rate = link->sample_rate;
+ nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ channel_layout = link->channel_layout;
+ } else {
+ sample_rate = avctx->sample_rate;
+ nb_channels = avctx->channels;
+ channel_layout = avctx->channel_layout;
+ }
+
+ /* prepare audio output */
+ audio_hw_buf_size = audio_open(is, channel_layout, nb_channels, 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;
+
packet_queue_start(&is->audioq);
SDL_PauseAudio(0);
break;
@@ -2277,6 +2388,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);
@@ -3002,6 +3116,7 @@ static const OptionDef options[] = {
{ "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" },
#if CONFIG_AVFILTER
{ "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
+ { "af", OPT_STRING | HAS_ARG, {(void*)&afilters}, "audio filters", "filter list" },
#endif
{ "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { (void*)&rdftspeed }, "rdft speed", "msecs" },
{ "showmode", HAS_ARG, {(void*)opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
--
1.7.5.4
More information about the ffmpeg-devel
mailing list