From 7dd56d411e1e5afbf0c0d42b40256a59e1d2f217 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 12 May 2012 19:40:41 +0200 Subject: yadif: Improve pts accuracy. Signed-off-by: Anton Khirnov --- libavfilter/vf_yadif.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index 790dda5a0b..fac0e5b5f3 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -218,11 +218,11 @@ static void return_frame(AVFilterContext *ctx, int is_second) filter(ctx, yadif->out, tff ^ !is_second, tff); if (is_second) { - if (yadif->next->pts != AV_NOPTS_VALUE && - yadif->cur->pts != AV_NOPTS_VALUE) { - yadif->out->pts = - (yadif->next->pts&yadif->cur->pts) + - ((yadif->next->pts^yadif->cur->pts)>>1); + int64_t cur_pts = yadif->cur->pts; + int64_t next_pts = yadif->next->pts; + + if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) { + yadif->out->pts = cur_pts + next_pts; } else { yadif->out->pts = AV_NOPTS_VALUE; } @@ -255,6 +255,8 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) yadif->out = avfilter_ref_buffer(yadif->cur, AV_PERM_READ); avfilter_unref_buffer(yadif->prev); yadif->prev = NULL; + if (yadif->out->pts != AV_NOPTS_VALUE) + yadif->out->pts *= 2; avfilter_start_frame(ctx->outputs[0], yadif->out); return; } @@ -267,6 +269,8 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) avfilter_copy_buffer_ref_props(yadif->out, yadif->cur); yadif->out->video->interlaced = 0; + if (yadif->out->pts != AV_NOPTS_VALUE) + yadif->out->pts *= 2; avfilter_start_frame(ctx->outputs[0], yadif->out); } @@ -400,6 +404,16 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { } +static int config_props(AVFilterLink *link) +{ + link->time_base.num = link->src->inputs[0]->time_base.num; + link->time_base.den = link->src->inputs[0]->time_base.den * 2; + link->w = link->src->inputs[0]->w; + link->h = link->src->inputs[0]->h; + + return 0; +} + AVFilter avfilter_vf_yadif = { .name = "yadif", .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image"), @@ -420,6 +434,7 @@ AVFilter avfilter_vf_yadif = { .outputs = (AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_VIDEO, .poll_frame = poll_frame, - .request_frame = request_frame, }, + .request_frame = request_frame, + .config_props = config_props, }, { .name = NULL}}, }; -- cgit v1.2.3 From 394a0267abd6a292932f858949449b5cd6f8efda Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Mon, 14 May 2012 14:25:25 +0200 Subject: yadif: Flush filter on eof. Signed-off-by: Anton Khirnov --- libavfilter/vf_yadif.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'libavfilter') diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index fac0e5b5f3..1cecdd98cb 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -61,6 +61,7 @@ typedef struct { int w, int prefs, int mrefs, int parity, int mode); const AVPixFmtDescriptor *csp; + int eof; } YADIFContext; #define CHECK(j)\ @@ -304,8 +305,21 @@ static int request_frame(AVFilterLink *link) do { int ret; - if ((ret = avfilter_request_frame(link->src->inputs[0]))) + if (yadif->eof) + return AVERROR_EOF; + + ret = avfilter_request_frame(link->src->inputs[0]); + + if (ret == AVERROR_EOF && yadif->next) { + AVFilterBufferRef *next = avfilter_ref_buffer(yadif->next, AV_PERM_READ); + next->pts = yadif->next->pts * 2 - yadif->cur->pts; + + start_frame(link->src->inputs[0], next); + end_frame(link->src->inputs[0]); + yadif->eof = 1; + } else if (ret < 0) { return ret; + } } while (!yadif->cur); return 0; -- cgit v1.2.3 From 5775a1832c4165e6acc1d307004b38701bb463f4 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 6 May 2012 06:59:06 +0200 Subject: lavfi: add types and functions for channel layout/samplerate negotiation --- libavfilter/avfilter.h | 16 +++ libavfilter/formats.c | 282 ++++++++++++++++++++++++++++++++++++------------- libavfilter/formats.h | 78 ++++++++++++++ 3 files changed, 300 insertions(+), 76 deletions(-) create mode 100644 libavfilter/formats.h (limited to 'libavfilter') diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index fd996db94b..718f77df3d 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -618,6 +618,22 @@ struct AVFilterLink { * input link is assumed to be an unchangeable property. */ AVRational time_base; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavfilter and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + /** + * Lists of channel layouts and sample rates used for automatic + * negotiation. + */ + AVFilterFormats *in_samplerates; + AVFilterFormats *out_samplerates; + struct AVFilterChannelLayouts *in_channel_layouts; + struct AVFilterChannelLayouts *out_channel_layouts; }; /** diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 206eff5587..06567c4d2f 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -22,58 +22,132 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "internal.h" +#include "formats.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; - } +#define MERGE_REF(ret, a, fmts, type, fail) \ +do { \ + type ***tmp; \ + int i; \ + \ + if (!(tmp = av_realloc(ret->refs, \ + sizeof(*tmp) * (ret->refcount + a->refcount)))) \ + goto fail; \ + ret->refs = tmp; \ + \ + for (i = 0; i < a->refcount; i ++) { \ + ret->refs[ret->refcount] = a->refs[i]; \ + *ret->refs[ret->refcount++] = ret; \ + } \ + \ + av_freep(&a->refs); \ + av_freep(&a->fmts); \ + av_freep(&a); \ +} while (0) - av_free(a->refs); - av_free(a->formats); - av_free(a); -} +/** + * Add all formats common for a and b to ret, copy the refs and destroy + * a and b. + */ +#define MERGE_FORMATS(ret, a, b, fmts, nb, type, fail) \ +do { \ + int i, j, k = 0, count = FFMIN(a->nb, b->nb); \ + \ + if (!(ret = av_mallocz(sizeof(*ret)))) \ + goto fail; \ + \ + if (count) { \ + if (!(ret->fmts = av_malloc(sizeof(*ret->fmts) * count))) \ + goto fail; \ + for (i = 0; i < a->nb; i++) \ + for (j = 0; j < b->nb; j++) \ + if (a->fmts[i] == b->fmts[j]) \ + ret->fmts[k++] = a->fmts[i]; \ + \ + ret->nb = k; \ + } \ + /* check that there was at least one common format */ \ + if (!ret->nb) \ + goto fail; \ + \ + MERGE_REF(ret, a, fmts, type, fail); \ + MERGE_REF(ret, b, fmts, type, fail); \ +} while (0) AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b) { - AVFilterFormats *ret; - unsigned i, j, k = 0, m_count; + AVFilterFormats *ret = NULL; if (a == b) return a; - ret = av_mallocz(sizeof(*ret)); - - /* merge list of formats */ - m_count = FFMIN(a->format_count, b->format_count); - if (m_count) { - ret->formats = av_malloc(sizeof(*ret->formats) * m_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]; + MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail); - ret->format_count = k; + return ret; +fail: + if (ret) { + av_freep(&ret->refs); + av_freep(&ret->formats); } - /* check that there was at least one common format */ - if(!ret->format_count) { - av_free(ret->formats); - av_free(ret); - return NULL; + av_freep(&ret); + return NULL; +} + +AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a, + AVFilterFormats *b) +{ + AVFilterFormats *ret = NULL; + + if (a == b) return a; + + if (a->format_count && b->format_count) { + MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail); + } else if (a->format_count) { + MERGE_REF(a, b, formats, AVFilterFormats, fail); + ret = a; + } else { + MERGE_REF(b, a, formats, AVFilterFormats, fail); + ret = b; } - ret->refs = av_malloc(sizeof(*ret->refs) * (a->refcount + b->refcount)); + return ret; +fail: + if (ret) { + av_freep(&ret->refs); + av_freep(&ret->formats); + } + av_freep(&ret); + return NULL; +} - merge_ref(ret, a); - merge_ref(ret, b); +AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, + AVFilterChannelLayouts *b) +{ + AVFilterChannelLayouts *ret = NULL; + + if (a == b) return a; + + if (a->nb_channel_layouts && b->nb_channel_layouts) { + MERGE_FORMATS(ret, a, b, channel_layouts, nb_channel_layouts, + AVFilterChannelLayouts, fail); + } else if (a->nb_channel_layouts) { + MERGE_REF(a, b, channel_layouts, AVFilterChannelLayouts, fail); + ret = a; + } else { + MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, fail); + ret = b; + } return ret; +fail: + if (ret) { + av_freep(&ret->refs); + av_freep(&ret->channel_layouts); + } + av_freep(&ret); + return NULL; } int ff_fmt_is_in(int fmt, const int *fmts) @@ -104,21 +178,31 @@ AVFilterFormats *avfilter_make_format_list(const int *fmts) return formats; } +#define ADD_FORMAT(f, fmt, type, list, nb) \ +do { \ + type *fmts; \ + \ + if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) \ + return AVERROR(ENOMEM); \ + \ + fmts = av_realloc((*f)->list, \ + sizeof(*(*f)->list) * ((*f)->nb + 1));\ + if (!fmts) \ + return AVERROR(ENOMEM); \ + \ + (*f)->list = fmts; \ + (*f)->list[(*f)->nb++] = fmt; \ + return 0; \ +} while (0) + int avfilter_add_format(AVFilterFormats **avff, int fmt) { - int *fmts; - - if (!(*avff) && !(*avff = av_mallocz(sizeof(**avff)))) - return AVERROR(ENOMEM); - - fmts = av_realloc((*avff)->formats, - sizeof(*(*avff)->formats) * ((*avff)->format_count+1)); - if (!fmts) - return AVERROR(ENOMEM); + ADD_FORMAT(avff, fmt, int, formats, format_count); +} - (*avff)->formats = fmts; - (*avff)->formats[(*avff)->format_count++] = fmt; - return 0; +int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout) +{ + ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts); } AVFilterFormats *avfilter_all_formats(enum AVMediaType type) @@ -136,51 +220,97 @@ AVFilterFormats *avfilter_all_formats(enum AVMediaType type) return ret; } -void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref) +AVFilterFormats *ff_all_samplerates(void) { - *ref = f; - f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount); - f->refs[f->refcount-1] = ref; + AVFilterFormats *ret = av_mallocz(sizeof(*ret)); + return ret; } -static int find_ref_index(AVFilterFormats **ref) +AVFilterChannelLayouts *ff_all_channel_layouts(void) { - int i; - for(i = 0; i < (*ref)->refcount; i ++) - if((*ref)->refs[i] == ref) - return i; - return -1; + AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret)); + return ret; } -void avfilter_formats_unref(AVFilterFormats **ref) +#define FORMATS_REF(f, ref) \ +do { \ + *ref = f; \ + f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount); \ + f->refs[f->refcount-1] = ref; \ +} while (0) + +void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref) { - int idx; + FORMATS_REF(f, ref); +} - if (!*ref) - return; +void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref) +{ + FORMATS_REF(f, ref); +} - idx = find_ref_index(ref); +#define FIND_REF_INDEX(ref, idx) \ +do { \ + int i; \ + for (i = 0; i < (*ref)->refcount; i ++) \ + if((*ref)->refs[i] == ref) { \ + idx = i; \ + break; \ + } \ +} while (0) + +#define FORMATS_UNREF(ref, list) \ +do { \ + int idx = -1; \ + \ + if (!*ref) \ + return; \ + \ + FIND_REF_INDEX(ref, idx); \ + \ + if (idx >= 0) \ + memmove((*ref)->refs + idx, (*ref)->refs + idx + 1, \ + sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); \ + \ + if(!--(*ref)->refcount) { \ + av_free((*ref)->list); \ + av_free((*ref)->refs); \ + av_free(*ref); \ + } \ + *ref = NULL; \ +} while (0) - if(idx >= 0) - memmove((*ref)->refs + idx, (*ref)->refs + idx + 1, - sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); +void avfilter_formats_unref(AVFilterFormats **ref) +{ + FORMATS_UNREF(ref, formats); +} - if(!--(*ref)->refcount) { - av_free((*ref)->formats); - av_free((*ref)->refs); - av_free(*ref); - } - *ref = NULL; +void ff_channel_layouts_unref(AVFilterChannelLayouts **ref) +{ + FORMATS_UNREF(ref, channel_layouts); +} + +#define FORMATS_CHANGEREF(oldref, newref) \ +do { \ + int idx = -1; \ + \ + FIND_REF_INDEX(oldref, idx); \ + \ + if (idx >= 0) { \ + (*oldref)->refs[idx] = newref; \ + *newref = *oldref; \ + *oldref = NULL; \ + } \ +} while (0) + +void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref, + AVFilterChannelLayouts **newref) +{ + FORMATS_CHANGEREF(oldref, newref); } 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; - } + FORMATS_CHANGEREF(oldref, newref); } diff --git a/libavfilter/formats.h b/libavfilter/formats.h new file mode 100644 index 0000000000..7e0a60114c --- /dev/null +++ b/libavfilter/formats.h @@ -0,0 +1,78 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_FORMATS_H +#define AVFILTER_FORMATS_H + +#include "avfilter.h" + +typedef struct AVFilterChannelLayouts { + uint64_t *channel_layouts; ///< list of channel layouts + int nb_channel_layouts; ///< number of channel layouts + + unsigned refcount; ///< number of references to this list + struct AVFilterChannelLayouts ***refs; ///< references to this list +} AVFilterChannelLayouts; + +/** + * Return a channel layouts/samplerates list which contains the intersection of + * the layouts/samplerates 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 elements, neither is modified, and NULL + * is returned. + */ +AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, + AVFilterChannelLayouts *b); +AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a, + AVFilterFormats *b); + +/** + * Construct an empty AVFilterChannelLayouts/AVFilterFormats struct -- + * representing any channel layout/sample rate. + */ +AVFilterChannelLayouts *ff_all_channel_layouts(void); +AVFilterFormats *ff_all_samplerates(void); + +/** + * A helper for query_formats() which sets all links to the same list of channel + * layouts/sample rates. If there are no links hooked to this filter, the list + * is freed. + */ +void ff_set_common_channel_layouts(AVFilterContext *ctx, + AVFilterChannelLayouts *layouts); +void ff_set_common_samplerates(AVFilterContext *ctx, + AVFilterFormats *samplerates); + +int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout); + +/** + * Add *ref as a new reference to f. + */ +void ff_channel_layouts_ref(AVFilterChannelLayouts *f, + AVFilterChannelLayouts **ref); + +/** + * Remove a reference to a channel layouts list. + */ +void ff_channel_layouts_unref(AVFilterChannelLayouts **ref); + +void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref, + AVFilterChannelLayouts **newref); + +#endif // AVFILTER_FORMATS_H -- cgit v1.2.3 From ff1f51a8aa624753aaec76d8f836cd3c92d91fed Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 6 May 2012 07:00:22 +0200 Subject: lavfi: add channel layout/sample rate negotiation. --- libavfilter/af_resample.c | 11 ++ libavfilter/avfilter.c | 21 ++-- libavfilter/avfiltergraph.c | 257 ++++++++++++++++++++++++++++++++++++++------ libavfilter/defaults.c | 72 ++++++++----- 4 files changed, 294 insertions(+), 67 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c index f46e24b1b6..4ad5a8c38e 100644 --- a/libavfilter/af_resample.c +++ b/libavfilter/af_resample.c @@ -31,6 +31,7 @@ #include "audio.h" #include "avfilter.h" +#include "formats.h" #include "internal.h" typedef struct ResampleContext { @@ -56,10 +57,20 @@ static int query_formats(AVFilterContext *ctx) AVFilterFormats *in_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); AVFilterFormats *out_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); + AVFilterFormats *in_samplerates = ff_all_samplerates(); + AVFilterFormats *out_samplerates = ff_all_samplerates(); + AVFilterChannelLayouts *in_layouts = ff_all_channel_layouts(); + AVFilterChannelLayouts *out_layouts = ff_all_channel_layouts(); avfilter_formats_ref(in_formats, &inlink->out_formats); avfilter_formats_ref(out_formats, &outlink->in_formats); + avfilter_formats_ref(in_samplerates, &inlink->out_samplerates); + avfilter_formats_ref(out_samplerates, &outlink->in_samplerates); + + ff_channel_layouts_ref(in_layouts, &inlink->out_channel_layouts); + ff_channel_layouts_ref(out_layouts, &outlink->in_channel_layouts); + return 0; } diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index bd898e37ab..57108b13ce 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -28,6 +28,7 @@ #include "libavcodec/avcodec.h" #include "avfilter.h" +#include "formats.h" #include "internal.h" unsigned avfilter_version(void) { @@ -176,6 +177,12 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, if (link->out_formats) avfilter_formats_changeref(&link->out_formats, &filt->outputs[filt_dstpad_idx]->out_formats); + if (link->out_samplerates) + avfilter_formats_changeref(&link->out_samplerates, + &filt->outputs[filt_dstpad_idx]->out_samplerates); + if (link->out_channel_layouts) + ff_channel_layouts_changeref(&link->out_channel_layouts, + &filt->outputs[filt_dstpad_idx]->out_channel_layouts); return 0; } @@ -216,12 +223,6 @@ int avfilter_config_links(AVFilterContext *filter) link->sample_aspect_ratio = link->src->input_count ? link->src->inputs[0]->sample_aspect_ratio : (AVRational){1,1}; - if (link->sample_rate == 0 && link->src && link->src->input_count) - link->sample_rate = link->src->inputs[0]->sample_rate; - - if (link->channel_layout == 0 && link->src && link->src->input_count) - link->channel_layout = link->src->inputs[0]->channel_layout; - if ((config_link = link->dstpad->config_props)) if ((ret = config_link(link)) < 0) return ret; @@ -614,6 +615,10 @@ void avfilter_free(AVFilterContext *filter) link->src->outputs[link->srcpad - link->src->output_pads] = NULL; avfilter_formats_unref(&link->in_formats); avfilter_formats_unref(&link->out_formats); + avfilter_formats_unref(&link->in_samplerates); + avfilter_formats_unref(&link->out_samplerates); + ff_channel_layouts_unref(&link->in_channel_layouts); + ff_channel_layouts_unref(&link->out_channel_layouts); } av_freep(&link); } @@ -623,6 +628,10 @@ void avfilter_free(AVFilterContext *filter) link->dst->inputs[link->dstpad - link->dst->input_pads] = NULL; avfilter_formats_unref(&link->in_formats); avfilter_formats_unref(&link->out_formats); + avfilter_formats_unref(&link->in_samplerates); + avfilter_formats_unref(&link->out_samplerates); + ff_channel_layouts_unref(&link->in_channel_layouts); + ff_channel_layouts_unref(&link->out_channel_layouts); } av_freep(&link); } diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index e576cca471..01f7411b97 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -25,8 +25,10 @@ #include "avfilter.h" #include "avfiltergraph.h" +#include "formats.h" #include "internal.h" +#include "libavutil/audioconvert.h" #include "libavutil/log.h" static const AVClass filtergraph_class = { @@ -168,9 +170,27 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) 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)) { + int convert_needed = 0; + + if (!link) + continue; + + if (link->in_formats != link->out_formats && + !avfilter_merge_formats(link->in_formats, + link->out_formats)) + convert_needed = 1; + if (link->type == AVMEDIA_TYPE_AUDIO) { + if (link->in_channel_layouts != link->out_channel_layouts && + !ff_merge_channel_layouts(link->in_channel_layouts, + link->out_channel_layouts)) + convert_needed = 1; + if (link->in_samplerates != link->out_samplerates && + !ff_merge_samplerates(link->in_samplerates, + link->out_samplerates)) + convert_needed = 1; + } + + if (convert_needed) { AVFilterContext *convert; AVFilter *filter; AVFilterLink *inlink, *outlink; @@ -214,13 +234,27 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) inlink = convert->inputs[0]; outlink = convert->outputs[0]; if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || - !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) { + !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) + ret |= AVERROR(ENOSYS); + if (inlink->type == AVMEDIA_TYPE_AUDIO && + (!ff_merge_samplerates(inlink->in_samplerates, + inlink->out_samplerates) || + !ff_merge_channel_layouts(inlink->in_channel_layouts, + inlink->out_channel_layouts))) + ret |= AVERROR(ENOSYS); + if (outlink->type == AVMEDIA_TYPE_AUDIO && + (!ff_merge_samplerates(outlink->in_samplerates, + outlink->out_samplerates) || + !ff_merge_channel_layouts(outlink->in_channel_layouts, + outlink->out_channel_layouts))) + ret |= AVERROR(ENOSYS); + + if (ret < 0) { av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); - return AVERROR(EINVAL); + return ret; } - } } } } @@ -228,46 +262,90 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) return 0; } -static void pick_format(AVFilterLink *link) +static int pick_format(AVFilterLink *link) { if (!link || !link->in_formats) - return; + return 0; link->in_formats->format_count = 1; link->format = link->in_formats->formats[0]; + if (link->type == AVMEDIA_TYPE_AUDIO) { + if (!link->in_samplerates->format_count) { + av_log(link->src, AV_LOG_ERROR, "Cannot select sample rate for" + " the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->in_samplerates->format_count = 1; + link->sample_rate = link->in_samplerates->formats[0]; + + if (!link->in_channel_layouts->nb_channel_layouts) { + av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" + "the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->in_channel_layouts->nb_channel_layouts = 1; + link->channel_layout = link->in_channel_layouts->channel_layouts[0]; + } + avfilter_formats_unref(&link->in_formats); avfilter_formats_unref(&link->out_formats); + avfilter_formats_unref(&link->in_samplerates); + avfilter_formats_unref(&link->out_samplerates); + ff_channel_layouts_unref(&link->in_channel_layouts); + ff_channel_layouts_unref(&link->out_channel_layouts); + + return 0; } +#define REDUCE_FORMATS(fmt_type, list_type, list, var, nb, add_format) \ +do { \ + for (i = 0; i < filter->input_count; i++) { \ + AVFilterLink *link = filter->inputs[i]; \ + fmt_type fmt; \ + \ + if (!link->out_ ## list || link->out_ ## list->nb != 1) \ + continue; \ + fmt = link->out_ ## list->var[0]; \ + \ + for (j = 0; j < filter->output_count; j++) { \ + AVFilterLink *out_link = filter->outputs[j]; \ + list_type *fmts; \ + \ + if (link->type != out_link->type || \ + out_link->in_ ## list->nb == 1) \ + continue; \ + fmts = out_link->in_ ## list; \ + \ + if (!out_link->in_ ## list->nb) { \ + add_format(&out_link->in_ ##list, fmt); \ + break; \ + } \ + \ + for (k = 0; k < out_link->in_ ## list->nb; k++) \ + if (fmts->var[k] == fmt) { \ + fmts->var[0] = fmt; \ + fmts->nb = 1; \ + ret = 1; \ + break; \ + } \ + } \ + } \ +} while (0) + static int reduce_formats_on_filter(AVFilterContext *filter) { int i, j, k, ret = 0; - for (i = 0; i < filter->input_count; i++) { - AVFilterLink *link = filter->inputs[i]; - int format = link->out_formats->formats[0]; - - if (link->out_formats->format_count != 1) - continue; - - for (j = 0; j < filter->output_count; j++) { - AVFilterLink *out_link = filter->outputs[j]; - AVFilterFormats *fmts = out_link->in_formats; + REDUCE_FORMATS(int, AVFilterFormats, formats, formats, + format_count, avfilter_add_format); + REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, + format_count, avfilter_add_format); + REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, + channel_layouts, nb_channel_layouts, ff_add_channel_layout); - if (link->type != out_link->type || - out_link->in_formats->format_count == 1) - continue; - - for (k = 0; k < out_link->in_formats->format_count; k++) - if (fmts->formats[k] == format) { - fmts->formats[0] = format; - fmts->format_count = 1; - ret = 1; - break; - } - } - } return ret; } @@ -283,18 +361,121 @@ static void reduce_formats(AVFilterGraph *graph) } while (reduced); } -static void pick_formats(AVFilterGraph *graph) +static void swap_samplerates_on_filter(AVFilterContext *filter) +{ + AVFilterLink *link = NULL; + int sample_rate; + int i, j; + + for (i = 0; i < filter->input_count; i++) { + link = filter->inputs[i]; + + if (link->type == AVMEDIA_TYPE_AUDIO && + link->out_samplerates->format_count == 1) + break; + } + if (i == filter->input_count) + return; + + sample_rate = link->out_samplerates->formats[0]; + + for (i = 0; i < filter->output_count; i++) { + AVFilterLink *outlink = filter->outputs[i]; + int best_idx, best_diff = INT_MAX; + + if (outlink->type != AVMEDIA_TYPE_AUDIO || + outlink->in_samplerates->format_count < 2) + continue; + + for (j = 0; j < outlink->in_samplerates->format_count; j++) { + int diff = abs(sample_rate - outlink->in_samplerates->formats[j]); + + if (diff < best_diff) { + best_diff = diff; + best_idx = j; + } + } + FFSWAP(int, outlink->in_samplerates->formats[0], + outlink->in_samplerates->formats[best_idx]); + } +} + +static void swap_samplerates(AVFilterGraph *graph) +{ + int i; + + for (i = 0; i < graph->filter_count; i++) + swap_samplerates_on_filter(graph->filters[i]); +} + +static void swap_channel_layouts_on_filter(AVFilterContext *filter) { + AVFilterLink *link = NULL; + uint64_t chlayout; int i, j; + for (i = 0; i < filter->input_count; i++) { + link = filter->inputs[i]; + + if (link->type == AVMEDIA_TYPE_AUDIO && + link->out_channel_layouts->nb_channel_layouts == 1) + break; + } + if (i == filter->input_count) + return; + + chlayout = link->out_channel_layouts->channel_layouts[0]; + + for (i = 0; i < filter->output_count; i++) { + AVFilterLink *outlink = filter->outputs[i]; + int best_idx, best_score = INT_MIN; + + if (outlink->type != AVMEDIA_TYPE_AUDIO || + outlink->in_channel_layouts->nb_channel_layouts < 2) + continue; + + for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { + uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; + int matched_channels = av_get_channel_layout_nb_channels(chlayout & + out_chlayout); + int extra_channels = av_get_channel_layout_nb_channels(out_chlayout & + (~chlayout)); + int score = matched_channels - extra_channels; + + if (score > best_score) { + best_score = score; + best_idx = j; + } + } + FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], + outlink->in_channel_layouts->channel_layouts[best_idx]); + } + +} + +static void swap_channel_layouts(AVFilterGraph *graph) +{ + int i; + + for (i = 0; i < graph->filter_count; i++) + swap_channel_layouts_on_filter(graph->filters[i]); +} + +static int pick_formats(AVFilterGraph *graph) +{ + int i, j, ret; + 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]); + if ((ret = pick_format(filter->inputs[j])) < 0) + return ret; for (j = 0; j < filter->output_count; j++) - pick_format(filter->outputs[j]); + if ((ret = pick_format(filter->outputs[j])) < 0) + return ret; } + return 0; } int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) @@ -310,7 +491,13 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) * of format conversion inside filters */ reduce_formats(graph); - pick_formats(graph); + /* for audio filters, ensure the best sample rate and channel layout + * is selected */ + swap_samplerates(graph); + swap_channel_layouts(graph); + + if ((ret = pick_formats(graph)) < 0) + return ret; return 0; } diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c index caf6442974..cb7bf1c4ef 100644 --- a/libavfilter/defaults.c +++ b/libavfilter/defaults.c @@ -25,6 +25,7 @@ #include "avfilter.h" #include "internal.h" +#include "formats.h" /* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */ void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr) @@ -112,9 +113,6 @@ int avfilter_default_config_output_link(AVFilterLink *link) link->w = link->src->inputs[0]->w; link->h = link->src->inputs[0]->h; link->time_base = link->src->inputs[0]->time_base; - } else if (link->type == AVMEDIA_TYPE_AUDIO) { - link->channel_layout = link->src->inputs[0]->channel_layout; - link->sample_rate = link->src->inputs[0]->sample_rate; } } else { /* XXX: any non-simple filter which would cause this branch to be taken @@ -125,36 +123,53 @@ int avfilter_default_config_output_link(AVFilterLink *link) return 0; } +#define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \ +{ \ + int count = 0, i; \ + \ + for (i = 0; i < ctx->input_count; i++) { \ + if (ctx->inputs[i]) { \ + ref(fmts, &ctx->inputs[i]->out_fmts); \ + count++; \ + } \ + } \ + for (i = 0; i < ctx->output_count; i++) { \ + if (ctx->outputs[i]) { \ + ref(fmts, &ctx->outputs[i]->in_fmts); \ + count++; \ + } \ + } \ + \ + if (!count) { \ + av_freep(&fmts->list); \ + av_freep(&fmts->refs); \ + av_freep(&fmts); \ + } \ +} + +void ff_set_common_channel_layouts(AVFilterContext *ctx, + AVFilterChannelLayouts *layouts) +{ + SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts, + ff_channel_layouts_ref, channel_layouts); +} + +void ff_set_common_samplerates(AVFilterContext *ctx, + AVFilterFormats *samplerates) +{ + SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates, + avfilter_formats_ref, formats); +} + /** * 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); - } + SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats, + avfilter_formats_ref, formats); } int avfilter_default_query_formats(AVFilterContext *ctx) @@ -164,6 +179,11 @@ int avfilter_default_query_formats(AVFilterContext *ctx) AVMEDIA_TYPE_VIDEO; avfilter_set_common_formats(ctx, avfilter_all_formats(type)); + if (type == AVMEDIA_TYPE_AUDIO) { + ff_set_common_channel_layouts(ctx, ff_all_channel_layouts()); + ff_set_common_samplerates(ctx, ff_all_samplerates()); + } + return 0; } -- cgit v1.2.3 From fd127ede62306b273de925489c78d48474438b31 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 7 May 2012 20:21:20 +0200 Subject: avfiltergraph: reindent --- libavfilter/avfiltergraph.c | 120 ++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 60 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 01f7411b97..f65faae8ce 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -191,70 +191,70 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) } if (convert_needed) { - AVFilterContext *convert; - AVFilter *filter; - AVFilterLink *inlink, *outlink; - char scale_args[256]; - char inst_name[30]; - - /* couldn't merge format lists. auto-insert conversion filter */ - switch (link->type) { - case AVMEDIA_TYPE_VIDEO: - snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", - scaler_count++); - snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); - if ((ret = avfilter_graph_create_filter(&convert, - avfilter_get_by_name("scale"), - inst_name, scale_args, NULL, - graph)) < 0) - return ret; - break; - case AVMEDIA_TYPE_AUDIO: - if (!(filter = avfilter_get_by_name("resample"))) { - av_log(log_ctx, AV_LOG_ERROR, "'resample' filter " - "not present, cannot convert audio formats.\n"); - return AVERROR(EINVAL); - } - - snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d", - resampler_count++); - if ((ret = avfilter_graph_create_filter(&convert, - avfilter_get_by_name("resample"), - inst_name, NULL, NULL, graph)) < 0) - return ret; - break; - default: + AVFilterContext *convert; + AVFilter *filter; + AVFilterLink *inlink, *outlink; + char scale_args[256]; + char inst_name[30]; + + /* couldn't merge format lists. auto-insert conversion filter */ + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", + scaler_count++); + snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); + if ((ret = avfilter_graph_create_filter(&convert, + avfilter_get_by_name("scale"), + inst_name, scale_args, NULL, + graph)) < 0) + return ret; + break; + case AVMEDIA_TYPE_AUDIO: + if (!(filter = avfilter_get_by_name("resample"))) { + av_log(log_ctx, AV_LOG_ERROR, "'resample' filter " + "not present, cannot convert audio formats.\n"); return AVERROR(EINVAL); } - if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) - return ret; - - convert->filter->query_formats(convert); - inlink = convert->inputs[0]; - outlink = convert->outputs[0]; - if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || - !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) - ret |= AVERROR(ENOSYS); - if (inlink->type == AVMEDIA_TYPE_AUDIO && - (!ff_merge_samplerates(inlink->in_samplerates, - inlink->out_samplerates) || - !ff_merge_channel_layouts(inlink->in_channel_layouts, - inlink->out_channel_layouts))) - ret |= AVERROR(ENOSYS); - if (outlink->type == AVMEDIA_TYPE_AUDIO && - (!ff_merge_samplerates(outlink->in_samplerates, - outlink->out_samplerates) || - !ff_merge_channel_layouts(outlink->in_channel_layouts, - outlink->out_channel_layouts))) - ret |= AVERROR(ENOSYS); - - if (ret < 0) { - av_log(log_ctx, AV_LOG_ERROR, - "Impossible to convert between the formats supported by the filter " - "'%s' and the filter '%s'\n", link->src->name, link->dst->name); + snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d", + resampler_count++); + if ((ret = avfilter_graph_create_filter(&convert, + avfilter_get_by_name("resample"), + inst_name, NULL, NULL, graph)) < 0) return ret; - } + break; + default: + return AVERROR(EINVAL); + } + + if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) + return ret; + + convert->filter->query_formats(convert); + inlink = convert->inputs[0]; + outlink = convert->outputs[0]; + if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || + !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) + ret |= AVERROR(ENOSYS); + if (inlink->type == AVMEDIA_TYPE_AUDIO && + (!ff_merge_samplerates(inlink->in_samplerates, + inlink->out_samplerates) || + !ff_merge_channel_layouts(inlink->in_channel_layouts, + inlink->out_channel_layouts))) + ret |= AVERROR(ENOSYS); + if (outlink->type == AVMEDIA_TYPE_AUDIO && + (!ff_merge_samplerates(outlink->in_samplerates, + outlink->out_samplerates) || + !ff_merge_channel_layouts(outlink->in_channel_layouts, + outlink->out_channel_layouts))) + ret |= AVERROR(ENOSYS); + + if (ret < 0) { + av_log(log_ctx, AV_LOG_ERROR, + "Impossible to convert between the formats supported by the filter " + "'%s' and the filter '%s'\n", link->src->name, link->dst->name); + return ret; + } } } } -- cgit v1.2.3 From fad729fa505c0450482028c4a55c29fdc503dad7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 15:38:56 +0200 Subject: lavfi: rename vsrc_buffer.c to buffersrc.c Most of the code will be shared for both audio and video version. --- libavfilter/Makefile | 2 +- libavfilter/buffersrc.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/vsrc_buffer.c | 215 ---------------------------------------------- 3 files changed, 216 insertions(+), 216 deletions(-) create mode 100644 libavfilter/buffersrc.c delete mode 100644 libavfilter/vsrc_buffer.c (limited to 'libavfilter') diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 9cbb90847f..6a6bfd6811 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -15,12 +15,12 @@ OBJS = allfilters.o \ avfilter.o \ avfiltergraph.o \ buffersink.o \ + buffersrc.o \ defaults.o \ drawutils.o \ formats.o \ graphparser.o \ vf_scale.o \ - vsrc_buffer.o \ OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c new file mode 100644 index 0000000000..1ace368413 --- /dev/null +++ b/libavfilter/buffersrc.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2008 Vitor Sessak + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * memory buffer source filter + */ + +#include "avfilter.h" +#include "buffersrc.h" +#include "vsrc_buffer.h" +#include "libavutil/fifo.h" +#include "libavutil/imgutils.h" + +typedef struct { + AVFifoBuffer *fifo; + int h, w; + enum PixelFormat pix_fmt; + AVRational time_base; ///< time_base to set in the output link + AVRational pixel_aspect; + int eof; +} BufferSourceContext; + +#define CHECK_PARAM_CHANGE(s, c, width, height, format)\ + if (c->w != width || c->h != height || c->pix_fmt != format) {\ + av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ + return AVERROR(EINVAL);\ + } + +int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, + int64_t pts, AVRational pixel_aspect) +{ + BufferSourceContext *c = buffer_filter->priv; + AVFilterBufferRef *buf; + int ret; + + if (!frame) { + c->eof = 1; + return 0; + } else if (c->eof) + return AVERROR(EINVAL); + + if (!av_fifo_space(c->fifo) && + (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + + sizeof(buf))) < 0) + return ret; + + CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format); + + buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, + c->w, c->h); + av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, + c->pix_fmt, c->w, c->h); + + avfilter_copy_frame_props(buf, frame); + buf->pts = pts; + buf->video->pixel_aspect = pixel_aspect; + + if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) { + avfilter_unref_buffer(buf); + return ret; + } + + return 0; +} + +int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) +{ + BufferSourceContext *c = s->priv; + int ret; + + if (!buf) { + c->eof = 1; + return 0; + } else if (c->eof) + return AVERROR(EINVAL); + + if (!av_fifo_space(c->fifo) && + (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + + sizeof(buf))) < 0) + return ret; + + CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); + + if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) + return ret; + + return 0; +} + +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) +{ + BufferSourceContext *c = ctx->priv; + char pix_fmt_str[128]; + int n = 0; + + if (!args || + (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str, + &c->time_base.num, &c->time_base.den, + &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) { + av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args); + return AVERROR(EINVAL); + } + if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) { + char *tail; + c->pix_fmt = strtol(pix_fmt_str, &tail, 10); + if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) { + av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str); + return AVERROR(EINVAL); + } + } + + if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) + return AVERROR(ENOMEM); + + av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name); + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + BufferSourceContext *s = ctx->priv; + while (av_fifo_size(s->fifo)) { + AVFilterBufferRef *buf; + av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL); + avfilter_unref_buffer(buf); + } + av_fifo_free(s->fifo); + s->fifo = NULL; +} + +static int query_formats(AVFilterContext *ctx) +{ + BufferSourceContext *c = ctx->priv; + enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE }; + + avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); + return 0; +} + +static int config_props(AVFilterLink *link) +{ + BufferSourceContext *c = link->src->priv; + + link->w = c->w; + link->h = c->h; + link->sample_aspect_ratio = c->pixel_aspect; + link->time_base = c->time_base; + + return 0; +} + +static int request_frame(AVFilterLink *link) +{ + BufferSourceContext *c = link->src->priv; + AVFilterBufferRef *buf; + + if (!av_fifo_size(c->fifo)) { + if (c->eof) + return AVERROR_EOF; + return AVERROR(EAGAIN); + } + av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); + + avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); + avfilter_draw_slice(link, 0, link->h, 1); + avfilter_end_frame(link); + avfilter_unref_buffer(buf); + + return 0; +} + +static int poll_frame(AVFilterLink *link) +{ + BufferSourceContext *c = link->src->priv; + int size = av_fifo_size(c->fifo); + if (!size && c->eof) + return AVERROR_EOF; + return size/sizeof(AVFilterBufferRef*); +} + +AVFilter avfilter_vsrc_buffer = { + .name = "buffer", + .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), + .priv_size = sizeof(BufferSourceContext), + .query_formats = query_formats, + + .init = init, + .uninit = uninit, + + .inputs = (AVFilterPad[]) {{ .name = NULL }}, + .outputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = request_frame, + .poll_frame = poll_frame, + .config_props = config_props, }, + { .name = NULL}}, +}; diff --git a/libavfilter/vsrc_buffer.c b/libavfilter/vsrc_buffer.c deleted file mode 100644 index 1ace368413..0000000000 --- a/libavfilter/vsrc_buffer.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2008 Vitor Sessak - * - * This file is part of Libav. - * - * Libav is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * Libav is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * memory buffer source filter - */ - -#include "avfilter.h" -#include "buffersrc.h" -#include "vsrc_buffer.h" -#include "libavutil/fifo.h" -#include "libavutil/imgutils.h" - -typedef struct { - AVFifoBuffer *fifo; - int h, w; - enum PixelFormat pix_fmt; - AVRational time_base; ///< time_base to set in the output link - AVRational pixel_aspect; - int eof; -} BufferSourceContext; - -#define CHECK_PARAM_CHANGE(s, c, width, height, format)\ - if (c->w != width || c->h != height || c->pix_fmt != format) {\ - av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ - return AVERROR(EINVAL);\ - } - -int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, - int64_t pts, AVRational pixel_aspect) -{ - BufferSourceContext *c = buffer_filter->priv; - AVFilterBufferRef *buf; - int ret; - - if (!frame) { - c->eof = 1; - return 0; - } else if (c->eof) - return AVERROR(EINVAL); - - if (!av_fifo_space(c->fifo) && - (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + - sizeof(buf))) < 0) - return ret; - - CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format); - - buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, - c->w, c->h); - av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, - c->pix_fmt, c->w, c->h); - - avfilter_copy_frame_props(buf, frame); - buf->pts = pts; - buf->video->pixel_aspect = pixel_aspect; - - if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) { - avfilter_unref_buffer(buf); - return ret; - } - - return 0; -} - -int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) -{ - BufferSourceContext *c = s->priv; - int ret; - - if (!buf) { - c->eof = 1; - return 0; - } else if (c->eof) - return AVERROR(EINVAL); - - if (!av_fifo_space(c->fifo) && - (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + - sizeof(buf))) < 0) - return ret; - - CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); - - if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) - return ret; - - return 0; -} - -static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) -{ - BufferSourceContext *c = ctx->priv; - char pix_fmt_str[128]; - int n = 0; - - if (!args || - (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str, - &c->time_base.num, &c->time_base.den, - &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) { - av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args); - return AVERROR(EINVAL); - } - if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) { - char *tail; - c->pix_fmt = strtol(pix_fmt_str, &tail, 10); - if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) { - av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str); - return AVERROR(EINVAL); - } - } - - if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) - return AVERROR(ENOMEM); - - av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name); - return 0; -} - -static av_cold void uninit(AVFilterContext *ctx) -{ - BufferSourceContext *s = ctx->priv; - while (av_fifo_size(s->fifo)) { - AVFilterBufferRef *buf; - av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL); - avfilter_unref_buffer(buf); - } - av_fifo_free(s->fifo); - s->fifo = NULL; -} - -static int query_formats(AVFilterContext *ctx) -{ - BufferSourceContext *c = ctx->priv; - enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE }; - - avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); - return 0; -} - -static int config_props(AVFilterLink *link) -{ - BufferSourceContext *c = link->src->priv; - - link->w = c->w; - link->h = c->h; - link->sample_aspect_ratio = c->pixel_aspect; - link->time_base = c->time_base; - - return 0; -} - -static int request_frame(AVFilterLink *link) -{ - BufferSourceContext *c = link->src->priv; - AVFilterBufferRef *buf; - - if (!av_fifo_size(c->fifo)) { - if (c->eof) - return AVERROR_EOF; - return AVERROR(EAGAIN); - } - av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); - - avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); - avfilter_draw_slice(link, 0, link->h, 1); - avfilter_end_frame(link); - avfilter_unref_buffer(buf); - - return 0; -} - -static int poll_frame(AVFilterLink *link) -{ - BufferSourceContext *c = link->src->priv; - int size = av_fifo_size(c->fifo); - if (!size && c->eof) - return AVERROR_EOF; - return size/sizeof(AVFilterBufferRef*); -} - -AVFilter avfilter_vsrc_buffer = { - .name = "buffer", - .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), - .priv_size = sizeof(BufferSourceContext), - .query_formats = query_formats, - - .init = init, - .uninit = uninit, - - .inputs = (AVFilterPad[]) {{ .name = NULL }}, - .outputs = (AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, - .poll_frame = poll_frame, - .config_props = config_props, }, - { .name = NULL}}, -}; -- cgit v1.2.3 From 8b05e13df3b25e186adaf19cf84f5fa93d829214 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 6 May 2012 07:14:01 +0200 Subject: buffersrc: fix invalid read in uninit if the fifo hasn't been allocated --- libavfilter/buffersrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libavfilter') diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 1ace368413..c7284c1ff8 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -137,7 +137,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) static av_cold void uninit(AVFilterContext *ctx) { BufferSourceContext *s = ctx->priv; - while (av_fifo_size(s->fifo)) { + while (s->fifo && av_fifo_size(s->fifo)) { AVFilterBufferRef *buf; av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL); avfilter_unref_buffer(buf); -- cgit v1.2.3 From 720c6b78d1e8323d2df070e3da2f0ed305156c65 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 31 Dec 2011 16:40:43 +0100 Subject: buffersrc: add av_buffersrc_write_frame(). It's the same as av_vsrc_buffer_add_frame(), except it doesn't take pts or pixel_aspect parameters. Those are read from AVFrame. Deprecate av_vsrc_buffer_add_frame(). --- avconv.c | 3 +-- libavfilter/buffersrc.c | 20 ++++++++++++++++++-- libavfilter/buffersrc.h | 11 +++++++++++ libavfilter/version.h | 3 +++ libavfilter/vsrc_buffer.h | 2 ++ 5 files changed, 35 insertions(+), 4 deletions(-) (limited to 'libavfilter') diff --git a/avconv.c b/avconv.c index c157778869..fbe3827405 100644 --- a/avconv.c +++ b/avconv.c @@ -2357,8 +2357,7 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int buf->refcount++; av_buffersrc_buffer(ist->filters[i]->filter, fb); } else - av_vsrc_buffer_add_frame(ist->filters[i]->filter, decoded_frame, - decoded_frame->pts, decoded_frame->sample_aspect_ratio); + av_buffersrc_write_frame(ist->filters[i]->filter, decoded_frame); } av_free(buffer_to_free); diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index c7284c1ff8..58fc642a94 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -44,8 +44,26 @@ typedef struct { return AVERROR(EINVAL);\ } +#if FF_API_VSRC_BUFFER_ADD_FRAME int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect) +{ + int64_t orig_pts = frame->pts; + AVRational orig_sar = frame->sample_aspect_ratio; + int ret; + + frame->pts = pts; + frame->sample_aspect_ratio = pixel_aspect; + if ((ret = av_buffersrc_write_frame(buffer_filter, frame)) < 0) + return ret; + frame->pts = orig_pts; + frame->sample_aspect_ratio = orig_sar; + + return 0; +} +#endif + +int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame) { BufferSourceContext *c = buffer_filter->priv; AVFilterBufferRef *buf; @@ -70,8 +88,6 @@ int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, c->pix_fmt, c->w, c->h); avfilter_copy_frame_props(buf, frame); - buf->pts = pts; - buf->video->pixel_aspect = pixel_aspect; if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) { avfilter_unref_buffer(buf); diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 918a54faee..ca82a75df8 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -36,4 +36,15 @@ */ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf); +/** + * Add a frame to the buffer source. + * + * @param s an instance of the buffersrc filter. + * @param frame frame to be added. + * + * @warning frame data will be memcpy()ed, which may be a big performance + * hit. Use av_buffersrc_buffer() to avoid copying the data. + */ +int av_buffersrc_write_frame(AVFilterContext *s, AVFrame *frame); + #endif /* AVFILTER_BUFFERSRC_H */ diff --git a/libavfilter/version.h b/libavfilter/version.h index 71928f3f3b..967d40d919 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -50,5 +50,8 @@ #ifndef FF_API_SAMPLERATE64 #define FF_API_SAMPLERATE64 (LIBAVFILTER_VERSION_MAJOR < 3) #endif +#ifndef FF_API_VSRC_BUFFER_ADD_FRAME +#define FF_API_VSRC_BUFFER_ADD_FRAME (LIBAVFILTER_VERSION_MAJOR < 3) +#endif #endif // AVFILTER_VERSION_H diff --git a/libavfilter/vsrc_buffer.h b/libavfilter/vsrc_buffer.h index 13a209c768..cbcc6305bb 100644 --- a/libavfilter/vsrc_buffer.h +++ b/libavfilter/vsrc_buffer.h @@ -29,7 +29,9 @@ #include "libavcodec/avcodec.h" /* AVFrame */ #include "avfilter.h" +#if FF_API_VSRC_BUFFER_ADD_FRAME int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect); +#endif #endif /* AVFILTER_VSRC_BUFFER_H */ -- cgit v1.2.3 From 4c66c4071830e74afa1aea3df52059ab163c1ddb Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 18:57:04 +0200 Subject: lavfi: add an audio buffer source. --- doc/filters.texi | 27 ++++++ libavfilter/allfilters.c | 4 + libavfilter/buffersrc.c | 211 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 222 insertions(+), 20 deletions(-) (limited to 'libavfilter') diff --git a/doc/filters.texi b/doc/filters.texi index 8eff84a0e4..8d4242607a 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -151,6 +151,33 @@ anullsrc=48000:4 anullsrc=48000:mono @end example +@section abuffer +Buffer audio frames, and make them available to the filter chain. + +This source is not intended to be part of user-supplied graph descriptions but +for insertion by calling programs through the interface defined in +@file{libavfilter/buffersrc.h}. + +It accepts the following named parameters: +@table @option + +@item time_base +Timebase which will be used for timestamps of submitted frames. It must be +either a floating-point number or in @var{numerator}/@var{denominator} form. + +@item sample_rate +Audio sample rate. + +@item sample_fmt +Name of the sample format, as returned by @code{av_get_sample_fmt_name()}. + +@item channel_layout +Channel layout of the audio data, in the form that can be accepted by +@code{av_get_channel_layout()}. +@end table + +All the parameters need to be explicitly defined. + @c man end AUDIO SOURCES @chapter Audio Sinks diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 66d890f161..25cd8222c3 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -95,6 +95,10 @@ void avfilter_register_all(void) extern AVFilter avfilter_vsrc_buffer; avfilter_register(&avfilter_vsrc_buffer); } + { + extern AVFilter avfilter_asrc_abuffer; + avfilter_register(&avfilter_asrc_abuffer); + } { extern AVFilter avfilter_vsink_buffer; avfilter_register(&avfilter_vsink_buffer); diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 58fc642a94..ca9390aa5a 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -23,27 +23,51 @@ * memory buffer source filter */ +#include "audio.h" #include "avfilter.h" #include "buffersrc.h" +#include "formats.h" #include "vsrc_buffer.h" + +#include "libavutil/audioconvert.h" #include "libavutil/fifo.h" #include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/samplefmt.h" typedef struct { + const AVClass *class; AVFifoBuffer *fifo; + AVRational time_base; ///< time_base to set in the output link + + /* video only */ int h, w; enum PixelFormat pix_fmt; - AVRational time_base; ///< time_base to set in the output link AVRational pixel_aspect; + + /* audio only */ + int sample_rate; + enum AVSampleFormat sample_fmt; + char *sample_fmt_str; + uint64_t channel_layout; + char *channel_layout_str; + int eof; } BufferSourceContext; -#define CHECK_PARAM_CHANGE(s, c, width, height, format)\ +#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\ if (c->w != width || c->h != height || c->pix_fmt != format) {\ av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ return AVERROR(EINVAL);\ } +#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\ + if (c->sample_fmt != format || c->sample_rate != srate ||\ + c->channel_layout != ch_layout) {\ + av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ + return AVERROR(EINVAL);\ + } + #if FF_API_VSRC_BUFFER_ADD_FRAME int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect) @@ -80,12 +104,28 @@ int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame) sizeof(buf))) < 0) return ret; - CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format); - - buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, - c->w, c->h); - av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, - c->pix_fmt, c->w, c->h); + switch (buffer_filter->outputs[0]->type) { + case AVMEDIA_TYPE_VIDEO: + CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, + frame->format); + buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, + c->w, c->h); + av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, + c->pix_fmt, c->w, c->h); + break; + case AVMEDIA_TYPE_AUDIO: + CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout, + frame->format); + buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, + frame->nb_samples); + av_samples_copy(buf->extended_data, frame->extended_data, + 0, 0, frame->nb_samples, + av_get_channel_layout_nb_channels(frame->channel_layout), + frame->format); + break; + default: + return AVERROR(EINVAL); + } avfilter_copy_frame_props(buf, frame); @@ -113,7 +153,17 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) sizeof(buf))) < 0) return ret; - CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); + switch (s->outputs[0]->type) { + case AVMEDIA_TYPE_VIDEO: + CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); + break; + case AVMEDIA_TYPE_AUDIO: + CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout, + buf->format); + break; + default: + return AVERROR(EINVAL); + } if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) return ret; @@ -121,7 +171,7 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) return 0; } -static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) +static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque) { BufferSourceContext *c = ctx->priv; char pix_fmt_str[128]; @@ -150,6 +200,69 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) return 0; } +#define OFFSET(x) offsetof(BufferSourceContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM +static const AVOption audio_options[] = { + { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, A }, + { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { 0 }, 0, INT_MAX, A }, + { "sample_fmt", NULL, OFFSET(sample_fmt_str), AV_OPT_TYPE_STRING, .flags = A }, + { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, + { NULL }, +}; + +static const AVClass abuffer_class = { + .class_name = "abuffer source", + .item_name = av_default_item_name, + .option = audio_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static av_cold int init_audio(AVFilterContext *ctx, const char *args, void *opaque) +{ + BufferSourceContext *s = ctx->priv; + int ret = 0; + + s->class = &abuffer_class; + av_opt_set_defaults(s); + + if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args); + goto fail; + } + + s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str); + if (s->sample_fmt == AV_SAMPLE_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n", + s->sample_fmt_str); + ret = AVERROR(EINVAL); + goto fail; + } + + s->channel_layout = av_get_channel_layout(s->channel_layout_str); + if (!s->channel_layout) { + av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n", + s->channel_layout_str); + ret = AVERROR(EINVAL); + goto fail; + } + + if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (!s->time_base.num) + s->time_base = (AVRational){1, s->sample_rate}; + + av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d " + "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str, + s->sample_rate, s->channel_layout_str); + +fail: + av_opt_free(s); + return ret; +} + static av_cold void uninit(AVFilterContext *ctx) { BufferSourceContext *s = ctx->priv; @@ -165,9 +278,29 @@ static av_cold void uninit(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx) { BufferSourceContext *c = ctx->priv; - enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE }; + AVFilterChannelLayouts *channel_layouts = NULL; + AVFilterFormats *formats = NULL; + AVFilterFormats *samplerates = NULL; + + switch (ctx->outputs[0]->type) { + case AVMEDIA_TYPE_VIDEO: + avfilter_add_format(&formats, c->pix_fmt); + avfilter_set_common_formats(ctx, formats); + break; + case AVMEDIA_TYPE_AUDIO: + avfilter_add_format(&formats, c->sample_fmt); + avfilter_set_common_formats(ctx, formats); + + avfilter_add_format(&samplerates, c->sample_rate); + ff_set_common_samplerates(ctx, samplerates); + + ff_add_channel_layout(&channel_layouts, c->channel_layout); + ff_set_common_channel_layouts(ctx, channel_layouts); + break; + default: + return AVERROR(EINVAL); + } - avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); return 0; } @@ -175,11 +308,21 @@ static int config_props(AVFilterLink *link) { BufferSourceContext *c = link->src->priv; - link->w = c->w; - link->h = c->h; - link->sample_aspect_ratio = c->pixel_aspect; - link->time_base = c->time_base; + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + link->w = c->w; + link->h = c->h; + link->sample_aspect_ratio = c->pixel_aspect; + break; + case AVMEDIA_TYPE_AUDIO: + link->channel_layout = c->channel_layout; + link->sample_rate = c->sample_rate; + break; + default: + return AVERROR(EINVAL); + } + link->time_base = c->time_base; return 0; } @@ -195,9 +338,19 @@ static int request_frame(AVFilterLink *link) } av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); - avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); - avfilter_draw_slice(link, 0, link->h, 1); - avfilter_end_frame(link); + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); + avfilter_draw_slice(link, 0, link->h, 1); + avfilter_end_frame(link); + break; + case AVMEDIA_TYPE_AUDIO: + ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); + break; + default: + return AVERROR(EINVAL); + } + avfilter_unref_buffer(buf); return 0; @@ -218,7 +371,7 @@ AVFilter avfilter_vsrc_buffer = { .priv_size = sizeof(BufferSourceContext), .query_formats = query_formats, - .init = init, + .init = init_video, .uninit = uninit, .inputs = (AVFilterPad[]) {{ .name = NULL }}, @@ -229,3 +382,21 @@ AVFilter avfilter_vsrc_buffer = { .config_props = config_props, }, { .name = NULL}}, }; + +AVFilter avfilter_asrc_abuffer = { + .name = "abuffer", + .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), + .priv_size = sizeof(BufferSourceContext), + .query_formats = query_formats, + + .init = init_audio, + .uninit = uninit, + + .inputs = (AVFilterPad[]) {{ .name = NULL }}, + .outputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .poll_frame = poll_frame, + .config_props = config_props, }, + { .name = NULL}}, +}; -- cgit v1.2.3 From a2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 19:22:38 +0200 Subject: lavfi: add an audio buffer sink. --- doc/filters.texi | 7 ++++ libavfilter/allfilters.c | 4 ++ libavfilter/buffersink.c | 102 +++++++++++++++++++++++++++++++++++++++++++++-- libavfilter/buffersink.h | 21 +++++++++- 4 files changed, 129 insertions(+), 5 deletions(-) (limited to 'libavfilter') diff --git a/doc/filters.texi b/doc/filters.texi index 8d4242607a..0314bfaf20 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -191,6 +191,13 @@ Null audio sink, do absolutely nothing with the input audio. It is mainly useful as a template and to be employed in analysis / debugging tools. +@section abuffersink +This sink is intended for programmatic use. Frames that arrive on this sink can +be retrieved by the calling program using the interface defined in +@file{libavfilter/buffersink.h}. + +This filter accepts no parameters. + @c man end AUDIO SINKS @chapter Video Filters diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 25cd8222c3..c84b3f2587 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -103,6 +103,10 @@ void avfilter_register_all(void) extern AVFilter avfilter_vsink_buffer; avfilter_register(&avfilter_vsink_buffer); } + { + extern AVFilter avfilter_asink_abuffer; + avfilter_register(&avfilter_asink_abuffer); + } { extern AVFilter avfilter_vf_scale; avfilter_register(&avfilter_vf_scale); diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index e4cbe3be42..8787268f4c 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -23,13 +23,20 @@ * buffer sink */ +#include "libavutil/audio_fifo.h" +#include "libavutil/audioconvert.h" #include "libavutil/fifo.h" +#include "libavutil/mathematics.h" +#include "audio.h" #include "avfilter.h" #include "buffersink.h" typedef struct { - AVFifoBuffer *fifo; ///< FIFO buffer of video frame references + AVFifoBuffer *fifo; ///< FIFO buffer of frame references + + AVAudioFifo *audio_fifo; ///< FIFO for audio samples + int64_t next_pts; ///< interpolating audio pts } BufferSinkContext; #define FIFO_INIT_SIZE 8 @@ -44,6 +51,9 @@ static av_cold void uninit(AVFilterContext *ctx) avfilter_unref_buffer(buf); } av_fifo_free(sink->fifo); + + if (sink->audio_fifo) + av_audio_fifo_free(sink->audio_fifo); } static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) @@ -58,9 +68,8 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) return 0; } -static void end_frame(AVFilterLink *link) +static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf) { - AVFilterContext *ctx = link->dst; BufferSinkContext *sink = ctx->priv; if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) && @@ -69,10 +78,20 @@ static void end_frame(AVFilterLink *link) return; } - av_fifo_generic_write(sink->fifo, &link->cur_buf, sizeof(link->cur_buf), NULL); + av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL); +} + +static void end_frame(AVFilterLink *link) +{ + write_buf(link->dst, link->cur_buf); link->cur_buf = NULL; } +static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +{ + write_buf(link->dst, buf); +} + int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) { BufferSinkContext *sink = ctx->priv; @@ -98,6 +117,66 @@ int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) return 0; } +static int read_from_fifo(AVFilterContext *ctx, AVFilterBufferRef **pbuf, + int nb_samples) +{ + BufferSinkContext *s = ctx->priv; + AVFilterLink *link = ctx->inputs[0]; + AVFilterBufferRef *buf; + + if (!(buf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples))) + return AVERROR(ENOMEM); + av_audio_fifo_read(s->audio_fifo, (void**)buf->extended_data, nb_samples); + + buf->pts = s->next_pts; + s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate}, + link->time_base); + + *pbuf = buf; + return 0; + +} + +int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf, + int nb_samples) +{ + BufferSinkContext *s = ctx->priv; + AVFilterLink *link = ctx->inputs[0]; + int ret = 0; + + if (!s->audio_fifo) { + int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); + if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples))) + return AVERROR(ENOMEM); + } + + while (ret >= 0) { + AVFilterBufferRef *buf; + + if (av_audio_fifo_size(s->audio_fifo) >= nb_samples) + return read_from_fifo(ctx, pbuf, nb_samples); + + ret = av_buffersink_read(ctx, &buf); + if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) + return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo)); + else if (ret < 0) + return ret; + + if (buf->pts != AV_NOPTS_VALUE) { + s->next_pts = buf->pts - + av_rescale_q(av_audio_fifo_size(s->audio_fifo), + (AVRational){ 1, link->sample_rate }, + link->time_base); + } + + ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data, + buf->audio->nb_samples); + avfilter_unref_buffer(buf); + } + + return ret; +} + AVFilter avfilter_vsink_buffer = { .name = "buffersink", .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), @@ -112,3 +191,18 @@ AVFilter avfilter_vsink_buffer = { { .name = NULL }}, .outputs = (AVFilterPad[]) {{ .name = NULL }}, }; + +AVFilter avfilter_asink_abuffer = { + .name = "abuffersink", + .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), + .priv_size = sizeof(BufferSinkContext), + .init = init, + .uninit = uninit, + + .inputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_samples = filter_samples, + .min_perms = AV_PERM_READ, }, + { .name = NULL }}, + .outputs = (AVFilterPad[]) {{ .name = NULL }}, +}; diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h index e579b9ad03..8f94a9c94d 100644 --- a/libavfilter/buffersink.h +++ b/libavfilter/buffersink.h @@ -29,7 +29,7 @@ /** * Get a buffer with filtered data from sink and put it in buf. * - * @param sink pointer to a context of a buffersink AVFilter. + * @param sink pointer to a context of a buffersink or abuffersink AVFilter. * @param buf pointer to the buffer will be written here if buf is non-NULL. buf * must be freed by the caller using avfilter_unref_buffer(). * Buf may also be NULL to query whether a buffer is ready to be @@ -40,4 +40,23 @@ */ int av_buffersink_read(AVFilterContext *sink, AVFilterBufferRef **buf); +/** + * Same as av_buffersink_read, but with the ability to specify the number of + * samples read. This function is less efficient than av_buffersink_read(), + * because it copies the data around. + * + * @param sink pointer to a context of the abuffersink AVFilter. + * @param buf pointer to the buffer will be written here if buf is non-NULL. buf + * must be freed by the caller using avfilter_unref_buffer(). buf + * will contain exactly nb_samples audio samples, except at the end + * of stream, when it can contain less than nb_samples. + * Buf may also be NULL to query whether a buffer is ready to be + * output. + * + * @warning do not mix this function with av_buffersink_read(). Use only one or + * the other with a single sink, not both. + */ +int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf, + int nb_samples); + #endif /* AVFILTER_BUFFERSINK_H */ -- cgit v1.2.3 From fb604ae8500d4ee7de6af61387c11618b3dea25b Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 6 May 2012 09:00:53 +0200 Subject: lavfi: add aformat filter Based on a patch by Mina Nagy Zaki --- doc/filters.texi | 26 +++++++++ libavfilter/Makefile | 1 + libavfilter/af_aformat.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 176 insertions(+) create mode 100644 libavfilter/af_aformat.c (limited to 'libavfilter') diff --git a/doc/filters.texi b/doc/filters.texi index 0314bfaf20..f066657add 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -107,6 +107,32 @@ build. Below is a description of the currently available audio filters. +@section aformat + +Convert the input audio to one of the specified formats. The framework will +negotiate the most appropriate format to minimize conversions. + +The filter accepts the following named parameters: +@table @option + +@item sample_fmts +A comma-separated list of requested sample formats. + +@item sample_rates +A comma-separated list of requested sample rates. + +@item channel_layouts +A comma-separated list of requested channel layouts. + +@end table + +If a parameter is omitted, all values are allowed. + +For example to force the output to either unsigned 8-bit or signed 16-bit stereo: +@example +aformat=sample_fmts\=u8\,s16:channel_layouts\=stereo +@end example + @section anull Pass the audio source unchanged to the output. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 6a6bfd6811..df75bd5e74 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -22,6 +22,7 @@ OBJS = allfilters.o \ graphparser.o \ vf_scale.o \ +OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c new file mode 100644 index 0000000000..84442d379e --- /dev/null +++ b/libavfilter/af_aformat.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011 Mina Nagy Zaki + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * format audio filter + */ + +#include "libavutil/audioconvert.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" + +#include "audio.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" + +typedef struct AFormatContext { + const AVClass *class; + + AVFilterFormats *formats; + AVFilterFormats *sample_rates; + AVFilterChannelLayouts *channel_layouts; + + char *formats_str; + char *sample_rates_str; + char *channel_layouts_str; +} AFormatContext; + +#define OFFSET(x) offsetof(AFormatContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM +static const AVOption options[] = { + { "sample_fmts", "A comma-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A }, + { "sample_rates", "A comma-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A }, + { "channel_layouts", "A comma-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A }, + { NULL }, +}; + +static const AVClass aformat_class = { + .class_name = "aformat filter", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +#define PARSE_FORMATS(str, type, list, add_to_list, get_fmt, none, desc) \ +do { \ + char *next, *cur = str; \ + while (cur) { \ + type fmt; \ + next = strchr(cur, ','); \ + if (next) \ + *next++ = 0; \ + \ + if ((fmt = get_fmt(cur)) == none) { \ + av_log(ctx, AV_LOG_ERROR, "Error parsing " desc ": %s.\n", cur);\ + ret = AVERROR(EINVAL); \ + goto fail; \ + } \ + add_to_list(&list, fmt); \ + \ + cur = next; \ + } \ +} while (0) + +static int get_sample_rate(const char *samplerate) +{ + int ret = strtol(samplerate, NULL, 0); + return FFMAX(ret, 0); +} + +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) +{ + AFormatContext *s = ctx->priv; + int ret; + + if (!args) { + av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n"); + return AVERROR(EINVAL); + } + + s->class = &aformat_class; + av_opt_set_defaults(s); + + if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args); + return ret; + } + + PARSE_FORMATS(s->formats_str, enum AVSampleFormat, s->formats, + avfilter_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format"); + PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, avfilter_add_format, + get_sample_rate, 0, "sample rate"); + PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts, + ff_add_channel_layout, av_get_channel_layout, 0, + "channel layout"); + +fail: + av_opt_free(s); + return ret; +} + +static int query_formats(AVFilterContext *ctx) +{ + AFormatContext *s = ctx->priv; + + avfilter_set_common_formats(ctx, s->formats ? s->formats : + avfilter_all_formats(AVMEDIA_TYPE_AUDIO)); + ff_set_common_samplerates(ctx, s->sample_rates ? s->sample_rates : + ff_all_samplerates()); + ff_set_common_channel_layouts(ctx, s->channel_layouts ? s->channel_layouts : + ff_all_channel_layouts()); + + return 0; +} + +AVFilter avfilter_af_aformat = { + .name = "aformat", + .description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), + .init = init, + .query_formats = query_formats, + .priv_size = sizeof(AFormatContext), + + .inputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_samples = ff_null_filter_samples }, + { .name = NULL}}, + .outputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO}, + { .name = NULL}}, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index c84b3f2587..4f5f852b8b 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -34,6 +34,7 @@ void avfilter_register_all(void) return; initialized = 1; + REGISTER_FILTER (AFORMAT, aformat, af); REGISTER_FILTER (ANULL, anull, af); REGISTER_FILTER (RESAMPLE, resample, af); -- cgit v1.2.3 From 9f26421b0be2af36b5405608f4e7429b4bd7fbdb Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 8 May 2012 16:33:50 +0200 Subject: lavfi: add asyncts filter. --- doc/filters.texi | 19 ++++ libavfilter/Makefile | 2 + libavfilter/af_asyncts.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 259 insertions(+) create mode 100644 libavfilter/af_asyncts.c (limited to 'libavfilter') diff --git a/doc/filters.texi b/doc/filters.texi index f066657add..0e611d2793 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -137,6 +137,25 @@ aformat=sample_fmts\=u8\,s16:channel_layouts\=stereo Pass the audio source unchanged to the output. +@section asyncts +Synchronize audio data with timestamps by squeezing/stretching it and/or +dropping samples/adding silence when needed. + +The filter accepts the following named parameters: +@table @option + +@item compensate +Enable stretching/squeezing the data to make it match the timestamps. + +@item min_delta +Minimum difference between timestamps and audio data (in seconds) to trigger +adding/dropping samples. + +@item max_comp +Maximum compensation in samples per second. + +@end table + @section resample Convert the audio sample format, sample rate and channel layout. This filter is not meant to be used directly, it is inserted automatically by libavfilter diff --git a/libavfilter/Makefile b/libavfilter/Makefile index df75bd5e74..a90d8a02b1 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -1,5 +1,6 @@ NAME = avfilter FFLIBS = avutil swscale +FFLIBS-$(CONFIG_ASYNCTS_FILTER) += avresample FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec FFLIBS-$(CONFIG_RESAMPLE_FILTER) += avresample @@ -24,6 +25,7 @@ OBJS = allfilters.o \ OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o +OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c new file mode 100644 index 0000000000..5cde0bf00a --- /dev/null +++ b/libavfilter/af_asyncts.c @@ -0,0 +1,237 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavresample/avresample.h" +#include "libavutil/audio_fifo.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include "libavutil/samplefmt.h" + +#include "audio.h" +#include "avfilter.h" + +typedef struct ASyncContext { + const AVClass *class; + + AVAudioResampleContext *avr; + int64_t pts; ///< timestamp in samples of the first sample in fifo + int min_delta; ///< pad/trim min threshold in samples + + /* options */ + int resample; + float min_delta_sec; + int max_comp; +} ASyncContext; + +#define OFFSET(x) offsetof(ASyncContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM +static const AVOption options[] = { + { "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { 0 }, 0, 1, A }, + { "min_delta", "Minimum difference between timestamps and audio data " + "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { 0.1 }, 0, INT_MAX, A }, + { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { 500 }, 0, INT_MAX, A }, + { NULL }, +}; + +static const AVClass async_class = { + .class_name = "asyncts filter", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static int init(AVFilterContext *ctx, const char *args, void *opaque) +{ + ASyncContext *s = ctx->priv; + int ret; + + s->class = &async_class; + av_opt_set_defaults(s); + + if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args); + return ret; + } + av_opt_free(s); + + s->pts = AV_NOPTS_VALUE; + + return 0; +} + +static void uninit(AVFilterContext *ctx) +{ + ASyncContext *s = ctx->priv; + + if (s->avr) { + avresample_close(s->avr); + avresample_free(&s->avr); + } +} + +static int config_props(AVFilterLink *link) +{ + ASyncContext *s = link->src->priv; + int ret; + + s->min_delta = s->min_delta_sec * link->sample_rate; + link->time_base = (AVRational){1, link->sample_rate}; + + s->avr = avresample_alloc_context(); + if (!s->avr) + return AVERROR(ENOMEM); + + av_opt_set_int(s->avr, "in_channel_layout", link->channel_layout, 0); + av_opt_set_int(s->avr, "out_channel_layout", link->channel_layout, 0); + av_opt_set_int(s->avr, "in_sample_fmt", link->format, 0); + av_opt_set_int(s->avr, "out_sample_fmt", link->format, 0); + av_opt_set_int(s->avr, "in_sample_rate", link->sample_rate, 0); + av_opt_set_int(s->avr, "out_sample_rate", link->sample_rate, 0); + + if (s->resample) + av_opt_set_int(s->avr, "force_resampling", 1, 0); + + if ((ret = avresample_open(s->avr)) < 0) + return ret; + + return 0; +} + +static int request_frame(AVFilterLink *link) +{ + AVFilterContext *ctx = link->src; + ASyncContext *s = ctx->priv; + int ret = avfilter_request_frame(ctx->inputs[0]); + int nb_samples; + + /* flush the fifo */ + if (ret == AVERROR_EOF && (nb_samples = avresample_get_delay(s->avr))) { + AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE, + nb_samples); + if (!buf) + return AVERROR(ENOMEM); + avresample_convert(s->avr, (void**)buf->extended_data, buf->linesize[0], + nb_samples, NULL, 0, 0); + buf->pts = s->pts; + ff_filter_samples(link, buf); + return 0; + } + + return ret; +} + +static void write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) +{ + avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); + avfilter_unref_buffer(buf); +} + +/* get amount of data currently buffered, in samples */ +static int64_t get_delay(ASyncContext *s) +{ + return avresample_available(s->avr) + avresample_get_delay(s->avr); +} + +static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +{ + AVFilterContext *ctx = inlink->dst; + ASyncContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + int nb_channels = av_get_channel_layout_nb_channels(buf->audio->channel_layout); + int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts : + av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); + int out_size; + int64_t delta; + + /* buffer data until we get the first timestamp */ + if (s->pts == AV_NOPTS_VALUE) { + if (pts != AV_NOPTS_VALUE) { + s->pts = pts - get_delay(s); + } + write_to_fifo(s, buf); + return; + } + + /* now wait for the next timestamp */ + if (pts == AV_NOPTS_VALUE) { + write_to_fifo(s, buf); + return; + } + + /* when we have two timestamps, compute how many samples would we have + * to add/remove to get proper sync between data and timestamps */ + delta = pts - s->pts - get_delay(s); + out_size = avresample_available(s->avr); + + if (labs(delta) > s->min_delta) { + av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta); + out_size += delta; + } else if (s->resample) { + int comp = av_clip(delta, -s->max_comp, s->max_comp); + av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp); + avresample_set_compensation(s->avr, delta, inlink->sample_rate); + } + + if (out_size > 0) { + AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, + out_size); + if (!buf_out) + return; + + avresample_read(s->avr, (void**)buf_out->extended_data, out_size); + buf_out->pts = s->pts; + + if (delta > 0) { + av_samples_set_silence(buf_out->extended_data, out_size - delta, + delta, nb_channels, buf->format); + } + ff_filter_samples(outlink, buf_out); + } else { + av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " + "whole buffer.\n"); + } + + /* drain any remaining buffered data */ + avresample_read(s->avr, NULL, avresample_available(s->avr)); + + s->pts = pts - avresample_get_delay(s->avr); + avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); + avfilter_unref_buffer(buf); +} + +AVFilter avfilter_af_asyncts = { + .name = "asyncts", + .description = NULL_IF_CONFIG_SMALL("Sync audio data to timestamps"), + + .init = init, + .uninit = uninit, + + .priv_size = sizeof(ASyncContext), + + .inputs = (const AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_samples = filter_samples }, + { NULL }}, + .outputs = (const AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_props, + .request_frame = request_frame }, + { NULL }}, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 4f5f852b8b..3fa0152d86 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -36,6 +36,7 @@ void avfilter_register_all(void) REGISTER_FILTER (AFORMAT, aformat, af); REGISTER_FILTER (ANULL, anull, af); + REGISTER_FILTER (ASYNCTS, asyncts, af); REGISTER_FILTER (RESAMPLE, resample, af); REGISTER_FILTER (ANULLSRC, anullsrc, asrc); -- cgit v1.2.3 From c5432d3ca4af629cea713c7613d22f5c451d41ab Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 10 May 2012 07:36:10 +0200 Subject: lavfi: move video-related functions to a separate file. This is easier to follow than having them randomly scattered in avfilter.c and defaults.c. --- libavfilter/Makefile | 1 + libavfilter/avfilter.c | 184 ------------------------------- libavfilter/defaults.c | 87 --------------- libavfilter/video.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+), 271 deletions(-) create mode 100644 libavfilter/video.c (limited to 'libavfilter') diff --git a/libavfilter/Makefile b/libavfilter/Makefile index a90d8a02b1..12819cbb06 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -22,6 +22,7 @@ OBJS = allfilters.o \ formats.o \ graphparser.o \ vf_scale.o \ + video.o \ OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 57108b13ce..9dacf70e22 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -248,35 +248,6 @@ static char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms) } #endif -static void ff_dlog_ref(void *ctx, AVFilterBufferRef *ref, int end) -{ - av_unused char buf[16]; - av_dlog(ctx, - "ref[%p buf:%p refcount:%d perms:%s data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64, - ref, ref->buf, ref->buf->refcount, ff_get_ref_perms_string(buf, sizeof(buf), ref->perms), ref->data[0], - ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3], - ref->pts, ref->pos); - - if (ref->video) { - av_dlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c", - ref->video->pixel_aspect.num, ref->video->pixel_aspect.den, - ref->video->w, ref->video->h, - !ref->video->interlaced ? 'P' : /* Progressive */ - ref->video->top_field_first ? 'T' : 'B', /* Top / Bottom */ - ref->video->key_frame, - av_get_picture_type_char(ref->video->pict_type)); - } - if (ref->audio) { - av_dlog(ctx, " cl:%"PRId64"d n:%d r:%d p:%d", - ref->audio->channel_layout, - ref->audio->nb_samples, - ref->audio->sample_rate, - ref->audio->planar); - } - - av_dlog(ctx, "]%s", end ? "\n" : ""); -} - void ff_dlog_link(void *ctx, AVFilterLink *link, int end) { if (link->type == AVMEDIA_TYPE_VIDEO) { @@ -301,71 +272,6 @@ void ff_dlog_link(void *ctx, AVFilterLink *link, int end) } } -AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h) -{ - AVFilterBufferRef *ret = NULL; - - av_unused char buf[16]; - FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); - av_dlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h); - - if (link->dstpad->get_video_buffer) - ret = link->dstpad->get_video_buffer(link, perms, w, h); - - if (!ret) - ret = avfilter_default_get_video_buffer(link, perms, w, h); - - if (ret) - ret->type = AVMEDIA_TYPE_VIDEO; - - FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " returning "); ff_dlog_ref(NULL, ret, 1); - - return ret; -} - -AVFilterBufferRef * -avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms, - int w, int h, enum PixelFormat format) -{ - AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer)); - AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef)); - - if (!pic || !picref) - goto fail; - - picref->buf = pic; - picref->buf->free = ff_avfilter_default_free_buffer; - if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps)))) - goto fail; - - pic->w = picref->video->w = w; - pic->h = picref->video->h = h; - - /* make sure the buffer gets read permission or it's useless for output */ - picref->perms = perms | AV_PERM_READ; - - pic->refcount = 1; - picref->type = AVMEDIA_TYPE_VIDEO; - pic->format = picref->format = format; - - memcpy(pic->data, data, 4*sizeof(data[0])); - memcpy(pic->linesize, linesize, 4*sizeof(linesize[0])); - memcpy(picref->data, pic->data, sizeof(picref->data)); - memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize)); - - pic-> extended_data = pic->data; - picref->extended_data = picref->data; - - return picref; - -fail: - if (picref && picref->video) - av_free(picref->video); - av_free(picref); - av_free(pic); - return NULL; -} - int avfilter_request_frame(AVFilterLink *link) { FF_DPRINTF_START(NULL, request_frame); ff_dlog_link(NULL, link, 1); @@ -395,96 +301,6 @@ int avfilter_poll_frame(AVFilterLink *link) 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, AVFilterBufferRef *picref) -{ - void (*start_frame)(AVFilterLink *, AVFilterBufferRef *); - AVFilterPad *dst = link->dstpad; - int perms = picref->perms; - - FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1); - - if (!(start_frame = dst->start_frame)) - start_frame = avfilter_default_start_frame; - - if (picref->linesize[0] < 0) - perms |= AV_PERM_NEG_LINESIZES; - /* prepare to copy the picture if it has insufficient permissions */ - if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) { - av_log(link->dst, AV_LOG_DEBUG, - "frame copy needed (have perms %x, need %x, reject %x)\n", - picref->perms, - link->dstpad->min_perms, link->dstpad->rej_perms); - - link->cur_buf = avfilter_get_video_buffer(link, dst->min_perms, link->w, link->h); - link->src_buf = picref; - avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf); - } - else - link->cur_buf = picref; - - start_frame(link, link->cur_buf); -} - -void avfilter_end_frame(AVFilterLink *link) -{ - void (*end_frame)(AVFilterLink *); - - if (!(end_frame = link->dstpad->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->src_buf) { - avfilter_unref_buffer(link->src_buf); - link->src_buf = NULL; - } -} - -void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) -{ - uint8_t *src[4], *dst[4]; - int i, j, vsub; - void (*draw_slice)(AVFilterLink *, int, int, int); - - FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir); - - /* copy the slice if needed for permission reasons */ - if (link->src_buf) { - vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; - - for (i = 0; i < 4; i++) { - if (link->src_buf->data[i]) { - src[i] = link->src_buf-> data[i] + - (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i]; - dst[i] = link->cur_buf->data[i] + - (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i]; - } else - src[i] = dst[i] = NULL; - } - - for (i = 0; i < 4; i++) { - int planew = - av_image_get_linesize(link->format, link->cur_buf->video->w, i); - - if (!src[i]) continue; - - for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) { - memcpy(dst[i], src[i], planew); - src[i] += link->src_buf->linesize[i]; - dst[i] += link->cur_buf->linesize[i]; - } - } - } - - if (!(draw_slice = link->dstpad->draw_slice)) - draw_slice = avfilter_default_draw_slice; - draw_slice(link, y, h, slice_dir); -} - #define MAX_REGISTERED_AVFILTERS_NB 64 static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1]; diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c index cb7bf1c4ef..9829cdcff4 100644 --- a/libavfilter/defaults.c +++ b/libavfilter/defaults.c @@ -36,73 +36,6 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr) av_free(ptr); } -/* 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. */ -AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h) -{ - int linesize[4]; - uint8_t *data[4]; - AVFilterBufferRef *picref = NULL; - - // +2 is needed for swscaler, +16 to be SIMD-friendly - if (av_image_alloc(data, linesize, w, h, link->format, 16) < 0) - return NULL; - - picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize, - perms, w, h, link->format); - if (!picref) { - av_free(data[0]); - return NULL; - } - - return picref; -} - -void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) -{ - AVFilterLink *outlink = NULL; - - if (inlink->dst->output_count) - outlink = inlink->dst->outputs[0]; - - if (outlink) { - outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); - avfilter_copy_buffer_ref_props(outlink->out_buf, picref); - avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0)); - } -} - -void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) -{ - AVFilterLink *outlink = NULL; - - if (inlink->dst->output_count) - outlink = inlink->dst->outputs[0]; - - if (outlink) - avfilter_draw_slice(outlink, y, h, slice_dir); -} - -void avfilter_default_end_frame(AVFilterLink *inlink) -{ - AVFilterLink *outlink = NULL; - - if (inlink->dst->output_count) - outlink = inlink->dst->outputs[0]; - - avfilter_unref_buffer(inlink->cur_buf); - inlink->cur_buf = NULL; - - if (outlink) { - if (outlink->out_buf) { - avfilter_unref_buffer(outlink->out_buf); - outlink->out_buf = NULL; - } - avfilter_end_frame(outlink); - } -} - /** * default config_link() implementation for output video links to simplify * the implementation of one input one output video filters */ @@ -186,23 +119,3 @@ int avfilter_default_query_formats(AVFilterContext *ctx) return 0; } - -void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) -{ - avfilter_start_frame(link->dst->outputs[0], picref); -} - -void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) -{ - avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir); -} - -void avfilter_null_end_frame(AVFilterLink *link) -{ - avfilter_end_frame(link->dst->outputs[0]); -} - -AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h) -{ - return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h); -} diff --git a/libavfilter/video.c b/libavfilter/video.c new file mode 100644 index 0000000000..26805feba0 --- /dev/null +++ b/libavfilter/video.c @@ -0,0 +1,294 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" + +#include "avfilter.h" +#include "internal.h" + +static void ff_dlog_ref(void *ctx, AVFilterBufferRef *ref, int end) +{ + av_unused char buf[16]; + av_dlog(ctx, + "ref[%p buf:%p refcount:%d perms:%s data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64, + ref, ref->buf, ref->buf->refcount, ff_get_ref_perms_string(buf, sizeof(buf), ref->perms), ref->data[0], + ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3], + ref->pts, ref->pos); + + if (ref->video) { + av_dlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c", + ref->video->pixel_aspect.num, ref->video->pixel_aspect.den, + ref->video->w, ref->video->h, + !ref->video->interlaced ? 'P' : /* Progressive */ + ref->video->top_field_first ? 'T' : 'B', /* Top / Bottom */ + ref->video->key_frame, + av_get_picture_type_char(ref->video->pict_type)); + } + if (ref->audio) { + av_dlog(ctx, " cl:%"PRId64"d n:%d r:%d p:%d", + ref->audio->channel_layout, + ref->audio->nb_samples, + ref->audio->sample_rate, + ref->audio->planar); + } + + av_dlog(ctx, "]%s", end ? "\n" : ""); +} + +AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h) +{ + return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h); +} + +/* 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. */ +AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h) +{ + int linesize[4]; + uint8_t *data[4]; + AVFilterBufferRef *picref = NULL; + + // +2 is needed for swscaler, +16 to be SIMD-friendly + if (av_image_alloc(data, linesize, w, h, link->format, 16) < 0) + return NULL; + + picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize, + perms, w, h, link->format); + if (!picref) { + av_free(data[0]); + return NULL; + } + + return picref; +} + +AVFilterBufferRef * +avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms, + int w, int h, enum PixelFormat format) +{ + AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer)); + AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef)); + + if (!pic || !picref) + goto fail; + + picref->buf = pic; + picref->buf->free = ff_avfilter_default_free_buffer; + if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps)))) + goto fail; + + pic->w = picref->video->w = w; + pic->h = picref->video->h = h; + + /* make sure the buffer gets read permission or it's useless for output */ + picref->perms = perms | AV_PERM_READ; + + pic->refcount = 1; + picref->type = AVMEDIA_TYPE_VIDEO; + pic->format = picref->format = format; + + memcpy(pic->data, data, 4*sizeof(data[0])); + memcpy(pic->linesize, linesize, 4*sizeof(linesize[0])); + memcpy(picref->data, pic->data, sizeof(picref->data)); + memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize)); + + pic-> extended_data = pic->data; + picref->extended_data = picref->data; + + return picref; + +fail: + if (picref && picref->video) + av_free(picref->video); + av_free(picref); + av_free(pic); + return NULL; +} + +AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h) +{ + AVFilterBufferRef *ret = NULL; + + av_unused char buf[16]; + FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); + av_dlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h); + + if (link->dstpad->get_video_buffer) + ret = link->dstpad->get_video_buffer(link, perms, w, h); + + if (!ret) + ret = avfilter_default_get_video_buffer(link, perms, w, h); + + if (ret) + ret->type = AVMEDIA_TYPE_VIDEO; + + FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " returning "); ff_dlog_ref(NULL, ret, 1); + + return ret; +} + +void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) +{ + avfilter_start_frame(link->dst->outputs[0], picref); +} + +void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) +{ + AVFilterLink *outlink = NULL; + + if (inlink->dst->output_count) + outlink = inlink->dst->outputs[0]; + + if (outlink) { + outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); + avfilter_copy_buffer_ref_props(outlink->out_buf, picref); + avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0)); + } +} + +/* 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, AVFilterBufferRef *picref) +{ + void (*start_frame)(AVFilterLink *, AVFilterBufferRef *); + AVFilterPad *dst = link->dstpad; + int perms = picref->perms; + + FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1); + + if (!(start_frame = dst->start_frame)) + start_frame = avfilter_default_start_frame; + + if (picref->linesize[0] < 0) + perms |= AV_PERM_NEG_LINESIZES; + /* prepare to copy the picture if it has insufficient permissions */ + if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) { + av_log(link->dst, AV_LOG_DEBUG, + "frame copy needed (have perms %x, need %x, reject %x)\n", + picref->perms, + link->dstpad->min_perms, link->dstpad->rej_perms); + + link->cur_buf = avfilter_get_video_buffer(link, dst->min_perms, link->w, link->h); + link->src_buf = picref; + avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf); + } + else + link->cur_buf = picref; + + start_frame(link, link->cur_buf); +} + +void avfilter_null_end_frame(AVFilterLink *link) +{ + avfilter_end_frame(link->dst->outputs[0]); +} + +void avfilter_default_end_frame(AVFilterLink *inlink) +{ + AVFilterLink *outlink = NULL; + + if (inlink->dst->output_count) + outlink = inlink->dst->outputs[0]; + + avfilter_unref_buffer(inlink->cur_buf); + inlink->cur_buf = NULL; + + if (outlink) { + if (outlink->out_buf) { + avfilter_unref_buffer(outlink->out_buf); + outlink->out_buf = NULL; + } + avfilter_end_frame(outlink); + } +} + +void avfilter_end_frame(AVFilterLink *link) +{ + void (*end_frame)(AVFilterLink *); + + if (!(end_frame = link->dstpad->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->src_buf) { + avfilter_unref_buffer(link->src_buf); + link->src_buf = NULL; + } +} + +void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) +{ + avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir); +} + +void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) +{ + AVFilterLink *outlink = NULL; + + if (inlink->dst->output_count) + outlink = inlink->dst->outputs[0]; + + if (outlink) + avfilter_draw_slice(outlink, y, h, slice_dir); +} + +void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) +{ + uint8_t *src[4], *dst[4]; + int i, j, vsub; + void (*draw_slice)(AVFilterLink *, int, int, int); + + FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir); + + /* copy the slice if needed for permission reasons */ + if (link->src_buf) { + vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; + + for (i = 0; i < 4; i++) { + if (link->src_buf->data[i]) { + src[i] = link->src_buf-> data[i] + + (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i]; + dst[i] = link->cur_buf->data[i] + + (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i]; + } else + src[i] = dst[i] = NULL; + } + + for (i = 0; i < 4; i++) { + int planew = + av_image_get_linesize(link->format, link->cur_buf->video->w, i); + + if (!src[i]) continue; + + for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) { + memcpy(dst[i], src[i], planew); + src[i] += link->src_buf->linesize[i]; + dst[i] += link->cur_buf->linesize[i]; + } + } + } + + if (!(draw_slice = link->dstpad->draw_slice)) + draw_slice = avfilter_default_draw_slice; + draw_slice(link, y, h, slice_dir); +} + -- cgit v1.2.3 From 4c64fed37ce0964c45d3699ccf5ac55b077a8291 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 10 May 2012 07:41:16 +0200 Subject: lavfi: move formats-related functions from default.c to formats.c It's more convenient to have them all in one file. --- libavfilter/defaults.c | 64 -------------------------------------------------- libavfilter/formats.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 64 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c index 9829cdcff4..7230da0ba2 100644 --- a/libavfilter/defaults.c +++ b/libavfilter/defaults.c @@ -55,67 +55,3 @@ int avfilter_default_config_output_link(AVFilterLink *link) return 0; } - -#define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \ -{ \ - int count = 0, i; \ - \ - for (i = 0; i < ctx->input_count; i++) { \ - if (ctx->inputs[i]) { \ - ref(fmts, &ctx->inputs[i]->out_fmts); \ - count++; \ - } \ - } \ - for (i = 0; i < ctx->output_count; i++) { \ - if (ctx->outputs[i]) { \ - ref(fmts, &ctx->outputs[i]->in_fmts); \ - count++; \ - } \ - } \ - \ - if (!count) { \ - av_freep(&fmts->list); \ - av_freep(&fmts->refs); \ - av_freep(&fmts); \ - } \ -} - -void ff_set_common_channel_layouts(AVFilterContext *ctx, - AVFilterChannelLayouts *layouts) -{ - SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts, - ff_channel_layouts_ref, channel_layouts); -} - -void ff_set_common_samplerates(AVFilterContext *ctx, - AVFilterFormats *samplerates) -{ - SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates, - avfilter_formats_ref, formats); -} - -/** - * 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) -{ - SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats, - avfilter_formats_ref, formats); -} - -int avfilter_default_query_formats(AVFilterContext *ctx) -{ - enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type : - ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type : - AVMEDIA_TYPE_VIDEO; - - avfilter_set_common_formats(ctx, avfilter_all_formats(type)); - if (type == AVMEDIA_TYPE_AUDIO) { - ff_set_common_channel_layouts(ctx, ff_all_channel_layouts()); - ff_set_common_samplerates(ctx, ff_all_samplerates()); - } - - return 0; -} diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 06567c4d2f..36b4d6d682 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -314,3 +314,67 @@ void avfilter_formats_changeref(AVFilterFormats **oldref, { FORMATS_CHANGEREF(oldref, newref); } + +#define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \ +{ \ + int count = 0, i; \ + \ + for (i = 0; i < ctx->input_count; i++) { \ + if (ctx->inputs[i]) { \ + ref(fmts, &ctx->inputs[i]->out_fmts); \ + count++; \ + } \ + } \ + for (i = 0; i < ctx->output_count; i++) { \ + if (ctx->outputs[i]) { \ + ref(fmts, &ctx->outputs[i]->in_fmts); \ + count++; \ + } \ + } \ + \ + if (!count) { \ + av_freep(&fmts->list); \ + av_freep(&fmts->refs); \ + av_freep(&fmts); \ + } \ +} + +void ff_set_common_channel_layouts(AVFilterContext *ctx, + AVFilterChannelLayouts *layouts) +{ + SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts, + ff_channel_layouts_ref, channel_layouts); +} + +void ff_set_common_samplerates(AVFilterContext *ctx, + AVFilterFormats *samplerates) +{ + SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates, + avfilter_formats_ref, formats); +} + +/** + * 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) +{ + SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats, + avfilter_formats_ref, formats); +} + +int avfilter_default_query_formats(AVFilterContext *ctx) +{ + enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type : + ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type : + AVMEDIA_TYPE_VIDEO; + + avfilter_set_common_formats(ctx, avfilter_all_formats(type)); + if (type == AVMEDIA_TYPE_AUDIO) { + ff_set_common_channel_layouts(ctx, ff_all_channel_layouts()); + ff_set_common_samplerates(ctx, ff_all_samplerates()); + } + + return 0; +} -- cgit v1.2.3 From 4a1ac8c43fcf526b249c3409f1ba54755143a224 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 10 May 2012 07:58:11 +0200 Subject: lavfi: move buffer management function to a separate file. --- libavfilter/Makefile | 1 + libavfilter/avfilter.c | 138 ---------------------------------------- libavfilter/buffer.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/defaults.c | 9 --- 4 files changed, 169 insertions(+), 147 deletions(-) create mode 100644 libavfilter/buffer.c (limited to 'libavfilter') diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 12819cbb06..680b8d958c 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -15,6 +15,7 @@ OBJS = allfilters.o \ audio.o \ avfilter.o \ avfiltergraph.o \ + buffer.o \ buffersink.o \ buffersrc.o \ defaults.o \ diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 9dacf70e22..febc12ff15 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -24,8 +24,6 @@ #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/audioconvert.h" -#include "libavutil/imgutils.h" -#include "libavcodec/avcodec.h" #include "avfilter.h" #include "formats.h" @@ -46,59 +44,6 @@ const char *avfilter_license(void) return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1; } -AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask) -{ - AVFilterBufferRef *ret = av_malloc(sizeof(AVFilterBufferRef)); - if (!ret) - return NULL; - *ret = *ref; - if (ref->type == AVMEDIA_TYPE_VIDEO) { - ret->video = av_malloc(sizeof(AVFilterBufferRefVideoProps)); - if (!ret->video) { - av_free(ret); - return NULL; - } - *ret->video = *ref->video; - ret->extended_data = ret->data; - } else if (ref->type == AVMEDIA_TYPE_AUDIO) { - ret->audio = av_malloc(sizeof(AVFilterBufferRefAudioProps)); - if (!ret->audio) { - av_free(ret); - return NULL; - } - *ret->audio = *ref->audio; - - if (ref->extended_data != ref->data) { - int nb_channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout); - if (!(ret->extended_data = av_malloc(sizeof(*ret->extended_data) * - nb_channels))) { - av_freep(&ret->audio); - av_freep(&ret); - return NULL; - } - memcpy(ret->extended_data, ref->extended_data, - sizeof(*ret->extended_data) * nb_channels); - } else - ret->extended_data = ret->data; - } - ret->perms &= pmask; - ret->buf->refcount ++; - return ret; -} - -void avfilter_unref_buffer(AVFilterBufferRef *ref) -{ - if (!ref) - return; - if (!(--ref->buf->refcount)) - ref->buf->free(ref->buf); - if (ref->extended_data != ref->data) - av_freep(&ref->extended_data); - av_free(ref->video); - av_free(ref->audio); - av_free(ref); -} - void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off, AVFilterPad **pads, AVFilterLink ***links, AVFilterPad *newpad) @@ -469,86 +414,3 @@ int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque ret = filter->filter->init(filter, args, opaque); return ret; } - -int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src) -{ - dst->pts = src->pts; - dst->format = src->format; - - switch (dst->type) { - case AVMEDIA_TYPE_VIDEO: - dst->video->w = src->width; - dst->video->h = src->height; - dst->video->pixel_aspect = src->sample_aspect_ratio; - dst->video->interlaced = src->interlaced_frame; - dst->video->top_field_first = src->top_field_first; - dst->video->key_frame = src->key_frame; - dst->video->pict_type = src->pict_type; - break; - case AVMEDIA_TYPE_AUDIO: - dst->audio->sample_rate = src->sample_rate; - dst->audio->channel_layout = src->channel_layout; - break; - default: - return AVERROR(EINVAL); - } - - return 0; -} - -int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src) -{ - int planes, nb_channels; - - memcpy(dst->data, src->data, sizeof(dst->data)); - memcpy(dst->linesize, src->linesize, sizeof(dst->linesize)); - - dst->pts = src->pts; - dst->format = src->format; - - switch (src->type) { - case AVMEDIA_TYPE_VIDEO: - dst->width = src->video->w; - dst->height = src->video->h; - dst->sample_aspect_ratio = src->video->pixel_aspect; - dst->interlaced_frame = src->video->interlaced; - dst->top_field_first = src->video->top_field_first; - dst->key_frame = src->video->key_frame; - dst->pict_type = src->video->pict_type; - break; - case AVMEDIA_TYPE_AUDIO: - nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout); - planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1; - - if (planes > FF_ARRAY_ELEMS(dst->data)) { - dst->extended_data = av_mallocz(planes * sizeof(*dst->extended_data)); - if (!dst->extended_data) - return AVERROR(ENOMEM); - memcpy(dst->extended_data, src->extended_data, - planes * sizeof(dst->extended_data)); - } else - dst->extended_data = dst->data; - - dst->sample_rate = src->audio->sample_rate; - dst->channel_layout = src->audio->channel_layout; - dst->nb_samples = src->audio->nb_samples; - break; - default: - return AVERROR(EINVAL); - } - - return 0; -} - -void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src) -{ - // copy common properties - dst->pts = src->pts; - dst->pos = src->pos; - - switch (src->type) { - case AVMEDIA_TYPE_VIDEO: *dst->video = *src->video; break; - case AVMEDIA_TYPE_AUDIO: *dst->audio = *src->audio; break; - default: break; - } -} diff --git a/libavfilter/buffer.c b/libavfilter/buffer.c new file mode 100644 index 0000000000..be0da26ea1 --- /dev/null +++ b/libavfilter/buffer.c @@ -0,0 +1,168 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/audioconvert.h" +#include "libavcodec/avcodec.h" + +#include "avfilter.h" +#include "internal.h" + +/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */ +void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr) +{ + if (ptr->extended_data != ptr->data) + av_freep(&ptr->extended_data); + av_free(ptr->data[0]); + av_free(ptr); +} + +AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask) +{ + AVFilterBufferRef *ret = av_malloc(sizeof(AVFilterBufferRef)); + if (!ret) + return NULL; + *ret = *ref; + if (ref->type == AVMEDIA_TYPE_VIDEO) { + ret->video = av_malloc(sizeof(AVFilterBufferRefVideoProps)); + if (!ret->video) { + av_free(ret); + return NULL; + } + *ret->video = *ref->video; + ret->extended_data = ret->data; + } else if (ref->type == AVMEDIA_TYPE_AUDIO) { + ret->audio = av_malloc(sizeof(AVFilterBufferRefAudioProps)); + if (!ret->audio) { + av_free(ret); + return NULL; + } + *ret->audio = *ref->audio; + + if (ref->extended_data != ref->data) { + int nb_channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout); + if (!(ret->extended_data = av_malloc(sizeof(*ret->extended_data) * + nb_channels))) { + av_freep(&ret->audio); + av_freep(&ret); + return NULL; + } + memcpy(ret->extended_data, ref->extended_data, + sizeof(*ret->extended_data) * nb_channels); + } else + ret->extended_data = ret->data; + } + ret->perms &= pmask; + ret->buf->refcount ++; + return ret; +} + +void avfilter_unref_buffer(AVFilterBufferRef *ref) +{ + if (!ref) + return; + if (!(--ref->buf->refcount)) + ref->buf->free(ref->buf); + if (ref->extended_data != ref->data) + av_freep(&ref->extended_data); + av_free(ref->video); + av_free(ref->audio); + av_free(ref); +} + +int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src) +{ + dst->pts = src->pts; + dst->format = src->format; + + switch (dst->type) { + case AVMEDIA_TYPE_VIDEO: + dst->video->w = src->width; + dst->video->h = src->height; + dst->video->pixel_aspect = src->sample_aspect_ratio; + dst->video->interlaced = src->interlaced_frame; + dst->video->top_field_first = src->top_field_first; + dst->video->key_frame = src->key_frame; + dst->video->pict_type = src->pict_type; + break; + case AVMEDIA_TYPE_AUDIO: + dst->audio->sample_rate = src->sample_rate; + dst->audio->channel_layout = src->channel_layout; + break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src) +{ + int planes, nb_channels; + + memcpy(dst->data, src->data, sizeof(dst->data)); + memcpy(dst->linesize, src->linesize, sizeof(dst->linesize)); + + dst->pts = src->pts; + dst->format = src->format; + + switch (src->type) { + case AVMEDIA_TYPE_VIDEO: + dst->width = src->video->w; + dst->height = src->video->h; + dst->sample_aspect_ratio = src->video->pixel_aspect; + dst->interlaced_frame = src->video->interlaced; + dst->top_field_first = src->video->top_field_first; + dst->key_frame = src->video->key_frame; + dst->pict_type = src->video->pict_type; + break; + case AVMEDIA_TYPE_AUDIO: + nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout); + planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1; + + if (planes > FF_ARRAY_ELEMS(dst->data)) { + dst->extended_data = av_mallocz(planes * sizeof(*dst->extended_data)); + if (!dst->extended_data) + return AVERROR(ENOMEM); + memcpy(dst->extended_data, src->extended_data, + planes * sizeof(dst->extended_data)); + } else + dst->extended_data = dst->data; + + dst->sample_rate = src->audio->sample_rate; + dst->channel_layout = src->audio->channel_layout; + dst->nb_samples = src->audio->nb_samples; + break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src) +{ + // copy common properties + dst->pts = src->pts; + dst->pos = src->pos; + + switch (src->type) { + case AVMEDIA_TYPE_VIDEO: *dst->video = *src->video; break; + case AVMEDIA_TYPE_AUDIO: *dst->audio = *src->audio; break; + default: break; + } +} diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c index 7230da0ba2..ec61480c34 100644 --- a/libavfilter/defaults.c +++ b/libavfilter/defaults.c @@ -27,15 +27,6 @@ #include "internal.h" #include "formats.h" -/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */ -void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr) -{ - if (ptr->extended_data != ptr->data) - av_freep(&ptr->extended_data); - av_free(ptr->data[0]); - av_free(ptr); -} - /** * default config_link() implementation for output video links to simplify * the implementation of one input one output video filters */ -- cgit v1.2.3 From d89eca507c00f92e3b0649d678e9ea406b85b1b4 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 14 May 2012 22:02:14 +0200 Subject: Add missing version bumps and APIchanges/Changelog entries. --- Changelog | 1 + doc/APIchanges | 20 +++++++++++++++++--- libavfilter/version.h | 4 ++-- libavutil/avutil.h | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) (limited to 'libavfilter') diff --git a/Changelog b/Changelog index 99fc1dca44..79fc8746bc 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ version : - ZeroCodec decoder - drop support for avconv without libavfilter - add libavresample audio conversion library +- audio filters support in libavfilter and avconv version 0.8: diff --git a/doc/APIchanges b/doc/APIchanges index b6b32f5398..dac87ee606 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,16 +13,30 @@ libavutil: 2011-04-18 API changes, most recent first: -2012-xx-xx - xxxxxxx - lavc 54.13.1 +2012-05-15 - lavfi 2.17.0 + Add support for audio filters + ac71230/a2cd9be - add video/audio buffer sink in a new installed + header buffersink.h + 720c6b7 - add av_buffersrc_write_frame(), deprecate + av_vsrc_buffer_add_frame() + ab16504 - add avfilter_copy_buf_props() + 9453c9e - add extended_data to AVFilterBuffer + 1b8c927 - add avfilter_get_audio_buffer_ref_from_arrays() + +2012-05-09 - lavu 51.30.0 - samplefmt.h + 142e740 - add av_samples_copy() + 6d7f617 - add av_samples_set_silence() + +2012-05-09 - a5117a2 - lavc 54.13.1 For audio formats with fixed frame size, the last frame no longer needs to be padded with silence, libavcodec will handle this internally (effectively all encoders behave as if they had CODEC_CAP_SMALL_LAST_FRAME set). -2012-xx-xx - xxxxxxx - lavc 54.13.0 - avcodec.h +2012-05-07 - 828bd08 - lavc 54.13.0 - avcodec.h Add sample_rate and channel_layout fields to AVFrame. -2012-xx-xx - xxxxxxx - lavr 0.0.1 +2012-05-01 - 4010d72 - lavr 0.0.1 Change AV_MIX_COEFF_TYPE_Q6 to AV_MIX_COEFF_TYPE_Q8. 2012-04-25 - 3527a73 - lavu 51.29.0 - cpu.h diff --git a/libavfilter/version.h b/libavfilter/version.h index 967d40d919..192af68dcb 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -29,8 +29,8 @@ #include "libavutil/avutil.h" #define LIBAVFILTER_VERSION_MAJOR 2 -#define LIBAVFILTER_VERSION_MINOR 16 -#define LIBAVFILTER_VERSION_MICRO 1 +#define LIBAVFILTER_VERSION_MINOR 17 +#define LIBAVFILTER_VERSION_MICRO 0 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ diff --git a/libavutil/avutil.h b/libavutil/avutil.h index bf2f89a803..3e51357ae6 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -152,7 +152,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 51 -#define LIBAVUTIL_VERSION_MINOR 29 +#define LIBAVUTIL_VERSION_MINOR 30 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ -- cgit v1.2.3