[FFmpeg-devel] [PATCH] api-example for libavfilter

Michael Niedermayer michaelni
Sat Dec 11 14:03:02 CET 2010


On Fri, Dec 10, 2010 at 07:11:05PM +0100, Nicolas George wrote:
> Le nonidi 19 frimaire, an CCXIX, Tomas H?rdin a ?crit?:
> > I would also like to see a more pure libavfilter example that doesn't
> > depend on libavformat and libavcodec. However, I don't think it has to
> > be mutually exclusive to an example that does use them like this one.
> > 
> > In short: this example seems fair. IMO we could use another one that
> > only does filtering on generated data.
> 
> Thanks for your advice. Here is an updated proposal:
> 
> - Renamed to "decode_filter-example.c".
> 
> - Removed useless "string.h" include.
> 
> - Closed and freed everything.
> 
> On the other hand, I stick to using nullsink to terminate the chain, unless
> someone who knows tells me that there is another preferred method.
> 
> I keep in mind submitting a trivial ASCII-art sink for sometime soon.
> 
> Regards,
> 
> -- 
>   Nicolas George

>  Makefile                |    4 
>  decode_filter-example.c |  232 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 236 insertions(+)
> 53ae1c5a6e66e764314633428f85b5629e735b18  ffmpeg-vf-test-20101210-1903-01-vf-test.diff
>  libavfilter/Makefile                |    4 +
>  libavfilter/decode_filter-example.c |  232 +++++++++++++++++++++++++++++++++++

what follows is more a review of the APIs than the api example, as i think its
a great oppertunity to review the APIs based on the example ...



