lavfi: add types and functions for channel layout/samplerate negotiation
This commit is contained in:
parent
394a0267ab
commit
5775a1832c
@ -618,6 +618,22 @@ struct AVFilterLink {
|
|||||||
* input link is assumed to be an unchangeable property.
|
* input link is assumed to be an unchangeable property.
|
||||||
*/
|
*/
|
||||||
AVRational time_base;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,58 +22,132 @@
|
|||||||
#include "libavutil/pixdesc.h"
|
#include "libavutil/pixdesc.h"
|
||||||
#include "avfilter.h"
|
#include "avfilter.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "formats.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all refs from a to ret and destroy a.
|
* Add all refs from a to ret and destroy a.
|
||||||
*/
|
*/
|
||||||
static void merge_ref(AVFilterFormats *ret, AVFilterFormats *a)
|
#define MERGE_REF(ret, a, fmts, type, fail) \
|
||||||
{
|
do { \
|
||||||
int i;
|
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)
|
||||||
|
|
||||||
for(i = 0; i < a->refcount; i ++) {
|
/**
|
||||||
ret->refs[ret->refcount] = a->refs[i];
|
* Add all formats common for a and b to ret, copy the refs and destroy
|
||||||
*ret->refs[ret->refcount++] = ret;
|
* a and b.
|
||||||
}
|
*/
|
||||||
|
#define MERGE_FORMATS(ret, a, b, fmts, nb, type, fail) \
|
||||||
av_free(a->refs);
|
do { \
|
||||||
av_free(a->formats);
|
int i, j, k = 0, count = FFMIN(a->nb, b->nb); \
|
||||||
av_free(a);
|
\
|
||||||
}
|
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 *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
|
||||||
{
|
{
|
||||||
AVFilterFormats *ret;
|
AVFilterFormats *ret = NULL;
|
||||||
unsigned i, j, k = 0, m_count;
|
|
||||||
|
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return a;
|
return a;
|
||||||
|
|
||||||
ret = av_mallocz(sizeof(*ret));
|
MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail);
|
||||||
|
|
||||||
/* 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];
|
|
||||||
|
|
||||||
ret->format_count = k;
|
|
||||||
}
|
|
||||||
/* check that there was at least one common format */
|
|
||||||
if(!ret->format_count) {
|
|
||||||
av_free(ret->formats);
|
|
||||||
av_free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret->refs = av_malloc(sizeof(*ret->refs) * (a->refcount + b->refcount));
|
|
||||||
|
|
||||||
merge_ref(ret, a);
|
|
||||||
merge_ref(ret, b);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
fail:
|
||||||
|
if (ret) {
|
||||||
|
av_freep(&ret->refs);
|
||||||
|
av_freep(&ret->formats);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
fail:
|
||||||
|
if (ret) {
|
||||||
|
av_freep(&ret->refs);
|
||||||
|
av_freep(&ret->formats);
|
||||||
|
}
|
||||||
|
av_freep(&ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
int ff_fmt_is_in(int fmt, const int *fmts)
|
||||||
@ -104,21 +178,31 @@ AVFilterFormats *avfilter_make_format_list(const int *fmts)
|
|||||||
return formats;
|
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 avfilter_add_format(AVFilterFormats **avff, int fmt)
|
||||||
{
|
{
|
||||||
int *fmts;
|
ADD_FORMAT(avff, fmt, int, formats, format_count);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(*avff) && !(*avff = av_mallocz(sizeof(**avff))))
|
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
|
||||||
return AVERROR(ENOMEM);
|
{
|
||||||
|
ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts);
|
||||||
fmts = av_realloc((*avff)->formats,
|
|
||||||
sizeof(*(*avff)->formats) * ((*avff)->format_count+1));
|
|
||||||
if (!fmts)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
|
|
||||||
(*avff)->formats = fmts;
|
|
||||||
(*avff)->formats[(*avff)->format_count++] = fmt;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFilterFormats *avfilter_all_formats(enum AVMediaType type)
|
AVFilterFormats *avfilter_all_formats(enum AVMediaType type)
|
||||||
@ -136,51 +220,97 @@ AVFilterFormats *avfilter_all_formats(enum AVMediaType type)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
|
AVFilterFormats *ff_all_samplerates(void)
|
||||||
{
|
{
|
||||||
*ref = f;
|
AVFilterFormats *ret = av_mallocz(sizeof(*ret));
|
||||||
f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount);
|
return ret;
|
||||||
f->refs[f->refcount-1] = ref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_ref_index(AVFilterFormats **ref)
|
AVFilterChannelLayouts *ff_all_channel_layouts(void)
|
||||||
{
|
{
|
||||||
int i;
|
AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
|
||||||
for(i = 0; i < (*ref)->refcount; i ++)
|
return ret;
|
||||||
if((*ref)->refs[i] == ref)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
FORMATS_REF(f, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
|
||||||
|
{
|
||||||
|
FORMATS_REF(f, 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)
|
||||||
|
|
||||||
void avfilter_formats_unref(AVFilterFormats **ref)
|
void avfilter_formats_unref(AVFilterFormats **ref)
|
||||||
{
|
{
|
||||||
int idx;
|
FORMATS_UNREF(ref, formats);
|
||||||
|
}
|
||||||
|
|
||||||
if (!*ref)
|
void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
|
||||||
return;
|
{
|
||||||
|
FORMATS_UNREF(ref, channel_layouts);
|
||||||
|
}
|
||||||
|
|
||||||
idx = find_ref_index(ref);
|
#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)
|
||||||
|
|
||||||
if(idx >= 0)
|
void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
|
||||||
memmove((*ref)->refs + idx, (*ref)->refs + idx + 1,
|
AVFilterChannelLayouts **newref)
|
||||||
sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1));
|
{
|
||||||
|
FORMATS_CHANGEREF(oldref, newref);
|
||||||
if(!--(*ref)->refcount) {
|
|
||||||
av_free((*ref)->formats);
|
|
||||||
av_free((*ref)->refs);
|
|
||||||
av_free(*ref);
|
|
||||||
}
|
|
||||||
*ref = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void avfilter_formats_changeref(AVFilterFormats **oldref,
|
void avfilter_formats_changeref(AVFilterFormats **oldref,
|
||||||
AVFilterFormats **newref)
|
AVFilterFormats **newref)
|
||||||
{
|
{
|
||||||
int idx = find_ref_index(oldref);
|
FORMATS_CHANGEREF(oldref, newref);
|
||||||
|
|
||||||
if(idx >= 0) {
|
|
||||||
(*oldref)->refs[idx] = newref;
|
|
||||||
*newref = *oldref;
|
|
||||||
*oldref = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
78
libavfilter/formats.h
Normal file
78
libavfilter/formats.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user