[PATCH] Implement -af in ffplay.
Stefano Sabatini
stefano.sabatini-lala
Wed Jan 12 00:39:32 CET 2011
Based on a patch by Hemanth.
---
doc/ffplay.texi | 5 +
ffplay.c | 202 +++++++++++++++++++++++++++++++++++++++++++++
libavfilter/af_resample.c | 1 -
3 files changed, 207 insertions(+), 1 deletions(-)
diff --git a/doc/ffplay.texi b/doc/ffplay.texi
index c9c38da..41483c0 100644
--- a/doc/ffplay.texi
+++ b/doc/ffplay.texi
@@ -61,6 +61,11 @@ Loops movie playback <number> times. 0 means forever.
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).
@end table
diff --git a/ffplay.c b/ffplay.c
index a52ec12..7c2b4a2 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -109,6 +109,7 @@ typedef struct VideoPicture {
#if CONFIG_AVFILTER
AVFilterBufferRef *picref;
+ AVFilterBufferRef *samplesref;
#endif
} VideoPicture;
@@ -211,6 +212,8 @@ typedef struct VideoState {
#if CONFIG_AVFILTER
AVFilterContext *out_video_filter; ///<the last filter in the video chain
+ AVFilterContext *out_audio_filter; ///<the last filter in the audio chain
+ AVFilterGraph *agraph;
#endif
float skip_frames;
@@ -220,6 +223,7 @@ typedef struct VideoState {
static void show_help(void);
static int audio_write_get_buf_size(VideoState *is);
+static int audio_decode_frame(VideoState *is, double *pts_ptr);
/* options specified by the user */
static AVInputFormat *file_iformat;
@@ -269,6 +273,7 @@ static int framedrop=1;
static int rdftspeed=20;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
+static char *afilters = NULL;
#endif
/* current context */
@@ -1786,6 +1791,147 @@ static AVFilter input_filter =
{ .name = NULL }},
};
+typedef struct {
+ VideoState *is;
+} AudioFilterPriv;
+
+static int input_audio_init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ AudioFilterPriv *priv = ctx->priv;
+
+ if (!opaque) return AVERROR(EINVAL);
+
+ priv->is = opaque;
+
+ return 0;
+}
+
+static void samples_buf_free(AVFilterBuffer *ptr)
+{
+ av_free(ptr);
+}
+
+static int input_request_audio_frame(AVFilterLink *link)
+{
+ AudioFilterPriv *priv = link->src->priv;
+ AVFilterBufferRef *samplesref;
+ AVCodecContext *avctx;
+ double pts = 0.0;
+ int buf_size = 0;
+ int linesize[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ uint8_t *data[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+ buf_size = audio_decode_frame(priv->is, &pts);
+ avctx = priv->is->audio_st->codec;
+ if (buf_size <= 0)
+ return AVERROR(EINVAL);
+
+ /* FIXME Currently audio streams seem to have no info on planar/packed.
+ * Assuming packed here and passing 0 as last attribute to get_audio_buffer.
+ */
+ if (!avctx->channel_layout)
+ avctx->channel_layout = avcodec_guess_channel_layout(avctx->channels, 0, NULL);
+
+ data [0] = priv->is->audio_buf;
+ linesize[0] = buf_size;
+ samplesref = avfilter_get_audio_buffer_ref_from_arrays(data, linesize, AV_PERM_WRITE,
+ avctx->sample_fmt, buf_size,
+ avctx->channel_layout, 0);
+ samplesref->buf->free = samples_buf_free;
+
+ // AVFilterBufferRef stores pts with timebase 1/samplerate.
+ samplesref->pts = (double) (pts * (double)avctx->sample_rate);
+ samplesref->audio->sample_rate = (int64_t) avctx->sample_rate;
+ avfilter_filter_samples(link, samplesref);
+
+ return 0;
+}
+
+static int input_query_audio_formats(AVFilterContext *ctx)
+{
+ AudioFilterPriv *priv = ctx->priv;
+ enum SampleFormat sample_fmts[] = {
+ priv->is->audio_st->codec->sample_fmt, SAMPLE_FMT_NONE
+ };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(sample_fmts));
+ return 0;
+}
+
+static int input_config_audio_props(AVFilterLink *link)
+{
+ FilterPriv *priv = link->src->priv;
+ AVCodecContext *avctx = priv->is->audio_st->codec;
+
+ if (!avctx->channel_layout)
+ avctx->channel_layout = avcodec_guess_channel_layout(avctx->channels, 0, NULL);
+ link->channel_layout = avctx->channel_layout;
+ link->sample_rate = avctx->sample_rate;
+ return 0;
+}
+
+static AVFilter input_audio_filter =
+{
+ .name = "ffplay_audio_input",
+
+ .priv_size = sizeof(AudioFilterPriv),
+
+ .init = input_audio_init,
+
+ .query_formats = input_query_audio_formats,
+
+ .inputs = (AVFilterPad[]) {{ .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = input_request_audio_frame,
+ .config_props = input_config_audio_props, },
+ { .name = NULL }},
+};
+
+static void null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { }
+
+static int output_query_audio_formats(AVFilterContext *ctx)
+{
+ enum SampleFormat sample_fmts[] = { SAMPLE_FMT_S16, SAMPLE_FMT_NONE };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(sample_fmts));
+ return 0;
+}
+
+static int get_filtered_audio_samples(AVFilterContext *ctx, VideoState *is, double *pts)
+{
+ AVFilterBufferRef *samplesref;
+ AVCodecContext *avctx = is->audio_st->codec;
+ int ret, size;
+
+ if ((ret = avfilter_request_frame(ctx->inputs[0])))
+ return ret;
+ if (!(samplesref = ctx->inputs[0]->cur_buf))
+ return AVERROR(EINVAL);
+ ctx->inputs[0]->cur_buf = NULL;
+ size = samplesref->audio->size;
+
+ // AVFilterBufferRef stores pts with timebase 1/samplerate.
+ *pts = (double)samplesref->pts/(double)avctx->sample_rate;
+
+ is->audio_buf = samplesref->data[0];
+ avfilter_unref_buffer(samplesref);
+
+ return size;
+}
+
+static AVFilter output_audio_filter = {
+ .name = "ffplay_audio_output",
+
+ .query_formats = output_query_audio_formats,
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_samples = null_filter_samples,
+ .min_perms = AV_PERM_READ, },
+ { .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL }},
+};
#endif /* CONFIG_AVFILTER */
static int video_thread(void *arg)
@@ -2192,7 +2338,11 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
+#if CONFIG_AVFILTER
+ audio_size = get_filtered_audio_samples(is->out_audio_filter, is, &pts);
+#else
audio_size = audio_decode_frame(is, &pts);
+#endif
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = is->audio_buf1;
@@ -2224,6 +2374,10 @@ static int stream_component_open(VideoState *is, int stream_index)
AVCodecContext *avctx;
AVCodec *codec;
SDL_AudioSpec wanted_spec, spec;
+#if CONFIG_AVFILTER
+ AVFilterContext *afilt_src = NULL, *afilt_out = NULL;
+ int ret = AVERROR(EINVAL);
+#endif
if (stream_index < 0 || stream_index >= ic->nb_streams)
return -1;
@@ -2292,6 +2446,43 @@ static int stream_component_open(VideoState *is, int stream_index)
is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
+
+#if CONFIG_AVFILTER
+ is->agraph = avfilter_graph_alloc();
+ if (avfilter_graph_create_filter(&afilt_src, &input_audio_filter, "asrc",
+ NULL, is, is->agraph) < 0)
+ goto the_end;
+ if (avfilter_graph_create_filter(&afilt_out, &output_audio_filter, "aout",
+ NULL, NULL, is->agraph) < 0)
+ goto the_end;
+
+ if (afilters) {
+ AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = afilt_src;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = afilt_out;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse(is->agraph, afilters, inputs, outputs, NULL)) < 0)
+ goto the_end;
+ av_freep(&afilters);
+ } else {
+ if (avfilter_link(afilt_src, 0, afilt_out, 0) < 0) goto the_end;
+ }
+
+ if ((ret = avfilter_graph_config(is->agraph, NULL)) < 0)
+ goto the_end;
+
+ is->out_audio_filter = afilt_out;
+#endif
+
packet_queue_init(&is->audioq);
SDL_PauseAudio(0);
break;
@@ -2315,6 +2506,12 @@ static int stream_component_open(VideoState *is, int stream_index)
break;
}
return 0;
+#if CONFIG_AVFILTER
+the_end:
+ avfilter_graph_free(is->agraph);
+ av_freep(&(is->agraph));
+ return ret;
+#endif
}
static void stream_component_close(VideoState *is, int stream_index)
@@ -2336,6 +2533,10 @@ static void stream_component_close(VideoState *is, int stream_index)
if (is->reformat_ctx)
av_audio_convert_free(is->reformat_ctx);
is->reformat_ctx = NULL;
+#if CONFIG_AVFILTER
+ avfilter_graph_free(is->agraph);
+ av_freep(&(is->agraph));
+#endif
break;
case AVMEDIA_TYPE_VIDEO:
packet_queue_abort(&is->videoq);
@@ -3041,6 +3242,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" },
{ "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c
index 1fe91e5..b54a686 100644
--- a/libavfilter/af_resample.c
+++ b/libavfilter/af_resample.c
@@ -424,7 +424,6 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
resample->in_channel_layout = samplesref->audio->channel_layout;
/* Convert to s16 sample format first, then to desired channel layout and finally to desired sample format */
-
if (samplesref->format == AV_SAMPLE_FMT_S16)
resample->s16_samples_ptr = samplesref;
else
--
1.7.2.3
--i0/AhcQY5QxfSsSZ--
More information about the ffmpeg-devel
mailing list