>  2 files changed, 236 insertions(+), 0 deletions(-)
> 
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index aece3ab..b5d9176 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -56,4 +56,8 @@ OBJS-$(CONFIG_NULLSINK_FILTER)               += vsink_nullsink.o
>  
>  DIRS = x86
>  
> +EXAMPLES  = api
> +
>  include $(SUBDIR)../subdir.mak
> +
> +$(SUBDIR)decode_filter-example$(EXESUF): ELIBS = -lavformat -lavcodec -lavcore -lavutil $(FFEXTRALIBS)
> diff --git a/libavfilter/decode_filter-example.c b/libavfilter/decode_filter-example.c
> new file mode 100644
> index 0000000..526111a
> --- /dev/null
> +++ b/libavfilter/decode_filter-example.c
> @@ -0,0 +1,232 @@
> +/*
> + * API example for libavfilter
> + * Copyright (c) 2010 Nicolas George
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg 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.
> + *
> + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#define _XOPEN_SOURCE 600 /* for usleep */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <libavformat/avformat.h>
> +#include <libavcodec/avcodec.h>
> +#include <libavfilter/avfiltergraph.h>
> +#include <libavfilter/vsrc_buffer.h>
> +
> +const char *filter_descr = "scale=78:24,format=gray";
> +
> +static AVFormatContext *avf;
> +static AVCodecContext *video_dec;
> +AVFilterContext *video_in_filter;
> +AVFilterContext *video_out_filter;
> +AVFilterGraph *filter_graph;
> +static int video_stream = -1;
> +static int64_t last_pts = AV_NOPTS_VALUE;
> +
> +static void fatal_libav_error(const char *tag, int r)
> +{
> +    char buf[1024];
> +
> +    av_strerror(r, buf, sizeof(buf));
> +    fprintf(stderr, "%s: %s\n", tag, buf);
> +    exit(1);
> +}
> +
> +static void open_input_file(const char *filename)
> +{
> +    int r, i;
> +    AVCodec *codec;
> +    AVCodecContext *avc;
> +

> +    avcodec_register_all();
> +    av_register_all();

already called in main()


> +    r = av_open_input_file(&avf, filename, NULL, 0, NULL);
> +    if (r < 0)
> +        fatal_libav_error("av_open_input_file", r);
> +    r = av_find_stream_info(avf);
> +    if (r < 0)
> +        fatal_libav_error("av_find_stream_info", r);
> +

> +    /* Find a video stream */
> +    for (i = 0; i < (int)avf->nb_streams; i++) {
> +        avc = avf->streams[i]->codec;
> +        if (!video_dec && avc->codec_type == CODEC_TYPE_VIDEO) {
> +            video_dec = avc;
> +            video_stream = i;
> +        }
> +    }

We have code in ffplay.c that selects the "best" stream of a kind
(see surrounding code when you grep for st_best_packet_count)
this should be moved into the public API of libavformat and used here
and from ffplay
Selecting the first stream leads to known bugs (dont remember the issue #)



> +    /* Init the video decoder */
> +    if (video_dec) {
> +        codec = avcodec_find_decoder(video_dec->codec_id);
> +        if (!codec) {
> +            fprintf(stderr, "Unable to find video decoder\n");
> +            exit(1);
> +        }

> +        r = avcodec_open(video_dec, codec);

make libavcodec call avcodec_find_decoder() when codec=NULL and this becomes
simpler


> +        if (r < 0)
> +            fatal_libav_error("avcodec_open", r);
> +    }
> +}
> +
> +static void init_filters(const char *filters)
> +{
> +    char args[256];
> +    int r;
> +    AVFilter *vf_buffer = avfilter_get_by_name("buffer");
> +    AVFilter *vf_nullsink = avfilter_get_by_name("nullsink");
> +    AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
> +    AVFilterInOut *inputs  = av_malloc(sizeof(AVFilterInOut));
> +
> +
> +    filter_graph = avfilter_graph_alloc();
> +
> +    /* Buffer video source: the decoded frames from the codec will be
> +     * inserted here. */
> +    snprintf(args, sizeof(args), "%d:%d:%d:%d:%d", video_dec->width,
> +             video_dec->height, video_dec->pix_fmt,
> +             video_dec->time_base.num, video_dec->time_base.den);

> +    r = avfilter_graph_create_filter(&video_in_filter, vf_buffer, "src", args,
> +                                     NULL, filter_graph);
> +    if (r < 0)
> +        fatal_libav_error("avfilter_graph_create_filter: buffer", r);
> +
> +    /* Null video sink: to terminate the filter chain. */
> +    r = avfilter_graph_create_filter(&video_out_filter, vf_nullsink, "out",
> +                                     NULL, NULL, filter_graph);
> +    if (r < 0)
> +        fatal_libav_error("avfilter_graph_create_filter: nullsink", r);
> +

> +    /* Endpoints for the filter graph. */
> +    outputs->name       = av_strdup("in");
> +    outputs->filter_ctx = video_in_filter;
> +    outputs->pad_idx    = 0;
> +    outputs->next       = NULL;
> +    inputs->name       = av_strdup("out");
> +    inputs->filter_ctx = video_out_filter;
> +    inputs->pad_idx    = 0;
> +    inputs->next       = NULL;

These 2 blocks seems somewhat redundant
the avfilter_graph_create_filter() could do that already somehow, maybe if
we move the 2 AVFilterInOut into filter_graph


> +    r = avfilter_graph_parse(filter_graph, filters, inputs, outputs, NULL);
> +    if (r < 0)
> +        fatal_libav_error("avfilter_graph_parse", r);
> +
> +    r = avfilter_graph_config(filter_graph, NULL);
> +    if (r < 0)
> +        fatal_libav_error("avfilter_graph_config", r);
> +}
> +
> +static void display_frame(AVFilterLink *link)
> +{
> +    AVFilterBufferRef *ob;
> +    int x, y;
> +    uint8_t *p0, *p;
> +    int64_t delay;
> +
> +    ob = link->cur_buf;
> +    if (ob->pts != AV_NOPTS_VALUE) {
> +        if (last_pts != AV_NOPTS_VALUE) {
> +            /* sleep roughly the right amount of time;
> +             * usleep is in microseconds, just like AV_TIME_BASE. */
> +            delay = av_rescale_q(ob->pts - last_pts,
> +                                 link->time_base,
> +                                 AV_TIME_BASE_Q);
> +            if (delay > 0 && delay < 1000000)
> +                usleep(delay);
> +        }
> +        last_pts = ob->pts;
> +    }
> +    /* ob->data, ob->linesize and ob->pts could be copied to an AVFrame
> +     * structure. */
> +    /* Trivial ASCII grayscale display. */

> +    p0 = ob->data[0];
> +    puts("\033c");
> +    for (y = 0; y < link->h; y++) {
> +        p = p0;
> +        for (x = 0; x < link->w; x++)
> +            putchar(" .-+#"[*(p++) / 52]);

p[x] would avoid the temp p vs p0 varible


> +        putchar('\n');
> +        p0 += ob->linesize[0];
> +    }
> +    fflush(stdout);
> +    avfilter_unref_buffer(ob);
> +}
> +
> +static void got_video_frame(AVFrame *frame)
> +{
> +    int r;
> +    AVFilterLink *out = video_out_filter->inputs[0];
> +
> +    av_vsrc_buffer_add_frame(video_in_filter, frame, frame->pts,
> +                             video_dec->sample_aspect_ratio);
> +    while (avfilter_poll_frame(out)) {
> +        r = avfilter_request_frame(out);
> +        if (r < 0)
> +            fatal_libav_error("avfilter_request_frame", r);
> +        if (!out->cur_buf)
> +            fatal_libav_error("avfilter_request_frame", AVERROR(ENOENT));
> +        display_frame(out);
> +    }
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    int r;
> +    AVPacket packet;
> +    AVFrame frame;
> +    int got_frame;
> +
> +    if (argc != 2) {
> +        fprintf(stderr, "Usage: api_example file\n");
> +        exit(1);
> +    }

> +    avcodec_register_all();

unneeded


> +    avfilter_register_all();
> +    av_register_all();
> +    open_input_file(argv[1]);
> +    init_filters(filter_descr);
> +    /* Read all packets. */
> +    while (1) {
    
> +        r = av_read_frame(avf, &packet);
> +        if (r < 0)
> +            break;

EAGAIN handling is missing

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The real ebay dictionary, page 2
"100% positive feedback" - "All either got their money back or didnt complain"
"Best seller ever, very honest" - "Seller refunded buyer after failed scam"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20101211/7d04771c/attachment.pgp>



More information about the ffmpeg-devel mailing list