[FFmpeg-soc] [soc]: r4319 - in afilters: . README TODO allfilters.c avfilter.c avfilter.h avfiltergraph.c avfiltergraph.h checkout.sh defaults.c formats.c graphparser.c graphparser.h parseutils.c parseutils.h
kdub
subversion at mplayerhq.hu
Thu May 28 05:19:13 CEST 2009
Author: kdub
Date: Thu May 28 05:19:12 2009
New Revision: 4319
Log:
initial afilters commit, with build system for initial devwork
Added:
afilters/
afilters/README
afilters/TODO
afilters/allfilters.c
afilters/avfilter.c
afilters/avfilter.h
afilters/avfiltergraph.c
afilters/avfiltergraph.h
afilters/checkout.sh (contents, props changed)
afilters/defaults.c
afilters/formats.c
afilters/graphparser.c
afilters/graphparser.h
afilters/parseutils.c
afilters/parseutils.h
Added: afilters/README
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/README Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,7 @@
+Alright, here's how to get libavfilter up and compiling.
+
+If you've found this README, you've also found checkout.sh.
+* Running that script will check out a fresh ffmpeg from svn, and hardlink the .c and .h files you see here to the ffmpeg/libavfilter/ directory.
+* You can run configure and make as normal, but you'll have to descend to ffmpeg/libavfilter and run make to get libavfilter.a
+
+See the TODO for what works and doesnt work at this point :)
Added: afilters/TODO
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/TODO Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,13 @@
+
+At current, I still need to
+
+Phase 1:
+* Finalize Audio API
+* Keep the filters fast
+* Create method for converting between different PCM formats, and linking the chain together correctly
+
+Phase 2:
+* Write a few filters for the API
+* Integrate libavfilter into the ffmpeg executable
+* Document
+
Added: afilters/allfilters.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/allfilters.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,39 @@
+/*
+ * filter registration
+ * copyright (c) 2008 Vitor Sessak
+ *
+ * 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
+ */
+
+#include "avfilter.h"
+
+
+#define REGISTER_FILTER(X,x,y) { \
+ extern AVFilter avfilter_##y##_##x ; \
+ if(CONFIG_##X##_FILTER ) avfilter_register(&avfilter_##y##_##x ); }
+
+void avfilter_register_all(void)
+{
+ static int initialized;
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+// REGISTER_FILTER (CROP,crop,vf);
+
+}
Added: afilters/avfilter.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/avfilter.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,404 @@
+/*
+ * filter layer
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#include "libavcodec/imgconvert.h"
+#include "avfilter.h"
+
+unsigned avfilter_version(void) {
+ return LIBAVFILTER_VERSION_INT;
+}
+
+/** list of registered filters */
+static struct FilterList
+{
+ AVFilter *filter;
+ struct FilterList *next;
+} *filters = NULL;
+
+/** helper macros to get the in/out pad on the dst/src filter */
+#define link_dpad(link) link->dst-> input_pads[link->dstpad]
+#define link_spad(link) link->src->output_pads[link->srcpad]
+
+AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask)
+{
+ AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef));
+ *ret = *ref;
+ ret->perms &= pmask;
+ ret->pic->refcount ++;
+ return ret;
+}
+
+void avfilter_unref_pic(AVFilterPicRef *ref)
+{
+ if(!(--ref->pic->refcount))
+ ref->pic->free(ref->pic);
+ av_free(ref);
+}
+
+void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+ AVFilterPad **pads, AVFilterLink ***links,
+ AVFilterPad *newpad)
+{
+ unsigned i;
+
+ idx = FFMIN(idx, *count);
+
+ *pads = av_realloc(*pads, sizeof(AVFilterPad) * (*count + 1));
+ *links = av_realloc(*links, sizeof(AVFilterLink*) * (*count + 1));
+ memmove(*pads +idx+1, *pads +idx, sizeof(AVFilterPad) * (*count-idx));
+ memmove(*links+idx+1, *links+idx, sizeof(AVFilterLink*) * (*count-idx));
+ memcpy(*pads+idx, newpad, sizeof(AVFilterPad));
+ (*links)[idx] = NULL;
+
+ (*count) ++;
+ for(i = idx+1; i < *count; i ++)
+ if(*links[i])
+ (*(unsigned *)((uint8_t *) *links[i] + padidx_off)) ++;
+}
+
+int avfilter_link(AVFilterContext *src, unsigned srcpad,
+ AVFilterContext *dst, unsigned dstpad)
+{
+ AVFilterLink *link;
+
+ if(src->output_count <= srcpad || dst->input_count <= dstpad ||
+ src->outputs[srcpad] || dst->inputs[dstpad])
+ return -1;
+
+ src->outputs[srcpad] =
+ dst-> inputs[dstpad] = link = av_mallocz(sizeof(AVFilterLink));
+
+ link->src = src;
+ link->dst = dst;
+ link->srcpad = srcpad;
+ link->dstpad = dstpad;
+ link->format = PIX_FMT_NONE;
+
+ return 0;
+}
+
+int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
+ unsigned in, unsigned out)
+{
+ av_log(link->dst, AV_LOG_INFO, "auto-inserting filter '%s'\n",
+ filt->filter->name);
+
+ link->dst->inputs[link->dstpad] = NULL;
+ if(avfilter_link(filt, out, link->dst, link->dstpad)) {
+ /* failed to link output filter to new filter */
+ link->dst->inputs[link->dstpad] = link;
+ return -1;
+ }
+
+ /* re-hookup the link to the new destination filter we inserted */
+ link->dst = filt;
+ link->dstpad = in;
+ filt->inputs[in] = link;
+
+ /* if any information on supported colorspaces already exists on the
+ * link, we need to preserve that */
+ if(link->out_formats)
+ avfilter_formats_changeref(&link->out_formats,
+ &filt->outputs[out]->out_formats);
+
+ return 0;
+}
+
+int avfilter_config_links(AVFilterContext *filter)
+{
+ int (*config_link)(AVFilterLink *);
+ unsigned i;
+
+ for(i = 0; i < filter->input_count; i ++) {
+ AVFilterLink *link = filter->inputs[i];
+
+ if(!link) continue;
+
+ switch(link->init_state) {
+ case AVLINK_INIT:
+ continue;
+ case AVLINK_STARTINIT:
+ av_log(filter, AV_LOG_INFO, "circular filter chain detected\n");
+ return 0;
+ case AVLINK_UNINIT:
+ link->init_state = AVLINK_STARTINIT;
+
+ if(avfilter_config_links(link->src))
+ return -1;
+
+ if(!(config_link = link_spad(link).config_props))
+ config_link = avfilter_default_config_output_link;
+ if(config_link(link))
+ return -1;
+
+ if((config_link = link_dpad(link).config_props))
+ if(config_link(link))
+ return -1;
+
+ link->init_state = AVLINK_INIT;
+ }
+ }
+
+ return 0;
+}
+
+AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms)
+{
+ AVFilterPicRef *ret = NULL;
+
+ if(link_dpad(link).get_video_buffer)
+ ret = link_dpad(link).get_video_buffer(link, perms);
+
+ if(!ret)
+ ret = avfilter_default_get_video_buffer(link, perms);
+
+ return ret;
+}
+
+int avfilter_request_frame(AVFilterLink *link)
+{
+ if(link_spad(link).request_frame)
+ return link_spad(link).request_frame(link);
+ else if(link->src->inputs[0])
+ return avfilter_request_frame(link->src->inputs[0]);
+ else return -1;
+}
+
+int avfilter_poll_frame(AVFilterLink *link)
+{
+ int i, min=INT_MAX;
+
+ if(link_spad(link).poll_frame)
+ return link_spad(link).poll_frame(link);
+
+ for (i=0; i<link->src->input_count; i++) {
+ if(!link->src->inputs[i])
+ return -1;
+ min = FFMIN(min, avfilter_poll_frame(link->src->inputs[i]));
+ }
+
+ return min;
+}
+
+/* XXX: should we do the duplicating of the picture ref here, instead of
+ * forcing the source filter to do it? */
+void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
+{
+ void (*start_frame)(AVFilterLink *, AVFilterPicRef *);
+ AVFilterPad *dst = &link_dpad(link);
+
+ if(!(start_frame = dst->start_frame))
+ start_frame = avfilter_default_start_frame;
+
+ /* prepare to copy the picture if it has insufficient permissions */
+ if((dst->min_perms & picref->perms) != dst->min_perms ||
+ dst->rej_perms & picref->perms) {
+ /*
+ av_log(link->dst, AV_LOG_INFO,
+ "frame copy needed (have perms %x, need %x, reject %x)\n",
+ picref->perms,
+ link_dpad(link).min_perms, link_dpad(link).rej_perms);
+ */
+
+ link->cur_pic = avfilter_default_get_video_buffer(link, dst->min_perms);
+ link->srcpic = picref;
+ link->cur_pic->pts = link->srcpic->pts;
+ link->cur_pic->pixel_aspect = link->srcpic->pixel_aspect;
+ }
+ else
+ link->cur_pic = picref;
+
+ start_frame(link, link->cur_pic);
+}
+
+void avfilter_end_frame(AVFilterLink *link)
+{
+ void (*end_frame)(AVFilterLink *);
+
+ if(!(end_frame = link_dpad(link).end_frame))
+ end_frame = avfilter_default_end_frame;
+
+ end_frame(link);
+
+ /* unreference the source picture if we're feeding the destination filter
+ * a copied version dues to permission issues */
+ if(link->srcpic) {
+ avfilter_unref_pic(link->srcpic);
+ link->srcpic = NULL;
+ }
+
+}
+
+void avfilter_draw_slice(AVFilterLink *link, int y, int h)
+{
+ uint8_t *src[4], *dst[4];
+ int i, j, hsub, vsub;
+ void (*draw_slice)(AVFilterLink *, int, int);
+
+ /* copy the slice if needed for permission reasons */
+ if(link->srcpic) {
+ avcodec_get_chroma_sub_sample(link->format, &hsub, &vsub);
+
+ for(i = 0; i < 4; i ++) {
+ if(link->srcpic->data[i]) {
+ src[i] = link->srcpic-> data[i] +
+ (y >> (i==0 ? 0 : vsub)) * link->srcpic-> linesize[i];
+ dst[i] = link->cur_pic->data[i] +
+ (y >> (i==0 ? 0 : vsub)) * link->cur_pic->linesize[i];
+ } else
+ src[i] = dst[i] = NULL;
+ }
+
+ for(i = 0; i < 4; i ++) {
+ int planew =
+ ff_get_plane_bytewidth(link->format, link->cur_pic->w, i);
+
+ if(!src[i]) continue;
+
+ for(j = 0; j < h >> (i==0 ? 0 : vsub); j ++) {
+ memcpy(dst[i], src[i], planew);
+ src[i] += link->srcpic ->linesize[i];
+ dst[i] += link->cur_pic->linesize[i];
+ }
+ }
+ }
+
+ if(!(draw_slice = link_dpad(link).draw_slice))
+ draw_slice = avfilter_default_draw_slice;
+ draw_slice(link, y, h);
+}
+
+AVFilter *avfilter_get_by_name(const char *name)
+{
+ struct FilterList *filt;
+
+ for(filt = filters; filt; filt = filt->next)
+ if(!strcmp(filt->filter->name, name))
+ return filt->filter;
+
+ return NULL;
+}
+
+void avfilter_register(AVFilter *filter)
+{
+ struct FilterList *newfilt = av_malloc(sizeof(struct FilterList));
+
+ newfilt->filter = filter;
+ newfilt->next = filters;
+ filters = newfilt;
+}
+
+void avfilter_uninit(void)
+{
+ struct FilterList *tmp;
+
+ for(; filters; filters = tmp) {
+ tmp = filters->next;
+ av_free(filters);
+ }
+}
+
+static int pad_count(const AVFilterPad *pads)
+{
+ int count;
+
+ for(count = 0; pads->name; count ++) pads ++;
+ return count;
+}
+
+static const char *filter_name(void *p)
+{
+ AVFilterContext *filter = p;
+ return filter->filter->name;
+}
+
+static const AVClass avfilter_class = {
+ "AVFilter",
+ filter_name
+};
+
+AVFilterContext *avfilter_open(AVFilter *filter, const char *inst_name)
+{
+ AVFilterContext *ret;
+
+ if (!filter)
+ return 0;
+
+ ret = av_mallocz(sizeof(AVFilterContext));
+
+ ret->av_class = &avfilter_class;
+ ret->filter = filter;
+ ret->name = inst_name ? av_strdup(inst_name) : NULL;
+ ret->priv = av_mallocz(filter->priv_size);
+
+ ret->input_count = pad_count(filter->inputs);
+ if (ret->input_count) {
+ ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count);
+ memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->input_count);
+ ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count);
+ }
+
+ ret->output_count = pad_count(filter->outputs);
+ if (ret->output_count) {
+ ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count);
+ memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->output_count);
+ ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count);
+ }
+
+ return ret;
+}
+
+void avfilter_destroy(AVFilterContext *filter)
+{
+ int i;
+
+ if(filter->filter->uninit)
+ filter->filter->uninit(filter);
+
+ for(i = 0; i < filter->input_count; i ++) {
+ if(filter->inputs[i])
+ filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL;
+ av_freep(&filter->inputs[i]);
+ }
+ for(i = 0; i < filter->output_count; i ++) {
+ if(filter->outputs[i])
+ filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL;
+ av_freep(&filter->outputs[i]);
+ }
+
+ av_freep(&filter->name);
+ av_freep(&filter->input_pads);
+ av_freep(&filter->output_pads);
+ av_freep(&filter->inputs);
+ av_freep(&filter->outputs);
+ av_freep(&filter->priv);
+ av_free(filter);
+}
+
+int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque)
+{
+ int ret=0;
+
+ if(filter->filter->init)
+ ret = filter->filter->init(filter, args, opaque);
+ return ret;
+}
+
Added: afilters/avfilter.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/avfilter.h Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,635 @@
+/*
+ * filter layer
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#ifndef AVFILTER_AVFILTER_H
+#define AVFILTER_AVFILTER_H
+
+#define LIBAVFILTER_VERSION_MAJOR 0
+#define LIBAVFILTER_VERSION_MINOR 5
+#define LIBAVFILTER_VERSION_MICRO 0
+
+#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
+ LIBAVFILTER_VERSION_MINOR, \
+ LIBAVFILTER_VERSION_MICRO)
+#define LIBAVFILTER_VERSION AV_VERSION(LIBAVFILTER_VERSION_MAJOR, \
+ LIBAVFILTER_VERSION_MINOR, \
+ LIBAVFILTER_VERSION_MICRO)
+#define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT
+
+#include <stddef.h>
+#include "libavcodec/avcodec.h"
+
+/**
+ * Returns the LIBAVFILTER_VERSION_INT constant.
+ */
+unsigned avfilter_version(void);
+
+typedef struct AVFilterContext AVFilterContext;
+typedef struct AVFilterLink AVFilterLink;
+typedef struct AVFilterPad AVFilterPad;
+
+/* TODO: look for other flags which may be useful in this structure (interlace
+ * flags, etc)
+ */
+/**
+ * A reference-counted picture data type used by the filter system. Filters
+ * should not store pointers to this structure directly, but instead use the
+ * AVFilterPicRef structure below.
+ */
+typedef struct AVFilterPic
+{
+ uint8_t *data[4]; ///< picture data for each plane
+ int linesize[4]; ///< number of bytes per line
+ enum PixelFormat format; ///< colorspace
+
+ unsigned refcount; ///< number of references to this image
+
+ /** private data to be used by a custom free function */
+ void *priv;
+ /**
+ * A pointer to the function to deallocate this image if the default
+ * function is not sufficient. This could, for example, add the memory
+ * back into a memory pool to be reused later without the overhead of
+ * reallocating it from scratch.
+ */
+ void (*free)(struct AVFilterPic *pic);
+} AVFilterPic;
+
+/**
+ * A reference to an AVFilterPic. Since filters can manipulate the origin of
+ * a picture to, for example, crop image without any memcpy, the picture origin
+ * and dimensions are per-reference properties. Linesize is also useful for
+ * image flipping, frame to field filters, etc, and so is also per-reference.
+ *
+ * TODO: add anything necessary for frame reordering
+ */
+typedef struct AVFilterPicRef
+{
+ AVFilterPic *pic; ///< the picture that this is a reference to
+ uint8_t *data[4]; ///< picture data for each plane
+ int linesize[4]; ///< number of bytes per line
+ int w; ///< image width
+ int h; ///< image height
+
+ int64_t pts; ///< presentation timestamp in units of 1/AV_TIME_BASE
+
+ AVRational pixel_aspect; ///< pixel aspect ratio
+
+ int perms; ///< permissions
+#define AV_PERM_READ 0x01 ///< can read from the buffer
+#define AV_PERM_WRITE 0x02 ///< can write to the buffer
+#define AV_PERM_PRESERVE 0x04 ///< nobody else can overwrite the buffer
+#define AV_PERM_REUSE 0x08 ///< can output the buffer multiple times, with the same contents each time
+#define AV_PERM_REUSE2 0x10 ///< can output the buffer multiple times, modified each time
+} AVFilterPicRef;
+
+/**
+ * Adds a new reference to a picture.
+ * @param ref an existing reference to the picture
+ * @param pmask a bitmask containing the allowable permissions in the new
+ * reference
+ * @return a new reference to the picture with the same properties as the
+ * old, excluding any permissions denied by pmask
+ */
+AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask);
+
+/**
+ * Removes a reference to a picture. If this is the last reference to the
+ * picture, the picture itself is also automatically freed.
+ * @param ref reference to the picture
+ */
+void avfilter_unref_pic(AVFilterPicRef *ref);
+
+/**
+ * A list of supported formats for one end of a filter link. This is used
+ * during the format negotiation process to try to pick the best format to
+ * use to minimize the number of necessary conversions. Each filter gives a
+ * list of the formats supported by each input and output pad. The list
+ * given for each pad need not be distinct - they may be references to the
+ * same list of formats, as is often the case when a filter supports multiple
+ * formats, but will always output the same format as it is given in input.
+ *
+ * In this way, a list of possible input formats and a list of possible
+ * output formats are associated with each link. When a set of formats is
+ * negotiated over a link, the input and output lists are merged to form a
+ * new list containing only the common elements of each list. In the case
+ * that there were no common elements, a format conversion is necessary.
+ * Otherwise, the lists are merged, and all other links which reference
+ * either of the format lists involved in the merge are also affected.
+ *
+ * For example, consider the filter chain:
+ * filter (a) --> (b) filter (b) --> (c) filter
+ *
+ * where the letters in parenthesis indicate a list of formats supported on
+ * the input or output of the link. Suppose the lists are as follows:
+ * (a) = {A, B}
+ * (b) = {A, B, C}
+ * (c) = {B, C}
+ *
+ * First, the first link's lists are merged, yielding:
+ * filter (a) --> (a) filter (a) --> (c) filter
+ *
+ * Notice that format list (b) now refers to the same list as filter list (a).
+ * Next, the lists for the second link are merged, yielding:
+ * filter (a) --> (a) filter (a) --> (a) filter
+ *
+ * where (a) = {B}.
+ *
+ * Unfortunately, when the format lists at the two ends of a link are merged,
+ * we must ensure that all links which reference either pre-merge format list
+ * get updated as well. Therefore, we have the format list structure store a
+ * pointer to each of the pointers to itself.
+ */
+typedef struct AVFilterFormats AVFilterFormats;
+struct AVFilterFormats
+{
+ unsigned format_count; ///< number of formats
+ int *formats; ///< list of formats
+
+ unsigned refcount; ///< number of references to this list
+ AVFilterFormats ***refs; ///< references to this list
+};
+
+/**
+ * Helper function to create a list of supported formats. This is intended
+ * for use in AVFilter->query_formats().
+ * @param len the number of formats supported
+ * @param ... a list of the supported formats
+ * @return the format list, with no existing references
+ */
+AVFilterFormats *avfilter_make_format_list(int len, ...);
+
+/**
+ * Returns a list of all colorspaces supported by FFmpeg.
+ */
+AVFilterFormats *avfilter_all_colorspaces(void);
+
+/**
+ * Returns a format list which contains the intersection of the formats of
+ * a and b. Also, all the references of a, all the references of b, and
+ * a and b themselves will be deallocated.
+ *
+ * If a and b do not share any common formats, neither is modified, and NULL
+ * is returned.
+ */
+AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b);
+
+/**
+ * Adds *ref as a new reference to formats.
+ * That is the pointers will point like in the ascii art below:
+ * ________
+ * |formats |<--------.
+ * | ____ | ____|___________________
+ * | |refs| | | __|_
+ * | |* * | | | | | | AVFilterLink
+ * | |* *--------->|*ref|
+ * | |____| | | |____|
+ * |________| |________________________
+ */
+void avfilter_formats_ref(AVFilterFormats *formats, AVFilterFormats **ref);
+
+/**
+ * Removes *ref as a reference to the format list it currently points to,
+ * deallocates that list if this was the last reference, and sets *ref to NULL.
+ *
+ * Before After
+ * ________ ________ NULL
+ * |formats |<--------. |formats | ^
+ * | ____ | ____|________________ | ____ | ____|________________
+ * | |refs| | | __|_ | |refs| | | __|_
+ * | |* * | | | | | | AVFilterLink | |* * | | | | | | AVFilterLink
+ * | |* *--------->|*ref| | |* | | | |*ref|
+ * | |____| | | |____| | |____| | | |____|
+ * |________| |_____________________ |________| |_____________________
+ */
+void avfilter_formats_unref(AVFilterFormats **ref);
+
+/**
+ *
+ * Before After
+ * ________ ________
+ * |formats |<---------. |formats |<---------.
+ * | ____ | ___|___ | ____ | ___|___
+ * | |refs| | | | | | |refs| | | | | NULL
+ * | |* *--------->|*oldref| | |* *--------->|*newref| ^
+ * | |* * | | |_______| | |* * | | |_______| ___|___
+ * | |____| | | |____| | | | |
+ * |________| |________| |*oldref|
+ * |_______|
+ */
+void avfilter_formats_changeref(AVFilterFormats **oldref,
+ AVFilterFormats **newref);
+
+/**
+ * A filter pad used for either input or output.
+ */
+struct AVFilterPad
+{
+ /**
+ * Pad name. The name is unique among inputs and among outputs, but an
+ * input may have the same name as an output. This may be NULL if this
+ * pad has no need to ever be referenced by name.
+ */
+ const char *name;
+
+ /**
+ * AVFilterPad type. Only video supported now, hopefully someone will
+ * add audio in the future.
+ */
+ enum CodecType type;
+
+ /**
+ * Minimum required permissions on incoming buffers. Any buffer with
+ * insufficient permissions will be automatically copied by the filter
+ * system to a new buffer which provides the needed access permissions.
+ *
+ * Input pads only.
+ */
+ int min_perms;
+
+ /**
+ * Permissions which are not accepted on incoming buffers. Any buffer
+ * which has any of these permissions set will be automatically copied
+ * by the filter system to a new buffer which does not have those
+ * permissions. This can be used to easily disallow buffers with
+ * AV_PERM_REUSE.
+ *
+ * Input pads only.
+ */
+ int rej_perms;
+
+ /**
+ * Callback called before passing the first slice of a new frame. If
+ * NULL, the filter layer will default to storing a reference to the
+ * picture inside the link structure.
+ *
+ * Input video pads only.
+ */
+ void (*start_frame)(AVFilterLink *link, AVFilterPicRef *picref);
+
+ /**
+ * Callback function to get a buffer. If NULL, the filter system will
+ * handle buffer requests.
+ *
+ * Input video pads only.
+ */
+ AVFilterPicRef *(*get_video_buffer)(AVFilterLink *link, int perms);
+
+ /**
+ * Callback called after the slices of a frame are completely sent. If
+ * NULL, the filter layer will default to releasing the reference stored
+ * in the link structure during start_frame().
+ *
+ * Input video pads only.
+ */
+ void (*end_frame)(AVFilterLink *link);
+
+ /**
+ * Slice drawing callback. This is where a filter receives video data
+ * and should do its processing.
+ *
+ * Input video pads only.
+ */
+ void (*draw_slice)(AVFilterLink *link, int y, int height);
+
+ /**
+ * Frame poll callback. This returns the number of immediately available
+ * frames. It should return a positive value if the next request_frame()
+ * is guaranteed to return one frame (with no delay).
+ *
+ * Defaults to just calling the source poll_frame() method.
+ *
+ * Output video pads only.
+ */
+ int (*poll_frame)(AVFilterLink *link);
+
+ /**
+ * Frame request callback. A call to this should result in at least one
+ * frame being output over the given link. This should return zero on
+ * success, and another value on error.
+ *
+ * Output video pads only.
+ */
+ int (*request_frame)(AVFilterLink *link);
+
+ /**
+ * Link configuration callback.
+ *
+ * For output pads, this should set the link properties such as
+ * width/height. This should NOT set the format property - that is
+ * negotiated between filters by the filter system using the
+ * query_formats() callback before this function is called.
+ *
+ * For input pads, this should check the properties of the link, and update
+ * the filter's internal state as necessary.
+ *
+ * For both input and output filters, this should return zero on success,
+ * and another value on error.
+ */
+ int (*config_props)(AVFilterLink *link);
+};
+
+/** default handler for start_frame() for video inputs */
+void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref);
+/** default handler for draw_slice() for video inputs */
+void avfilter_default_draw_slice(AVFilterLink *link, int y, int h);
+/** default handler for end_frame() for video inputs */
+void avfilter_default_end_frame(AVFilterLink *link);
+/** default handler for config_props() for video outputs */
+int avfilter_default_config_output_link(AVFilterLink *link);
+/** default handler for config_props() for video inputs */
+int avfilter_default_config_input_link (AVFilterLink *link);
+/** default handler for get_video_buffer() for video inputs */
+AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link,
+ int perms);
+/**
+ * A helper for query_formats() which sets all links to the same list of
+ * formats. If there are no links hooked to this filter, the list of formats is
+ * freed.
+ */
+void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
+/** Default handler for query_formats() */
+int avfilter_default_query_formats(AVFilterContext *ctx);
+
+/**
+ * Filter definition. This defines the pads a filter contains, and all the
+ * callback functions used to interact with the filter.
+ */
+typedef struct
+{
+ const char *name; ///< filter name
+
+ int priv_size; ///< size of private data to allocate for the filter
+
+ /**
+ * Filter initialization function. Args contains the user-supplied
+ * parameters. FIXME: maybe an AVOption-based system would be better?
+ * opaque is data provided by the code requesting creation of the filter,
+ * and is used to pass data to the filter.
+ */
+ int (*init)(AVFilterContext *ctx, const char *args, void *opaque);
+
+ /**
+ * Filter uninitialization function. Should deallocate any memory held
+ * by the filter, release any picture references, etc. This does not need
+ * to deallocate the AVFilterContext->priv memory itself.
+ */
+ void (*uninit)(AVFilterContext *ctx);
+
+ /**
+ * Query formats supported by the filter and its pads. Should set the
+ * in_formats for links connected to its output pads, and out_formats
+ * for links connected to its input pads.
+ *
+ * Should return zero on success.
+ */
+ int (*query_formats)(AVFilterContext *);
+
+ const AVFilterPad *inputs; ///< NULL terminated list of inputs. NULL if none
+ const AVFilterPad *outputs; ///< NULL terminated list of outputs. NULL if none
+} AVFilter;
+
+/** An instance of a filter */
+struct AVFilterContext
+{
+ const AVClass *av_class; ///< needed for av_log()
+
+ AVFilter *filter; ///< the AVFilter of which this is an instance
+
+ char *name; ///< name of this filter instance
+
+ unsigned input_count; ///< number of input pads
+ AVFilterPad *input_pads; ///< array of input pads
+ AVFilterLink **inputs; ///< array of pointers to input links
+
+ unsigned output_count; ///< number of output pads
+ AVFilterPad *output_pads; ///< array of output pads
+ AVFilterLink **outputs; ///< array of pointers to output links
+
+ void *priv; ///< private data for use by the filter
+};
+
+/**
+ * A link between two filters. This contains pointers to the source and
+ * destination filters between which this link exists, and the indexes of
+ * the pads involved. In addition, this link also contains the parameters
+ * which have been negotiated and agreed upon between the filter, such as
+ * image dimensions, format, etc.
+ */
+struct AVFilterLink
+{
+ AVFilterContext *src; ///< source filter
+ unsigned int srcpad; ///< index of the output pad on the source filter
+
+ AVFilterContext *dst; ///< dest filter
+ unsigned int dstpad; ///< index of the input pad on the dest filter
+
+ /** stage of the initialization of the link properties (dimensions, etc) */
+ enum {
+ AVLINK_UNINIT = 0, ///< not started
+ AVLINK_STARTINIT, ///< started, but incomplete
+ AVLINK_INIT ///< complete
+ } init_state;
+
+ int w; ///< agreed upon image width
+ int h; ///< agreed upon image height
+ enum PixelFormat format; ///< agreed upon image colorspace
+
+ /**
+ * Lists of formats supported by the input and output filters respectively.
+ * These lists are used for negotiating the format to actually be used,
+ * which will be loaded into the format member, above, when chosen.
+ */
+ AVFilterFormats *in_formats;
+ AVFilterFormats *out_formats;
+
+ /**
+ * The picture reference currently being sent across the link by the source
+ * filter. This is used internally by the filter system to allow
+ * automatic copying of pictures which do not have sufficient permissions
+ * for the destination. This should not be accessed directly by the
+ * filters.
+ */
+ AVFilterPicRef *srcpic;
+
+ AVFilterPicRef *cur_pic;
+ AVFilterPicRef *outpic;
+};
+
+/**
+ * Links two filters together.
+ * @param src the source filter
+ * @param srcpad index of the output pad on the source filter
+ * @param dst the destination filter
+ * @param dstpad index of the input pad on the destination filter
+ * @return zero on success
+ */
+int avfilter_link(AVFilterContext *src, unsigned srcpad,
+ AVFilterContext *dst, unsigned dstpad);
+
+/**
+ * Negotiates the colorspace, dimensions, etc of all inputs to a filter.
+ * @param filter the filter to negotiate the properties for its inputs
+ * @return zero on successful negotiation
+ */
+int avfilter_config_links(AVFilterContext *filter);
+
+/**
+ * Requests a picture buffer with a specific set of permissions.
+ * @param link the output link to the filter from which the picture will
+ * be requested
+ * @param perms the required access permissions
+ * @return A reference to the picture. This must be unreferenced with
+ * avfilter_unref_pic when you are finished with it.
+ */
+AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms);
+
+/**
+ * Requests an input frame from the filter at the other end of the link.
+ * @param link the input link
+ * @return zero on success
+ */
+int avfilter_request_frame(AVFilterLink *link);
+
+/**
+ * Polls a frame from the filter chain.
+ * @param link the input link
+ * @return the number of immediately available frames, a negative
+ * number in case of error
+ */
+int avfilter_poll_frame(AVFilterLink *link);
+
+/**
+ * Notifies the next filter of the start of a frame.
+ * @param link the output link the frame will be sent over
+ * @param picref A reference to the frame about to be sent. The data for this
+ * frame need only be valid once draw_slice() is called for that
+ * portion. The receiving filter will free this reference when
+ * it no longer needs it.
+ */
+void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref);
+
+/**
+ * Notifies the next filter that the current frame has finished.
+ * @param link the output link the frame was sent over
+ */
+void avfilter_end_frame(AVFilterLink *link);
+
+/**
+ * Sends a slice to the next filter.
+ * @param link the output link over which the frame is being sent
+ * @param y offset in pixels from the top of the image for this slice
+ * @param h height of this slice in pixels
+ */
+void avfilter_draw_slice(AVFilterLink *link, int y, int h);
+
+/** Initialize the filter system. Registers all builtin filters */
+void avfilter_register_all(void);
+
+/** Uninitialize the filter system. Unregisters all filters */
+void avfilter_uninit(void);
+
+/**
+ * Registers a filter. This is only needed if you plan to use
+ * avfilter_get_by_name later to lookup the AVFilter structure by name. A
+ * filter can still by instantiated with avfilter_open even if it is not
+ * registered.
+ * @param filter the filter to register
+ */
+void avfilter_register(AVFilter *filter);
+
+/**
+ * Gets a filter definition matching the given name.
+ * @param name the filter name to find
+ * @return the filter definition, if any matching one is registered.
+ * NULL if none found.
+ */
+AVFilter *avfilter_get_by_name(const char *name);
+
+/**
+ * Creates a filter instance.
+ * @param filter the filter to create an instance of
+ * @param inst_name Name to give to the new instance. Can be NULL for none.
+ * @return Pointer to the new instance on success. NULL on failure.
+ */
+AVFilterContext *avfilter_open(AVFilter *filter, const char *inst_name);
+
+/**
+ * Initializes a filter.
+ * @param filter the filter to initialize
+ * @param args A string of parameters to use when initializing the filter.
+ * The format and meaning of this string varies by filter.
+ * @param opaque Any extra non-string data needed by the filter. The meaning
+ * of this parameter varies by filter.
+ * @return zero on success
+ */
+int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque);
+
+/**
+ * Destroys a filter.
+ * @param filter the filter to destroy
+ */
+void avfilter_destroy(AVFilterContext *filter);
+
+/**
+ * Inserts a filter in the middle of an existing link.
+ * @param link the link into which the filter should be inserted
+ * @param filt the filter to be inserted
+ * @param in the input pad on the filter to connect
+ * @param out the output pad on the filter to connect
+ * @return zero on success
+ */
+int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
+ unsigned in, unsigned out);
+
+/**
+ * Inserts a new pad.
+ * @param idx Insertion point. Pad is inserted at the end if this point
+ * is beyond the end of the list of pads.
+ * @param count Pointer to the number of pads in the list
+ * @param padidx_off Offset within an AVFilterLink structure to the element
+ * to increment when inserting a new pad causes link
+ * numbering to change
+ * @param pads Pointer to the pointer to the beginning of the list of pads
+ * @param links Pointer to the pointer to the beginning of the list of links
+ * @param newpad The new pad to add. A copy is made when adding.
+ */
+void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+ AVFilterPad **pads, AVFilterLink ***links,
+ AVFilterPad *newpad);
+
+/** Inserts a new input pad for the filter. */
+static inline void avfilter_insert_inpad(AVFilterContext *f, unsigned index,
+ AVFilterPad *p)
+{
+ avfilter_insert_pad(index, &f->input_count, offsetof(AVFilterLink, dstpad),
+ &f->input_pads, &f->inputs, p);
+}
+
+/** Inserts a new output pad for the filter. */
+static inline void avfilter_insert_outpad(AVFilterContext *f, unsigned index,
+ AVFilterPad *p)
+{
+ avfilter_insert_pad(index, &f->output_count, offsetof(AVFilterLink, srcpad),
+ &f->output_pads, &f->outputs, p);
+}
+
+#endif /* AVFILTER_AVFILTER_H */
Added: afilters/avfiltergraph.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/avfiltergraph.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,184 @@
+/*
+ * filter graphs
+ * copyright (c) 2008 Vitor Sessak
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "avfilter.h"
+#include "avfiltergraph.h"
+
+void avfilter_graph_destroy(AVFilterGraph *graph)
+{
+ for(; graph->filter_count > 0; graph->filter_count --)
+ avfilter_destroy(graph->filters[graph->filter_count - 1]);
+ av_freep(&graph->scale_sws_opts);
+ av_freep(&graph->filters);
+}
+
+int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
+{
+ graph->filters = av_realloc(graph->filters,
+ sizeof(AVFilterContext*) * ++graph->filter_count);
+
+ if (!graph->filters)
+ return -1;
+
+ graph->filters[graph->filter_count - 1] = filter;
+
+ return 0;
+}
+
+int avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
+{
+ AVFilterContext *filt;
+ int i, j;
+
+ for (i=0; i < graph->filter_count; i++) {
+ filt = graph->filters[i];
+
+ for (j = 0; j < filt->input_count; j++) {
+ if (!filt->inputs[j] || !filt->inputs[j]->src) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Input pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any source\n",
+ filt->input_pads[j].name, filt->name, filt->filter->name);
+ return -1;
+ }
+ }
+
+ for (j = 0; j < filt->output_count; j++) {
+ if (!filt->outputs[j] || !filt->outputs[j]->dst) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Output pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any destination\n",
+ filt->output_pads[j].name, filt->name, filt->filter->name);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
+{
+ int i;
+
+ for(i = 0; i < graph->filter_count; i ++)
+ if(graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
+ return graph->filters[i];
+
+ return NULL;
+}
+
+static int query_formats(AVFilterGraph *graph)
+{
+ int i, j;
+ int scaler_count = 0;
+ char inst_name[30];
+
+ /* ask all the sub-filters for their supported colorspaces */
+ for(i = 0; i < graph->filter_count; i ++) {
+ if(graph->filters[i]->filter->query_formats)
+ graph->filters[i]->filter->query_formats(graph->filters[i]);
+ else
+ avfilter_default_query_formats(graph->filters[i]);
+ }
+
+ /* go through and merge as many format lists as possible */
+ for(i = 0; i < graph->filter_count; i ++) {
+ AVFilterContext *filter = graph->filters[i];
+
+ for(j = 0; j < filter->input_count; j ++) {
+ AVFilterLink *link = filter->inputs[j];
+ if(link && link->in_formats != link->out_formats) {
+ if(!avfilter_merge_formats(link->in_formats,
+ link->out_formats)) {
+ AVFilterContext *scale;
+ char scale_args[256];
+ /* couldn't merge format lists. auto-insert scale filter */
+ snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d",
+ scaler_count);
+ scale =
+ avfilter_open(avfilter_get_by_name("scale"),inst_name);
+
+ snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts);
+ if(!scale || scale->filter->init(scale, scale_args, NULL) ||
+ avfilter_insert_filter(link, scale, 0, 0)) {
+ avfilter_destroy(scale);
+ return -1;
+ }
+
+ if (avfilter_graph_add_filter(graph, scale) < 0)
+ return -1;
+
+ scale->filter->query_formats(scale);
+ if(!avfilter_merge_formats(scale-> inputs[0]->in_formats,
+ scale-> inputs[0]->out_formats)||
+ !avfilter_merge_formats(scale->outputs[0]->in_formats,
+ scale->outputs[0]->out_formats))
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void pick_format(AVFilterLink *link)
+{
+ if(!link || !link->in_formats)
+ return;
+
+ link->in_formats->format_count = 1;
+ link->format = link->in_formats->formats[0];
+
+ avfilter_formats_unref(&link->in_formats);
+ avfilter_formats_unref(&link->out_formats);
+}
+
+static void pick_formats(AVFilterGraph *graph)
+{
+ int i, j;
+
+ for(i = 0; i < graph->filter_count; i ++) {
+ AVFilterContext *filter = graph->filters[i];
+
+ for(j = 0; j < filter->input_count; j ++)
+ pick_format(filter->inputs[j]);
+ for(j = 0; j < filter->output_count; j ++)
+ pick_format(filter->outputs[j]);
+ }
+}
+
+int avfilter_graph_config_formats(AVFilterGraph *graph)
+{
+ /* find supported formats from sub-filters, and merge along links */
+ if(query_formats(graph))
+ return -1;
+
+ /* Once everything is merged, it's possible that we'll still have
+ * multiple valid colorspace choices. We pick the first one. */
+ pick_formats(graph);
+
+ return 0;
+}
+
Added: afilters/avfiltergraph.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/avfiltergraph.h Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,69 @@
+/*
+ * Filter graphs
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#ifndef AVFILTER_AVFILTERGRAPH_H
+#define AVFILTER_AVFILTERGRAPH_H
+
+#include "avfilter.h"
+
+typedef struct AVFilterGraph {
+ unsigned filter_count;
+ AVFilterContext **filters;
+
+ char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters
+} AVFilterGraph;
+
+/**
+ * Gets a filter instance with name name from graph.
+ *
+ * @return the pointer to the found filter instance or NULL if it
+ * cannot be found.
+ */
+AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name);
+
+/**
+ * Adds an existing filter instance to a filter graph.
+ * @param graph The filter graph
+ * @param filter The filter to be added
+ */
+int avfilter_graph_add_filter(AVFilterGraph *graphctx, AVFilterContext *filter);
+
+/**
+ * Checks for the validity of graph.
+ *
+ * A graph is considered valid if all its input and output pads are
+ * connected.
+ *
+ * @return 0 in case of success, a negative value otherwise
+ */
+int avfilter_graph_check_validity(AVFilterGraph *graphctx, AVClass *log_ctx);
+
+/**
+ * Configures the formats of all the links in the graph.
+ */
+int avfilter_graph_config_formats(AVFilterGraph *graphctx);
+
+/**
+ * Frees a graph and destroys its links.
+ */
+void avfilter_graph_destroy(AVFilterGraph *graph);
+
+#endif /* AVFILTER_AVFILTERGRAPH_H */
Added: afilters/checkout.sh
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/checkout.sh Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,18 @@
+#!/bin/sh
+echo "checking clean ffmpeg svn"
+svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg
+
+echo "deleting source files in libavfilter..."
+rm ffmpeg/libavfilter/*.c ffmpeg/libavfilter/*.h
+
+
+
+echo "linking SoC files where we just deleted the avfilter files from pristine"
+
+for i in `ls *.c *.h`; do
+echo "Linking $i"
+ln $i ffmpeg/libavfilter/$i
+done
+
+echo "linking the SoC avfilter files into SVN..."
+echo "Done, now just do a regular configure and make to build."
Added: afilters/defaults.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/defaults.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,165 @@
+/*
+ * Filter layer - default implementations
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#include "libavcodec/imgconvert.h"
+#include "avfilter.h"
+
+/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */
+void avfilter_default_free_video_buffer(AVFilterPic *pic)
+{
+ av_free(pic->data[0]);
+ av_free(pic);
+}
+
+/* TODO: set the buffer's priv member to a context structure for the whole
+ * filter chain. This will allow for a buffer pool instead of the constant
+ * alloc & free cycle currently implemented. */
+AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms)
+{
+ AVFilterPic *pic = av_mallocz(sizeof(AVFilterPic));
+ AVFilterPicRef *ref = av_mallocz(sizeof(AVFilterPicRef));
+ int i, tempsize;
+ char *buf;
+
+ ref->pic = pic;
+ ref->w = link->w;
+ ref->h = link->h;
+
+ /* make sure the buffer gets read permission or it's useless for output */
+ ref->perms = perms | AV_PERM_READ;
+
+ pic->refcount = 1;
+ pic->format = link->format;
+ pic->free = avfilter_default_free_video_buffer;
+ ff_fill_linesize((AVPicture *)pic, pic->format, ref->w);
+
+ for (i=0; i<4;i++)
+ pic->linesize[i] = FFALIGN(pic->linesize[i], 16);
+
+ tempsize = ff_fill_pointer((AVPicture *)pic, NULL, pic->format, ref->h);
+ buf = av_malloc(tempsize);
+ ff_fill_pointer((AVPicture *)pic, buf, pic->format, ref->h);
+
+ memcpy(ref->data, pic->data, sizeof(pic->data));
+ memcpy(ref->linesize, pic->linesize, sizeof(pic->linesize));
+
+ return ref;
+}
+
+void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
+{
+ AVFilterLink *out = NULL;
+
+ if(link->dst->output_count)
+ out = link->dst->outputs[0];
+
+ if(out) {
+ out->outpic = avfilter_get_video_buffer(out, AV_PERM_WRITE);
+ out->outpic->pts = picref->pts;
+ avfilter_start_frame(out, avfilter_ref_pic(out->outpic, ~0));
+ }
+}
+
+void avfilter_default_draw_slice(AVFilterLink *link, int y, int h)
+{
+ AVFilterLink *out = NULL;
+
+ if(link->dst->output_count)
+ out = link->dst->outputs[0];
+
+ if(out)
+ avfilter_draw_slice(out, y, h);
+}
+
+void avfilter_default_end_frame(AVFilterLink *link)
+{
+ AVFilterLink *out = NULL;
+
+ if(link->dst->output_count)
+ out = link->dst->outputs[0];
+
+ avfilter_unref_pic(link->cur_pic);
+ link->cur_pic = NULL;
+
+ if(out) {
+ if(out->outpic) {
+ avfilter_unref_pic(out->outpic);
+ out->outpic = NULL;
+ }
+ avfilter_end_frame(out);
+ }
+}
+
+/**
+ * default config_link() implementation for output video links to simplify
+ * the implementation of one input one output video filters */
+int avfilter_default_config_output_link(AVFilterLink *link)
+{
+ if(link->src->input_count && link->src->inputs[0]) {
+ link->w = link->src->inputs[0]->w;
+ link->h = link->src->inputs[0]->h;
+ } else {
+ /* XXX: any non-simple filter which would cause this branch to be taken
+ * really should implement its own config_props() for this link. */
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * A helper for query_formats() which sets all links to the same list of
+ * formats. If there are no links hooked to this filter, the list of formats is
+ * freed.
+ *
+ * FIXME: this will need changed for filters with a mix of pad types
+ * (video + audio, etc)
+ */
+void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
+{
+ int count = 0, i;
+
+ for(i = 0; i < ctx->input_count; i ++) {
+ if(ctx->inputs[i]) {
+ avfilter_formats_ref(formats, &ctx->inputs[i]->out_formats);
+ count ++;
+ }
+ }
+ for(i = 0; i < ctx->output_count; i ++) {
+ if(ctx->outputs[i]) {
+ avfilter_formats_ref(formats, &ctx->outputs[i]->in_formats);
+ count ++;
+ }
+ }
+
+ if(!count) {
+ av_free(formats->formats);
+ av_free(formats->refs);
+ av_free(formats);
+ }
+}
+
+int avfilter_default_query_formats(AVFilterContext *ctx)
+{
+ avfilter_set_common_formats(ctx, avfilter_all_colorspaces());
+ return 0;
+}
+
Added: afilters/formats.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/formats.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,148 @@
+/*
+ * Filter layer - format negotiation
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#include "avfilter.h"
+
+/**
+ * Add all refs from a to ret and destroy a.
+ */
+static void merge_ref(AVFilterFormats *ret, AVFilterFormats *a)
+{
+ int i;
+
+ for(i = 0; i < a->refcount; i ++) {
+ ret->refs[ret->refcount] = a->refs[i];
+ *ret->refs[ret->refcount++] = ret;
+ }
+
+ av_free(a->refs);
+ av_free(a->formats);
+ av_free(a);
+}
+
+AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
+{
+ AVFilterFormats *ret;
+ unsigned i, j, k = 0;
+
+ ret = av_mallocz(sizeof(AVFilterFormats));
+
+ /* merge list of formats */
+ ret->formats = av_malloc(sizeof(*ret->formats) * FFMIN(a->format_count,
+ b->format_count));
+ for(i = 0; i < a->format_count; i ++)
+ for(j = 0; j < b->format_count; j ++)
+ if(a->formats[i] == b->formats[j])
+ ret->formats[k++] = a->formats[i];
+
+ ret->format_count = k;
+ /* check that there was at least one common format */
+ if(!ret->format_count) {
+ av_free(ret->formats);
+ av_free(ret);
+ return NULL;
+ }
+
+ ret->refs = av_malloc(sizeof(AVFilterFormats**)*(a->refcount+b->refcount));
+
+ merge_ref(ret, a);
+ merge_ref(ret, b);
+
+ return ret;
+}
+
+AVFilterFormats *avfilter_make_format_list(int len, ...)
+{
+ AVFilterFormats *ret;
+ int i;
+ va_list vl;
+
+ ret = av_mallocz(sizeof(AVFilterFormats));
+ ret->formats = av_malloc(sizeof(*ret->formats) * len);
+ ret->format_count = len;
+
+ va_start(vl, len);
+ for(i = 0; i < len; i ++)
+ ret->formats[i] = va_arg(vl, int);
+ va_end(vl);
+
+ return ret;
+}
+
+AVFilterFormats *avfilter_all_colorspaces(void)
+{
+ AVFilterFormats *ret;
+ int i;
+
+ ret = av_mallocz(sizeof(AVFilterFormats));
+ ret->formats = av_malloc(sizeof(*ret->formats) * PIX_FMT_NB);
+ ret->format_count = PIX_FMT_NB;
+
+ for(i = 0; i < PIX_FMT_NB; i ++)
+ ret->formats[i] = i;
+
+ return ret;
+}
+
+void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
+{
+ *ref = f;
+ f->refs = av_realloc(f->refs, sizeof(AVFilterFormats**) * ++f->refcount);
+ f->refs[f->refcount-1] = ref;
+}
+
+static int find_ref_index(AVFilterFormats **ref)
+{
+ int i;
+ for(i = 0; i < (*ref)->refcount; i ++)
+ if((*ref)->refs[i] == ref)
+ return i;
+ return -1;
+}
+
+void avfilter_formats_unref(AVFilterFormats **ref)
+{
+ int idx = find_ref_index(ref);
+
+ if(idx >= 0)
+ memmove((*ref)->refs + idx, (*ref)->refs + idx+1,
+ sizeof(AVFilterFormats**) * ((*ref)->refcount-idx-1));
+
+ if(!--(*ref)->refcount) {
+ av_free((*ref)->formats);
+ av_free((*ref)->refs);
+ av_free(*ref);
+ }
+ *ref = NULL;
+}
+
+void avfilter_formats_changeref(AVFilterFormats **oldref,
+ AVFilterFormats **newref)
+{
+ int idx = find_ref_index(oldref);
+
+ if(idx >= 0) {
+ (*oldref)->refs[idx] = newref;
+ *newref = *oldref;
+ *oldref = NULL;
+ }
+}
+
Added: afilters/graphparser.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/graphparser.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,357 @@
+/*
+ * filter graph parser
+ * copyright (c) 2008 Vitor Sessak
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "graphparser.h"
+#include "avfilter.h"
+#include "avfiltergraph.h"
+#include "parseutils.h"
+
+#define WHITESPACES " \n\t"
+
+static int link_filter(AVFilterContext *src, int srcpad,
+ AVFilterContext *dst, int dstpad,
+ AVClass *log_ctx)
+{
+ if(avfilter_link(src, srcpad, dst, dstpad)) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "cannot create the link %s:%d -> %s:%d\n",
+ src->filter->name, srcpad, dst->filter->name, dstpad);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse "[linkname]"
+ * @param name a pointer (that need to be free'd after use) to the name between
+ * parenthesis
+ */
+static char *parse_link_name(const char **buf, AVClass *log_ctx)
+{
+ const char *start = *buf;
+ char *name;
+ (*buf)++;
+
+ name = av_get_token(buf, "]");
+
+ if(!name[0]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Bad (empty?) label found in the following: \"%s\".\n", start);
+ goto fail;
+ }
+
+ if(*(*buf)++ != ']') {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Mismatched '[' found in the following: \"%s\".\n", start);
+ fail:
+ av_freep(&name);
+ }
+
+ return name;
+}
+
+static AVFilterContext *create_filter(AVFilterGraph *ctx, int index,
+ const char *filt_name, const char *args,
+ AVClass *log_ctx)
+{
+ AVFilterContext *filt_ctx;
+
+ AVFilter *filt;
+ char inst_name[30];
+
+ snprintf(inst_name, sizeof(inst_name), "Parsed filter %d", index);
+
+ filt = avfilter_get_by_name(filt_name);
+
+ if(!filt) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "no such filter: '%s'\n", filt_name);
+ return NULL;
+ }
+
+ filt_ctx = avfilter_open(filt, inst_name);
+ if(!filt_ctx) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "error creating filter '%s'\n", filt_name);
+ return NULL;
+ }
+
+ if(avfilter_graph_add_filter(ctx, filt_ctx) < 0) {
+ avfilter_destroy(filt_ctx);
+ return NULL;
+ }
+
+ if(avfilter_init_filter(filt_ctx, args, NULL)) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "error initializing filter '%s' with args '%s'\n", filt_name, args);
+ return NULL;
+ }
+
+ return filt_ctx;
+}
+
+/**
+ * Parse "filter=params"
+ */
+static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph,
+ int index, AVClass *log_ctx)
+{
+ char *opts = NULL;
+ char *name = av_get_token(buf, "=,[");
+ AVFilterContext *ret;
+
+ if(**buf == '=') {
+ (*buf)++;
+ opts = av_get_token(buf, "[],\n");
+ }
+
+ ret = create_filter(graph, index, name, opts, log_ctx);
+ av_free(name);
+ av_free(opts);
+ return ret;
+}
+
+static void free_inout(AVFilterInOut *head)
+{
+ while(head) {
+ AVFilterInOut *next = head->next;
+ av_free(head->name);
+ av_free(head);
+ head = next;
+ }
+}
+
+static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
+{
+ AVFilterInOut *ret;
+
+ while(*links && strcmp((*links)->name, label))
+ links = &((*links)->next);
+
+ ret = *links;
+
+ if(ret)
+ *links = ret->next;
+
+ return ret;
+}
+
+static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
+{
+ element->next = *inouts;
+ *inouts = element;
+}
+
+static int link_filter_inouts(AVFilterContext *filter,
+ AVFilterInOut **curr_inputs,
+ AVFilterInOut **open_inputs, AVClass *log_ctx)
+{
+ int pad = filter->input_count;
+
+ while(pad--) {
+ AVFilterInOut *p = *curr_inputs;
+ if(!p) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Not enough inputs specified for the \"%s\" filter.\n",
+ filter->filter->name);
+ return -1;
+ }
+
+ *curr_inputs = (*curr_inputs)->next;
+
+ if(p->filter) {
+ if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx))
+ return -1;
+ av_free(p->name);
+ av_free(p);
+ } else {
+ p->filter = filter;
+ p->pad_idx = pad;
+ insert_inout(open_inputs, p);
+ }
+ }
+
+ if(*curr_inputs) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Too many inputs specified for the \"%s\" filter.\n",
+ filter->filter->name);
+ return -1;
+ }
+
+ pad = filter->output_count;
+ while(pad--) {
+ AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut));
+ currlinkn->filter = filter;
+ currlinkn->pad_idx = pad;
+ insert_inout(curr_inputs, currlinkn);
+ }
+
+ return 0;
+}
+
+static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs,
+ AVFilterInOut **open_outputs, AVClass *log_ctx)
+{
+ int pad = 0;
+
+ while(**buf == '[') {
+ char *name = parse_link_name(buf, log_ctx);
+ AVFilterInOut *match;
+
+ if(!name)
+ return -1;
+
+ /* First check if the label is not in the open_outputs list */
+ match = extract_inout(name, open_outputs);
+
+ if(match) {
+ av_free(name);
+ } else {
+ /* Not in the list, so add it as an input */
+ match = av_mallocz(sizeof(AVFilterInOut));
+ match->name = name;
+ match->pad_idx = pad;
+ }
+
+ insert_inout(curr_inputs, match);
+
+ *buf += strspn(*buf, WHITESPACES);
+ pad++;
+ }
+
+ return pad;
+}
+
+static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
+ AVFilterInOut **open_inputs,
+ AVFilterInOut **open_outputs, AVClass *log_ctx)
+{
+ int pad = 0;
+
+ while(**buf == '[') {
+ char *name = parse_link_name(buf, log_ctx);
+ AVFilterInOut *match;
+
+ AVFilterInOut *input = *curr_inputs;
+ *curr_inputs = (*curr_inputs)->next;
+
+ if(!name)
+ return -1;
+
+ /* First check if the label is not in the open_inputs list */
+ match = extract_inout(name, open_inputs);
+
+ if(match) {
+ if(link_filter(input->filter, input->pad_idx,
+ match->filter, match->pad_idx, log_ctx) < 0)
+ return -1;
+ av_free(match->name);
+ av_free(name);
+ av_free(match);
+ av_free(input);
+ } else {
+ /* Not in the list, so add the first input as a open_output */
+ input->name = name;
+ insert_inout(open_outputs, input);
+ }
+ *buf += strspn(*buf, WHITESPACES);
+ pad++;
+ }
+
+ return pad;
+}
+
+int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut *open_inputs,
+ AVFilterInOut *open_outputs, AVClass *log_ctx)
+{
+ int index = 0;
+ char chr = 0;
+
+ AVFilterInOut *curr_inputs = NULL;
+
+ do {
+ AVFilterContext *filter;
+ filters += strspn(filters, WHITESPACES);
+
+ if(parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx) < 0)
+ goto fail;
+
+ filter = parse_filter(&filters, graph, index, log_ctx);
+
+ if(!filter)
+ goto fail;
+
+ if(filter->input_count == 1 && !curr_inputs && !index) {
+ /* First input can be omitted if it is "[in]" */
+ const char *tmp = "[in]";
+ if(parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx) < 0)
+ goto fail;
+ }
+
+ if(link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx) < 0)
+ goto fail;
+
+ if(parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
+ log_ctx) < 0)
+ goto fail;
+
+ filters += strspn(filters, WHITESPACES);
+ chr = *filters++;
+
+ if(chr == ';' && curr_inputs) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Could not find a output to link when parsing \"%s\"\n",
+ filters - 1);
+ goto fail;
+ }
+ index++;
+ } while(chr == ',' || chr == ';');
+
+ if (chr) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Unable to parse graph description substring: \"%s\"\n",
+ filters - 1);
+ goto fail;
+ }
+
+ if(open_inputs && !strcmp(open_inputs->name, "out") && curr_inputs) {
+ /* Last output can be omitted if it is "[out]" */
+ const char *tmp = "[out]";
+ if(parse_outputs(&tmp, &curr_inputs, &open_inputs,
+ &open_outputs, log_ctx) < 0)
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ avfilter_graph_destroy(graph);
+ free_inout(open_inputs);
+ free_inout(open_outputs);
+ free_inout(curr_inputs);
+ return -1;
+}
Added: afilters/graphparser.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/graphparser.h Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,52 @@
+/*
+ * Filter graph parser
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * 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
+ */
+
+#ifndef AVFILTER_GRAPHPARSER_H
+#define AVFILTER_GRAPHPARSER_H
+
+#include "avfilter.h"
+#include "avfiltergraph.h"
+
+/**
+ * A linked-list of the inputs/outputs of the filter chain.
+ */
+typedef struct AVFilterInOut {
+ const char *name;
+ AVFilterContext *filter;
+ int pad_idx;
+
+ struct AVFilterInOut *next;
+} AVFilterInOut;
+
+/**
+ * Adds a graph described by a string to a graph.
+ *
+ * @param graph the filter graph where to link the parsed graph context
+ * @param filters string to be parsed
+ * @param inputs linked list to the inputs of the graph
+ * @param outputs linked list to the outputs of the graph
+ * @return zero on success, -1 on error
+ */
+int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut *inputs, AVFilterInOut *outputs,
+ AVClass *log_ctx);
+
+#endif /* AVFILTER_GRAPHPARSER_H */
Added: afilters/parseutils.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/parseutils.c Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,472 @@
+/*
+ * copyright (c) 2009 Stefano Sabatini
+ * 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
+ */
+
+/**
+ * @file libavfilter/parseutils.c
+ * parsing utils
+ */
+
+#include <strings.h>
+#include "libavutil/avutil.h"
+#include "libavutil/random_seed.h"
+#include "parseutils.h"
+
+#define WHITESPACES " \n\t"
+
+char *av_get_token(const char **buf, const char *term)
+{
+ char *out = av_malloc(strlen(*buf) + 1);
+ char *ret= out, *end= out;
+ const char *p = *buf;
+ p += strspn(p, WHITESPACES);
+
+ while(*p && !strspn(p, term)) {
+ char c = *p++;
+ if(c == '\\' && *p){
+ *out++ = *p++;
+ end= out;
+ }else if(c == '\''){
+ while(*p && *p != '\'')
+ *out++ = *p++;
+ if(*p){
+ p++;
+ end= out;
+ }
+ }else{
+ *out++ = c;
+ }
+ }
+
+ do{
+ *out-- = 0;
+ }while(out >= end && strspn(out, WHITESPACES));
+
+ *buf = p;
+
+ return ret;
+}
+
+typedef struct {
+ const char *name; ///< a string representing the name of the color
+ uint8_t rgba_color[4]; ///< RGBA values for the color
+} ColorEntry;
+
+static ColorEntry color_table[] = {
+ { "AliceBlue", { 0xF0, 0xF8, 0xFF } },
+ { "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } },
+ { "Aqua", { 0x00, 0xFF, 0xFF } },
+ { "Aquamarine", { 0x7F, 0xFF, 0xD4 } },
+ { "Azure", { 0xF0, 0xFF, 0xFF } },
+ { "Beige", { 0xF5, 0xF5, 0xDC } },
+ { "Bisque", { 0xFF, 0xE4, 0xC4 } },
+ { "Black", { 0x00, 0x00, 0x00 } },
+ { "BlanchedAlmond", { 0xFF, 0xEB, 0xCD } },
+ { "Blue", { 0x00, 0x00, 0xFF } },
+ { "BlueViolet", { 0x8A, 0x2B, 0xE2 } },
+ { "Brown", { 0xA5, 0x2A, 0x2A } },
+ { "BurlyWood", { 0xDE, 0xB8, 0x87 } },
+ { "CadetBlue", { 0x5F, 0x9E, 0xA0 } },
+ { "Chartreuse", { 0x7F, 0xFF, 0x00 } },
+ { "Chocolate", { 0xD2, 0x69, 0x1E } },
+ { "Coral", { 0xFF, 0x7F, 0x50 } },
+ { "CornflowerBlue", { 0x64, 0x95, 0xED } },
+ { "Cornsilk", { 0xFF, 0xF8, 0xDC } },
+ { "Crimson", { 0xDC, 0x14, 0x3C } },
+ { "Cyan", { 0x00, 0xFF, 0xFF } },
+ { "DarkBlue", { 0x00, 0x00, 0x8B } },
+ { "DarkCyan", { 0x00, 0x8B, 0x8B } },
+ { "DarkGoldenRod", { 0xB8, 0x86, 0x0B } },
+ { "DarkGray", { 0xA9, 0xA9, 0xA9 } },
+ { "DarkGreen", { 0x00, 0x64, 0x00 } },
+ { "DarkKhaki", { 0xBD, 0xB7, 0x6B } },
+ { "DarkMagenta", { 0x8B, 0x00, 0x8B } },
+ { "DarkOliveGreen", { 0x55, 0x6B, 0x2F } },
+ { "Darkorange", { 0xFF, 0x8C, 0x00 } },
+ { "DarkOrchid", { 0x99, 0x32, 0xCC } },
+ { "DarkRed", { 0x8B, 0x00, 0x00 } },
+ { "DarkSalmon", { 0xE9, 0x96, 0x7A } },
+ { "DarkSeaGreen", { 0x8F, 0xBC, 0x8F } },
+ { "DarkSlateBlue", { 0x48, 0x3D, 0x8B } },
+ { "DarkSlateGray", { 0x2F, 0x4F, 0x4F } },
+ { "DarkTurquoise", { 0x00, 0xCE, 0xD1 } },
+ { "DarkViolet", { 0x94, 0x00, 0xD3 } },
+ { "DeepPink", { 0xFF, 0x14, 0x93 } },
+ { "DeepSkyBlue", { 0x00, 0xBF, 0xFF } },
+ { "DimGray", { 0x69, 0x69, 0x69 } },
+ { "DodgerBlue", { 0x1E, 0x90, 0xFF } },
+ { "FireBrick", { 0xB2, 0x22, 0x22 } },
+ { "FloralWhite", { 0xFF, 0xFA, 0xF0 } },
+ { "ForestGreen", { 0x22, 0x8B, 0x22 } },
+ { "Fuchsia", { 0xFF, 0x00, 0xFF } },
+ { "Gainsboro", { 0xDC, 0xDC, 0xDC } },
+ { "GhostWhite", { 0xF8, 0xF8, 0xFF } },
+ { "Gold", { 0xFF, 0xD7, 0x00 } },
+ { "GoldenRod", { 0xDA, 0xA5, 0x20 } },
+ { "Gray", { 0x80, 0x80, 0x80 } },
+ { "Green", { 0x00, 0x80, 0x00 } },
+ { "GreenYellow", { 0xAD, 0xFF, 0x2F } },
+ { "HoneyDew", { 0xF0, 0xFF, 0xF0 } },
+ { "HotPink", { 0xFF, 0x69, 0xB4 } },
+ { "IndianRed", { 0xCD, 0x5C, 0x5C } },
+ { "Indigo", { 0x4B, 0x00, 0x82 } },
+ { "Ivory", { 0xFF, 0xFF, 0xF0 } },
+ { "Khaki", { 0xF0, 0xE6, 0x8C } },
+ { "Lavender", { 0xE6, 0xE6, 0xFA } },
+ { "LavenderBlush", { 0xFF, 0xF0, 0xF5 } },
+ { "LawnGreen", { 0x7C, 0xFC, 0x00 } },
+ { "LemonChiffon", { 0xFF, 0xFA, 0xCD } },
+ { "LightBlue", { 0xAD, 0xD8, 0xE6 } },
+ { "LightCoral", { 0xF0, 0x80, 0x80 } },
+ { "LightCyan", { 0xE0, 0xFF, 0xFF } },
+ { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
+ { "LightGrey", { 0xD3, 0xD3, 0xD3 } },
+ { "LightGreen", { 0x90, 0xEE, 0x90 } },
+ { "LightPink", { 0xFF, 0xB6, 0xC1 } },
+ { "LightSalmon", { 0xFF, 0xA0, 0x7A } },
+ { "LightSeaGreen", { 0x20, 0xB2, 0xAA } },
+ { "LightSkyBlue", { 0x87, 0xCE, 0xFA } },
+ { "LightSlateGray", { 0x77, 0x88, 0x99 } },
+ { "LightSteelBlue", { 0xB0, 0xC4, 0xDE } },
+ { "LightYellow", { 0xFF, 0xFF, 0xE0 } },
+ { "Lime", { 0x00, 0xFF, 0x00 } },
+ { "LimeGreen", { 0x32, 0xCD, 0x32 } },
+ { "Linen", { 0xFA, 0xF0, 0xE6 } },
+ { "Magenta", { 0xFF, 0x00, 0xFF } },
+ { "Maroon", { 0x80, 0x00, 0x00 } },
+ { "MediumAquaMarine", { 0x66, 0xCD, 0xAA } },
+ { "MediumBlue", { 0x00, 0x00, 0xCD } },
+ { "MediumOrchid", { 0xBA, 0x55, 0xD3 } },
+ { "MediumPurple", { 0x93, 0x70, 0xD8 } },
+ { "MediumSeaGreen", { 0x3C, 0xB3, 0x71 } },
+ { "MediumSlateBlue", { 0x7B, 0x68, 0xEE } },
+ { "MediumSpringGreen", { 0x00, 0xFA, 0x9A } },
+ { "MediumTurquoise", { 0x48, 0xD1, 0xCC } },
+ { "MediumVioletRed", { 0xC7, 0x15, 0x85 } },
+ { "MidnightBlue", { 0x19, 0x19, 0x70 } },
+ { "MintCream", { 0xF5, 0xFF, 0xFA } },
+ { "MistyRose", { 0xFF, 0xE4, 0xE1 } },
+ { "Moccasin", { 0xFF, 0xE4, 0xB5 } },
+ { "NavajoWhite", { 0xFF, 0xDE, 0xAD } },
+ { "Navy", { 0x00, 0x00, 0x80 } },
+ { "OldLace", { 0xFD, 0xF5, 0xE6 } },
+ { "Olive", { 0x80, 0x80, 0x00 } },
+ { "OliveDrab", { 0x6B, 0x8E, 0x23 } },
+ { "Orange", { 0xFF, 0xA5, 0x00 } },
+ { "OrangeRed", { 0xFF, 0x45, 0x00 } },
+ { "Orchid", { 0xDA, 0x70, 0xD6 } },
+ { "PaleGoldenRod", { 0xEE, 0xE8, 0xAA } },
+ { "PaleGreen", { 0x98, 0xFB, 0x98 } },
+ { "PaleTurquoise", { 0xAF, 0xEE, 0xEE } },
+ { "PaleVioletRed", { 0xD8, 0x70, 0x93 } },
+ { "PapayaWhip", { 0xFF, 0xEF, 0xD5 } },
+ { "PeachPuff", { 0xFF, 0xDA, 0xB9 } },
+ { "Peru", { 0xCD, 0x85, 0x3F } },
+ { "Pink", { 0xFF, 0xC0, 0xCB } },
+ { "Plum", { 0xDD, 0xA0, 0xDD } },
+ { "PowderBlue", { 0xB0, 0xE0, 0xE6 } },
+ { "Purple", { 0x80, 0x00, 0x80 } },
+ { "Red", { 0xFF, 0x00, 0x00 } },
+ { "RosyBrown", { 0xBC, 0x8F, 0x8F } },
+ { "RoyalBlue", { 0x41, 0x69, 0xE1 } },
+ { "SaddleBrown", { 0x8B, 0x45, 0x13 } },
+ { "Salmon", { 0xFA, 0x80, 0x72 } },
+ { "SandyBrown", { 0xF4, 0xA4, 0x60 } },
+ { "SeaGreen", { 0x2E, 0x8B, 0x57 } },
+ { "SeaShell", { 0xFF, 0xF5, 0xEE } },
+ { "Sienna", { 0xA0, 0x52, 0x2D } },
+ { "Silver", { 0xC0, 0xC0, 0xC0 } },
+ { "SkyBlue", { 0x87, 0xCE, 0xEB } },
+ { "SlateBlue", { 0x6A, 0x5A, 0xCD } },
+ { "SlateGray", { 0x70, 0x80, 0x90 } },
+ { "Snow", { 0xFF, 0xFA, 0xFA } },
+ { "SpringGreen", { 0x00, 0xFF, 0x7F } },
+ { "SteelBlue", { 0x46, 0x82, 0xB4 } },
+ { "Tan", { 0xD2, 0xB4, 0x8C } },
+ { "Teal", { 0x00, 0x80, 0x80 } },
+ { "Thistle", { 0xD8, 0xBF, 0xD8 } },
+ { "Tomato", { 0xFF, 0x63, 0x47 } },
+ { "Turquoise", { 0x40, 0xE0, 0xD0 } },
+ { "Violet", { 0xEE, 0x82, 0xEE } },
+ { "Wheat", { 0xF5, 0xDE, 0xB3 } },
+ { "White", { 0xFF, 0xFF, 0xFF } },
+ { "WhiteSmoke", { 0xF5, 0xF5, 0xF5 } },
+ { "Yellow", { 0xFF, 0xFF, 0x00 } },
+ { "YellowGreen", { 0x9A, 0xCD, 0x32 } },
+};
+
+static int color_table_compare(const void *lhs, const void *rhs)
+{
+ return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
+}
+
+int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
+{
+ if (!strcasecmp(color_string, "random") || !strcasecmp(color_string, "bikeshed")) {
+ int rgba = ff_random_get_seed();
+ rgba_color[0] = rgba >> 24;
+ rgba_color[1] = rgba >> 16;
+ rgba_color[2] = rgba >> 8;
+ rgba_color[3] = rgba;
+ } else
+ if (!strncmp(color_string, "0x", 2)) {
+ char *tail;
+ int len = strlen(color_string);
+ int rgba = strtol(color_string, &tail, 16);
+
+ if (*tail || (len != 8 && len != 10)) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string);
+ return -1;
+ }
+ if (len == 10) {
+ rgba_color[3] = rgba;
+ rgba >>= 8;
+ }
+ rgba_color[0] = rgba >> 16;
+ rgba_color[1] = rgba >> 8;
+ rgba_color[2] = rgba;
+ } else {
+ const ColorEntry *entry = bsearch(color_string,
+ color_table,
+ FF_ARRAY_ELEMS(color_table),
+ sizeof(ColorEntry),
+ color_table_compare);
+ if (!entry) {
+ av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string);
+ return -1;
+ }
+ memcpy(rgba_color, entry->rgba_color, 4);
+ }
+
+ return 0;
+}
+
+/**
+ * Stores the value in the field in ctx that is named like key.
+ * ctx must be an AVClass context, storing is done using AVOptions.
+ *
+ * @param buf the string to parse, buf will be updated to point at the
+ * separator just after the parsed key/value pair
+ * @param key_val_sep a 0-terminated list of characters used to
+ * separate key from value
+ * @param pairs_sep a 0-terminated list of characters used to separate
+ * two pairs from each other
+ * @return 0 if the key/value pair has been successfully parsed and
+ * set, or a negative value corresponding to an AVERROR code in case
+ * of error:
+ * AVERROR(EINVAL) if the key/value pair cannot be parsed,
+ * the error code issued by av_set_string3() if the key/value pair
+ * cannot be set
+ */
+static int parse_key_value_pair(void *ctx, const char **buf,
+ const char *key_val_sep, const char *pairs_sep)
+{
+ char *key = av_get_token(buf, key_val_sep);
+ char *val;
+ int ret;
+
+ if (*key && strspn(*buf, key_val_sep)) {
+ (*buf)++;
+ val = av_get_token(buf, pairs_sep);
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
+ av_free(key);
+ return AVERROR(EINVAL);
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
+
+ ret = av_set_string3(ctx, key, val, 1, NULL);
+
+ av_free(key);
+ av_free(val);
+ return ret;
+}
+
+int av_set_options_string(void *ctx, const char *opts,
+ const char *key_val_sep, const char *pairs_sep)
+{
+ int ret, count = 0;
+
+ while (*opts) {
+ if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
+ return ret;
+ count++;
+
+ if (*opts)
+ opts++;
+ }
+
+ return count;
+}
+
+#ifdef TEST
+
+#undef printf
+
+typedef struct TestContext
+{
+ const AVClass *class;
+ int num;
+ int toggle;
+ char *string;
+ int flags;
+ AVRational rational;
+} TestContext;
+
+#define OFFSET(x) offsetof(TestContext, x)
+
+#define TEST_FLAG_COOL 01
+#define TEST_FLAG_LAME 02
+#define TEST_FLAG_MU 04
+
+static const AVOption test_options[]= {
+{"num", "set num", OFFSET(num), FF_OPT_TYPE_INT, 0, 0, 100 },
+{"toggle", "set toggle", OFFSET(toggle), FF_OPT_TYPE_INT, 0, 0, 1 },
+{"rational", "set rational", OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0, 0, 10 },
+{"string", "set string", OFFSET(string), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX },
+{"flags", "set flags", OFFSET(flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, 0, "flags" },
+{"cool", "set cool flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_COOL, INT_MIN, INT_MAX, 0, "flags" },
+{"lame", "set lame flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_LAME, INT_MIN, INT_MAX, 0, "flags" },
+{"mu", "set mu flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_MU, INT_MIN, INT_MAX, 0, "flags" },
+{NULL},
+};
+
+static const char *test_get_name(void *ctx)
+{
+ return "test";
+}
+
+static const AVClass test_class = {
+ "TestContext",
+ test_get_name,
+ test_options
+};
+
+int main(void)
+{
+ int i;
+
+ const char *strings[] = {
+ "''",
+ "",
+ ":",
+ "\\",
+ "'",
+ " '' :",
+ " '' '' :",
+ "foo '' :",
+ "'foo'",
+ "foo ",
+ "foo\\",
+ "foo': blah:blah",
+ "foo\\: blah:blah",
+ "foo\'",
+ "'foo : ' :blahblah",
+ "\\ :blah",
+ " foo",
+ " foo ",
+ " foo \\ ",
+ "foo ':blah",
+ " foo bar : blahblah",
+ "\\f\\o\\o",
+ "'foo : \\ \\ ' : blahblah",
+ "'\\fo\\o:': blahblah",
+ "\\'fo\\o\\:': foo ' :blahblah"
+ };
+
+ for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
+ const char *p= strings[i];
+ printf("|%s|", p);
+ printf(" -> |%s|", av_get_token(&p, ":"));
+ printf(" + |%s|\n", p);
+ }
+
+ printf("\nTesting av_parse_color()\n");
+ {
+ uint8_t rgba[4];
+ const char *color_names[] = {
+ "bikeshed",
+ "RaNdOm",
+ "foo",
+ "red",
+ "Red ",
+ "RED",
+ "Violet",
+ "Yellow",
+ "Red",
+ "0x000000",
+ "0x0000000",
+ "0x3e34ff",
+ "0x3e34ffaa",
+ "0xffXXee",
+ "0xfoobar",
+ "0xffffeeeeeeee",
+ };
+
+ av_log_set_level(AV_LOG_DEBUG);
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(color_names); i++) {
+ if (av_parse_color(rgba, color_names[i], NULL) >= 0)
+ printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
+ }
+ }
+
+ printf("\nTesting av_set_options_string()\n");
+ {
+ TestContext test_ctx;
+ const char *options[] = {
+ "",
+ ":",
+ "=",
+ "foo=:",
+ ":=foo",
+ "=foo",
+ "foo=",
+ "foo",
+ "foo=val",
+ "foo==val",
+ "toggle=:",
+ "string=:",
+ "toggle=1 : foo",
+ "toggle=100",
+ "toggle==1",
+ "flags=+mu-lame : num=42: toggle=0",
+ "num=42 : string=blahblah",
+ "rational=0 : rational=1/2 : rational=1/-1",
+ "rational=-1/0",
+ };
+
+ test_ctx.class = &test_class;
+ av_opt_set_defaults2(&test_ctx, 0, 0);
+ test_ctx.string = av_strdup("default");
+
+ av_log_set_level(AV_LOG_DEBUG);
+
+ for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
+ av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
+ if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
+ av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+#endif
Added: afilters/parseutils.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ afilters/parseutils.h Thu May 28 05:19:12 2009 (r4319)
@@ -0,0 +1,75 @@
+/*
+ * copyright (c) 2009 Stefano Sabatini
+ * 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
+ */
+
+/**
+ * @file libavfilter/parseutils.h
+ * parsing utils
+ */
+
+#ifndef AVFILTER_PARSEUTILS_H
+#define AVFILTER_PARSEUTILS_H
+
+#include "libavcodec/opt.h"
+
+/**
+ * Unescapes the given string until a non escaped terminating char,
+ * and returns the token corresponding to the unescaped string.
+ *
+ * The normal \ and ' escaping is supported. Leading and trailing
+ * whitespaces are removed.
+ *
+ * @param term a 0-terminated list of terminating chars
+ * @param buf the buffer to parse, buf will be updated to point to the
+ * terminating char
+ * @return the malloced unescaped string, which must be av_freed by
+ * the user
+ */
+char *av_get_token(const char **buf, const char *term);
+
+/**
+ * Puts the RGBA values that correspond to color_string in rgba_color.
+ *
+ * @param color_string a string specifying a color. It can be the name of
+ * a color (case insensitive match) or a 0xRRGGBB[AA] sequence.
+ * The string "random" will result in a random color.
+ * @return >= 0 in case of success, a negative value in case of
+ * failure (for example if color_string cannot be parsed).
+ */
+int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx);
+
+/**
+ * Parses the key/value pairs list in opts. For each key/value pair
+ * found, stores the value in the field in ctx that is named like the
+ * key. ctx must be an AVClass context, storing is done using
+ * AVOptions.
+ *
+ * @param key_val_sep a 0-terminated list of characters used to
+ * separate key from value
+ * @param pairs_sep a 0-terminated list of characters used to separate
+ * two pairs from each other
+ * @return the number of successfully set key/value pairs, or a negative
+ * value corresponding to an AVERROR code in case of error:
+ * AVERROR(EINVAL) if opts cannot be parsed,
+ * the error code issued by av_set_string3() if a key/value pair
+ * cannot be set
+ */
+int av_set_options_string(void *ctx, const char *opts,
+ const char *key_val_sep, const char *pairs_sep);
+
+#endif /* AVFILTER_PARSEUTILS_H */
More information about the FFmpeg-soc
mailing list