[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