ffmpeg changes to call lavfi audio framework. It works but is a
temporary way to test the other audio filters. Couple if issues with this:
1. Right now, asrc and ffmpeg.c copy any incoming audio frames and thewn
copy them back out. To avoid the two memcpy calls. is it ok to implement
interfaces to avoid this? Please let me know.
I was thinking of defining alternative get_video_buffer and
unref_samples to pass in a buffer pointer alone and use this as input
parameter. Comments?
Regards,
---
ffmpeg.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 177 insertions(+), 5 deletions(-)
diff --git a/ffmpeg.c b/ffmpeg.c
index b0722a4..3814476 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -48,6 +48,7 @@
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/graphparser.h"
# include "libavfilter/vsrc_buffer.h"
+# include "libavfilter/asrc_buffer.h"
#endif
#if HAVE_SYS_RESOURCE_H
@@ -151,7 +152,9 @@ static int loop_output = AVFMT_NOOUTPUTLOOP;
static int qp_hist = 0;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
+static char *afilters = NULL;
AVFilterGraph *graph = NULL;
+AVFilterGraph *agraph = NULL;
#endif
static int intra_only = 0;
@@ -310,6 +313,9 @@ typedef struct AVInputStream {
AVFrame *filter_frame;
int has_filter_frame;
AVFilterPicRef *picref;
+ AVFilterContext *out_audio_filter;
+ AVFilterContext *input_audio_filter;
+ AVFilterSamplesRef *samplesref;
#endif
} AVInputStream;
@@ -396,6 +402,72 @@ static AVFilter output_filter =
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};
+typedef struct {
+ int sample_fmt;
+} AFilterOutPriv;
+
+
+static int audio_output_init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ AFilterOutPriv *priv = ctx->priv;
+
+ if(!opaque) return AVERROR(EINVAL);
+
+ priv->sample_fmt = *((int *)opaque);
+
+ return 0;
+}
+
+static void output_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref)
+{
+}
+
+static int audio_output_query_formats(AVFilterContext *ctx)
+{
+ AFilterOutPriv *priv = ctx->priv;
+ enum SampleFormat sample_fmts[] = { priv->sample_fmt, SAMPLE_FMT_NONE };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(sample_fmts));
+ return 0;
+}
+
+static int get_filtered_audio_samples(AVFilterContext *ctx,
+ AVFilterSamplesRef **samplesref, uint8_t *samples2,
+ uint64_t *pts)
+{
+ AVFilterSamplesRef *samples;
+
+ if(avfilter_request_frame(ctx->inputs[0]))
+ return -1;
+ if(!(samples = ctx->inputs[0]->cur_samples))
+ return -1;
+ *samplesref = samples;
+ ctx->inputs[0]->cur_samples = NULL;
+
+ *pts = samples->pts;
+
+ memcpy(samples2, samples->data[0], samples->size);
+
+ return samples->size;
+}
+
+static AVFilter output_audio_filter =
+{
+ .name = "ffmpeg_audio_output",
+
+ .priv_size = sizeof(AFilterOutPriv),
+ .init = audio_output_init,
+
+ .query_formats = audio_output_query_formats,
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_samples = output_filter_samples,
+ .min_perms = AV_PERM_READ, },
+ { .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL }},
+};
+
static int configure_filters(AVInputStream *ist, AVOutputStream *ost)
{
AVFilterContext *last_filter, *filter;
@@ -495,6 +567,64 @@ static int configure_filters(AVInputStream *ist, AVOutputStream *ost)
return 0;
}
+
+static int configure_audio_filters(AVInputStream *ist, AVOutputStream *ost)
+{
+ AVFilterContext *last_filter;
+ char args[10];
+ int ret = AVERROR(EINVAL);
+
+ agraph = av_mallocz(sizeof(AVFilterGraph));
+
+ if (!(ist->input_audio_filter = avfilter_open(avfilter_get_by_name("abuffer"), "asrc")))
+ return AVERROR(EINVAL);
+ if (!(ist->out_audio_filter = avfilter_open(&output_audio_filter, "aout")))
+ return AVERROR(EINVAL);
+
+ snprintf(args, 10, "%d", ist->st->codec->sample_fmt);
+ if ((ret = avfilter_init_filter(ist->input_audio_filter, args, NULL)) < 0)
+ return ret;
+ if ((ret = avfilter_init_filter(ist->out_audio_filter, NULL, &ost->st->codec->sample_fmt)) < 0)
+ return ret;
+
+ /* add input and output filters to the overall graph */
+ avfilter_graph_add_filter(agraph, ist->input_audio_filter);
+ avfilter_graph_add_filter(agraph, ist->out_audio_filter);
+
+ last_filter = ist->input_audio_filter;
+
+ if (afilters) {
+ AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+
+ outputs->name = av_strdup("in");
+ outputs->filter = last_filter;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter = ist->out_audio_filter;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse(agraph, afilters, inputs, outputs, NULL)) < 0)
+ return ret;
+ av_freep(&afilters);
+ } else {
+ if ((ret = avfilter_link(last_filter, 0, ist->out_audio_filter, 0)) < 0)
+ return ret;
+ }
+
+ /* configure all the filter links */
+ if ((ret = avfilter_graph_check_validity(agraph, NULL)) < 0)
+ return ret;
+ if ((ret = avfilter_graph_config_formats(agraph, NULL)) < 0)
+ return ret;
+ if ((ret = avfilter_graph_config_links(agraph, NULL)) < 0)
+ return ret;
+
+ return 0;
+}
#endif /* CONFIG_AVFILTER */
static void term_exit(void)
@@ -1658,6 +1788,17 @@ static int output_packet(AVInputStream *ist, int ist_index,
ist->pts,
ist->st->codec->sample_aspect_ratio);
}
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && ist->input_audio_filter) {
+ // add it to be filtered
+ // right now, we have no information about whether buffer is planar, assume packed
+ if (!ist->st->codec->channel_layout) {
+ ist->st->codec->channel_layout = avcodec_guess_channel_layout(ist->st->codec->channels,
+ 0, NULL);
+ }
+ av_asrc_buffer_add_frame(ist->input_audio_filter, decoded_data_buf, decoded_data_size,
+ ist->st->codec->channel_layout, ist->st->codec->sample_fmt,
+ 0, ist->pts);
+ }
#endif
// preprocess audio (volume)
@@ -1682,8 +1823,13 @@ static int output_packet(AVInputStream *ist, int ist_index,
usleep(pts - now);
}
#if CONFIG_AVFILTER
- frame_available = ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
- !ist->out_video_filter || avfilter_poll_frame(ist->out_video_filter->inputs[0]);
+ frame_available = 1;
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ frame_available = !ist->out_video_filter ||
+ avfilter_poll_frame(ist->out_video_filter->inputs[0]);
+ else if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ frame_available = !ist->out_audio_filter ||
+ avfilter_poll_frame(ist->out_audio_filter->inputs[0]);
#endif
/* if output time reached then transcode raw format,
encode packets and output them */
@@ -1692,6 +1838,9 @@ static int output_packet(AVInputStream *ist, int ist_index,
while (frame_available) {
if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && ist->out_video_filter)
get_filtered_video_pic(ist->out_video_filter, &ist->picref, &picture, &ist->pts);
+ else if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && ist->out_audio_filter) {
+ decoded_data_size = get_filtered_audio_samples(ist->out_audio_filter, &ist->samplesref, decoded_data_buf, &ist->pts);
+ }
#endif
for(i=0;i<nb_ostreams;i++) {
int frame_size;
@@ -1707,6 +1856,11 @@ static int output_packet(AVInputStream *ist, int ist_index,
assert(ist->decoding_needed);
switch(ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
+#if CONFIG_AVFILTER
+ ist->st->codec->channel_layout = ist->samplesref->channel_layout;
+ ist->st->codec->channels =
+ avcodec_channel_layout_num_channels(ist->samplesref->channel_layout);
+#endif
do_audio_out(os, ost, ist, decoded_data_buf, decoded_data_size);
break;
case AVMEDIA_TYPE_VIDEO:
@@ -1782,14 +1936,21 @@ static int output_packet(AVInputStream *ist, int ist_index,
}
}
#if CONFIG_AVFILTER
- frame_available = (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
- ist->out_video_filter && avfilter_poll_frame(ist->out_video_filter->inputs[0]);
+ frame_available = 0;
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ frame_available = ist->out_video_filter &&
+ avfilter_poll_frame(ist->out_video_filter->inputs[0]);
+ else if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ frame_available = ist->out_audio_filter &&
+ avfilter_poll_frame(ist->out_audio_filter->inputs[0]);
#endif
}
#if CONFIG_AVFILTER
if(ist->picref)
avfilter_unref_pic(ist->picref);
+ if(ist->samplesref)
+ avfilter_unref_samples(ist->samplesref);
}
#endif
av_free(buffer_to_free);
@@ -2215,6 +2376,12 @@ static int av_transcode(AVFormatContext **output_files,
icodec->request_channels = codec->channels;
ist->decoding_needed = 1;
ost->encoding_needed = 1;
+#if CONFIG_AVFILTER
+ if (configure_audio_filters(ist, ost)) {
+ fprintf(stderr, "Error opening audio filters!\n");
+ exit(1);
+ }
+#endif
break;
case AVMEDIA_TYPE_VIDEO:
if (ost->st->codec->pix_fmt == PIX_FMT_NONE) {
@@ -2268,7 +2435,7 @@ static int av_transcode(AVFormatContext **output_files,
#if CONFIG_AVFILTER
if (configure_filters(ist, ost)) {
- fprintf(stderr, "Error opening filters!\n");
+ fprintf(stderr, "Error opening video filters!\n");
exit(1);
}
#endif
@@ -2662,6 +2829,10 @@ static int av_transcode(AVFormatContext **output_files,
avfilter_graph_destroy(graph);
av_freep(&graph);
}
+ if (agraph) {
+ avfilter_graph_destroy(agraph);
+ av_freep(&agraph);
+ }
#endif
/* finished ! */
@@ -4220,6 +4391,7 @@ static const OptionDef options[] = {
{ "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" },
#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
{ "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" },
{ "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" },
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc