Note: this example program is affected by this libavfilter bug: https://bugzilla.libav.org/show_bug.cgi?id=560
On Mon, Sep 16, 2013 at 2:42 PM, Andrew Kelley <[email protected]> wrote: > It sets up a filter chain, decodes audio into the buffersrc, > and plays audio from the buffersink using libao. > --- > libavfilter/api-example.c | 321 > ++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 321 insertions(+) > create mode 100644 libavfilter/api-example.c > > diff --git a/libavfilter/api-example.c b/libavfilter/api-example.c > new file mode 100644 > index 0000000..df5073f > --- /dev/null > +++ b/libavfilter/api-example.c > @@ -0,0 +1,321 @@ > +/* > + * copyright (c) 2013 Andrew Kelley > + * > + * This file is part of Libav. > + * > + * Libav is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * Libav is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > 02110-1301 USA > + */ > + > +/** > + * @file > + * libavfilter API use example. > + * > + * @example libavfilter/api-example.c > + * This example will read a file, decode the main audio stream, > + * pass it through a simple filter chain, and then send the samples > + * to the default sound device with libao. > + * > + * The filter chain it uses is: > + * (decoded samples) -> abuffer -> volume -> aformat -> abuffersink -> > (device) > + * > + * abuffer: this provides the endpoint where you can feed the decoded > samples. > + * volume: in this example we hardcode it to 0.90 > + * aformat: this converts the samples to the samplefreq, channel layout, > + * and sample format required by the audio device. > + * abuffersink: this provides the endpoint where you can read the samples > after > + * they have passed through the filter chain. > + */ > + > +#include <libavformat/avformat.h> > +#include <libavfilter/avfilter.h> > +#include <libavfilter/buffersink.h> > +#include <libavfilter/buffersrc.h> > +#include <libavutil/samplefmt.h> > +#include <libavutil/opt.h> > +#include <libavutil/channel_layout.h> > + > +#include <ao/ao.h> > + > +static ao_device *device = NULL; > + > +static char strbuf[512]; > +static AVFilterGraph *filter_graph = NULL; > +static AVFilterContext *abuffer_ctx = NULL; > +static AVFilterContext *volume_ctx = NULL; > +static AVFilterContext *aformat_ctx = NULL; > +static AVFilterContext *abuffersink_ctx = NULL; > + > +static AVFrame *oframe = NULL; > + > +static int init_filter_graph(AVFormatContext *ic, AVStream *audio_st) > +{ > + // create new graph > + filter_graph = avfilter_graph_alloc(); > + if (!filter_graph) { > + av_log(NULL, AV_LOG_ERROR, "unable to create filter graph: out of > memory\n"); > + return -1; > + } > + > + AVFilter *abuffer = avfilter_get_by_name("abuffer"); > + AVFilter *volume = avfilter_get_by_name("volume"); > + AVFilter *aformat = avfilter_get_by_name("aformat"); > + AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); > + > + int err; > + // create abuffer filter > + AVCodecContext *avctx = audio_st->codec; > + AVRational time_base = audio_st->time_base; > + snprintf(strbuf, sizeof(strbuf), > + > "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, > + time_base.num, time_base.den, avctx->sample_rate, > + av_get_sample_fmt_name(avctx->sample_fmt), > + avctx->channel_layout); > + fprintf(stderr, "abuffer: %s\n", strbuf); > + err = avfilter_graph_create_filter(&abuffer_ctx, abuffer, > + NULL, strbuf, NULL, filter_graph); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error initializing abuffer filter\n"); > + return err; > + } > + // create volume filter > + double vol = 0.90; > + snprintf(strbuf, sizeof(strbuf), "volume=%f", vol); > + fprintf(stderr, "volume: %s\n", strbuf); > + err = avfilter_graph_create_filter(&volume_ctx, volume, NULL, > + strbuf, NULL, filter_graph); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error initializing volume filter\n"); > + return err; > + } > + // create aformat filter > + snprintf(strbuf, sizeof(strbuf), > + "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64, > + av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), 44100, > + (uint64_t)AV_CH_LAYOUT_STEREO); > + fprintf(stderr, "aformat: %s\n", strbuf); > + err = avfilter_graph_create_filter(&aformat_ctx, aformat, > + NULL, strbuf, NULL, filter_graph); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "unable to create aformat filter\n"); > + return err; > + } > + // create abuffersink filter > + err = avfilter_graph_create_filter(&abuffersink_ctx, abuffersink, > + NULL, NULL, NULL, filter_graph); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "unable to create aformat filter\n"); > + return err; > + } > + > + // connect inputs and outputs > + if (err >= 0) err = avfilter_link(abuffer_ctx, 0, volume_ctx, 0); > + if (err >= 0) err = avfilter_link(volume_ctx, 0, aformat_ctx, 0); > + if (err >= 0) err = avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error connecting filters\n"); > + return err; > + } > + err = avfilter_graph_config(filter_graph, NULL); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error configuring the filter > graph\n"); > + return err; > + } > + return 0; > +} > + > +static int audio_decode_frame(AVFormatContext *ic, AVStream *audio_st, > + AVPacket *pkt, AVFrame *frame) > +{ > + AVPacket pkt_temp_; > + memset(&pkt_temp_, 0, sizeof(pkt_temp_)); > + AVPacket *pkt_temp = &pkt_temp_; > + > + *pkt_temp = *pkt; > + > + int len1, got_frame; > + int new_packet = 1; > + while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) { > + avcodec_get_frame_defaults(frame); > + new_packet = 0; > + > + len1 = avcodec_decode_audio4(audio_st->codec, frame, &got_frame, > pkt_temp); > + if (len1 < 0) { > + // if error we skip the frame > + pkt_temp->size = 0; > + return -1; > + } > + > + pkt_temp->data += len1; > + pkt_temp->size -= len1; > + > + if (!got_frame) { > + // stop sending empty packets if the decoder is finished > + if (!pkt_temp->data && > + audio_st->codec->codec->capabilities&CODEC_CAP_DELAY) > + { > + return 0; > + } > + continue; > + } > + > + // push the audio data from decoded frame into the filtergraph > + int err = av_buffersrc_write_frame(abuffer_ctx, frame); > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error writing frame to > buffersrc\n"); > + return -1; > + } > + // pull filtered audio from the filtergraph > + for (;;) { > + int err = av_buffersink_get_frame(abuffersink_ctx, oframe); > + if (err == AVERROR_EOF || err == AVERROR(EAGAIN)) > + break; > + if (err < 0) { > + av_log(NULL, AV_LOG_ERROR, "error reading buffer from > buffersink\n"); > + return -1; > + } > + ao_play(device, (void*)oframe->data[0], oframe->linesize[0]); > + } > + return 0; > + } > + return 0; > +} > + > +int main(int argc, char *argv[]) > +{ > + if (argc < 2) { > + fprintf(stderr, "Usage: %s file\n", argv[0]); > + return 1; > + } > + > + > + ao_initialize(); > + avcodec_register_all(); > + av_register_all(); > + avformat_network_init(); > + avfilter_register_all(); > + > + ao_sample_format fmt; > + memset(&fmt, 0, sizeof(fmt)); > + fmt.bits = 16; > + fmt.channels = 2; > + fmt.rate = 44100; > + fmt.byte_format = AO_FMT_NATIVE; > + device = ao_open_live(ao_default_driver_id(), &fmt, NULL); > + if (!device) { > + av_log(NULL, AV_LOG_ERROR, "opening audio device\n"); > + return 1; > + } > + > + AVFormatContext *ic = NULL; > + char *filename = argv[1]; > + if (avformat_open_input(&ic, filename, NULL, NULL) < 0) { > + av_log(NULL, AV_LOG_ERROR, "error opening %s\n", filename); > + return 1; > + } > + > + if (avformat_find_stream_info(ic, NULL) < 0) { > + av_log(NULL, AV_LOG_ERROR, "%s: could not find codec > parameters\n", filename); > + return 1; > + } > + > + // set all streams to discard. in a few lines here we will find the > audio > + // stream and cancel discarding it > + for (int i = 0; i < ic->nb_streams; i++) > + ic->streams[i]->discard = AVDISCARD_ALL; > + > + AVCodec *decoder = NULL; > + int audio_stream_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, > -1, -1, > + &decoder, 0); > + > + if (audio_stream_index < 0) { > + av_log(NULL, AV_LOG_ERROR, "%s: no audio stream found\n", > ic->filename); > + return 1; > + } > + > + if (!decoder) { > + av_log(NULL, AV_LOG_ERROR, "%s: no decoder found\n", > ic->filename); > + return 1; > + } > + > + AVStream *audio_st = ic->streams[audio_stream_index]; > + audio_st->discard = AVDISCARD_DEFAULT; > + > + AVCodecContext *avctx = audio_st->codec; > + > + if (avcodec_open2(avctx, decoder, NULL) < 0) { > + av_log(NULL, AV_LOG_ERROR, "unable to open decoder\n"); > + return 1; > + } > + > + if (!avctx->channel_layout) > + avctx->channel_layout = > av_get_default_channel_layout(avctx->channels); > + if (!avctx->channel_layout) { > + av_log(NULL, AV_LOG_ERROR, "unable to guess channel layout\n"); > + return 1; > + } > + > + if (init_filter_graph(ic, audio_st) < 0) { > + av_log(NULL, AV_LOG_ERROR, "unable to init filter graph\n"); > + return 1; > + } > + > + AVPacket audio_pkt; > + memset(&audio_pkt, 0, sizeof(audio_pkt)); > + AVPacket *pkt = &audio_pkt; > + AVFrame *frame = avcodec_alloc_frame(); > + > + oframe = av_frame_alloc(); > + if (!oframe) { > + av_log(NULL, AV_LOG_ERROR, "error allocating oframe\n"); > + return 1; > + } > + > + int eof = 0; > + for (;;) { > + if (eof) { > + if (avctx->codec->capabilities & CODEC_CAP_DELAY) { > + av_init_packet(pkt); > + pkt->data = NULL; > + pkt->size = 0; > + pkt->stream_index = audio_stream_index; > + if (audio_decode_frame(ic, audio_st, pkt, frame) > 0) { > + // keep flushing > + continue; > + } > + } > + break; > + } > + int err = av_read_frame(ic, pkt); > + if (err < 0) { > + if (err != AVERROR_EOF) > + av_log(NULL, AV_LOG_WARNING, "error reading frames\n"); > + eof = 1; > + continue; > + } > + if (pkt->stream_index != audio_stream_index) { > + av_free_packet(pkt); > + continue; > + } > + audio_decode_frame(ic, audio_st, pkt, frame); > + av_free_packet(pkt); > + } > + > + avformat_network_deinit(); > + ao_close(device); > + ao_shutdown(); > + > + return 0; > +} > + > -- > 1.8.1.2 > > _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
