lavfi/formats: put merge functions in structures.
It makes the code clearer and will allow adding new stages of negotiation easier.
This commit is contained in:
parent
1d8e1afc00
commit
86d3dd5627
|
@ -456,49 +456,42 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||
|
||||
for (j = 0; j < filter->nb_inputs; j++) {
|
||||
AVFilterLink *link = filter->inputs[j];
|
||||
const AVFilterNegotiation *neg;
|
||||
unsigned neg_step;
|
||||
int convert_needed = 0;
|
||||
|
||||
if (!link)
|
||||
continue;
|
||||
|
||||
if (link->incfg.formats != link->outcfg.formats
|
||||
&& link->incfg.formats && link->outcfg.formats)
|
||||
if (!ff_can_merge_formats(link->incfg.formats, link->outcfg.formats,
|
||||
link->type))
|
||||
neg = ff_filter_get_negotiation(link);
|
||||
av_assert0(neg);
|
||||
for (neg_step = 1; neg_step < neg->nb; neg_step++) {
|
||||
const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
|
||||
void *a = FF_FIELD_AT(void *, m->offset, link->incfg);
|
||||
void *b = FF_FIELD_AT(void *, m->offset, link->outcfg);
|
||||
if (a && b && a != b && !m->can_merge(a, b)) {
|
||||
convert_needed = 1;
|
||||
if (link->type == AVMEDIA_TYPE_AUDIO) {
|
||||
if (link->incfg.samplerates != link->outcfg.samplerates
|
||||
&& link->incfg.samplerates && link->outcfg.samplerates)
|
||||
if (!ff_can_merge_samplerates(link->incfg.samplerates,
|
||||
link->outcfg.samplerates))
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (neg_step = 0; neg_step < neg->nb; neg_step++) {
|
||||
const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
|
||||
void *a = FF_FIELD_AT(void *, m->offset, link->incfg);
|
||||
void *b = FF_FIELD_AT(void *, m->offset, link->outcfg);
|
||||
if (!(a && b)) {
|
||||
count_delayed++;
|
||||
} else if (a == b) {
|
||||
count_already_merged++;
|
||||
} else if (!convert_needed) {
|
||||
count_merged++;
|
||||
ret = m->merge(a, b);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
convert_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECKED_MERGE(field, ...) ((ret = ff_merge_ ## field(__VA_ARGS__)) <= 0)
|
||||
#define MERGE_DISPATCH(field, ...) \
|
||||
if (!(link->incfg.field && link->outcfg.field)) { \
|
||||
count_delayed++; \
|
||||
} else if (link->incfg.field == link->outcfg.field) { \
|
||||
count_already_merged++; \
|
||||
} else if (!convert_needed) { \
|
||||
count_merged++; \
|
||||
if (CHECKED_MERGE(field, __VA_ARGS__)) { \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
convert_needed = 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
if (link->type == AVMEDIA_TYPE_AUDIO) {
|
||||
MERGE_DISPATCH(channel_layouts, link->incfg.channel_layouts,
|
||||
link->outcfg.channel_layouts)
|
||||
MERGE_DISPATCH(samplerates, link->incfg.samplerates,
|
||||
link->outcfg.samplerates)
|
||||
}
|
||||
MERGE_DISPATCH(formats, link->incfg.formats,
|
||||
link->outcfg.formats, link->type)
|
||||
#undef MERGE_DISPATCH
|
||||
|
||||
if (convert_needed) {
|
||||
AVFilterContext *convert;
|
||||
const AVFilter *filter;
|
||||
|
@ -570,26 +563,21 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||
av_assert0(outlink-> incfg.channel_layouts->refcount > 0);
|
||||
av_assert0(outlink->outcfg.channel_layouts->refcount > 0);
|
||||
}
|
||||
if (CHECKED_MERGE(formats, inlink->incfg.formats,
|
||||
inlink->outcfg.formats, inlink->type) ||
|
||||
CHECKED_MERGE(formats, outlink->incfg.formats,
|
||||
outlink->outcfg.formats, outlink->type) ||
|
||||
inlink->type == AVMEDIA_TYPE_AUDIO &&
|
||||
(CHECKED_MERGE(samplerates, inlink->incfg.samplerates,
|
||||
inlink->outcfg.samplerates) ||
|
||||
CHECKED_MERGE(channel_layouts, inlink->incfg.channel_layouts,
|
||||
inlink->outcfg.channel_layouts)) ||
|
||||
outlink->type == AVMEDIA_TYPE_AUDIO &&
|
||||
(CHECKED_MERGE(samplerates, outlink->incfg.samplerates,
|
||||
outlink->outcfg.samplerates) ||
|
||||
CHECKED_MERGE(channel_layouts, outlink->incfg.channel_layouts,
|
||||
outlink->outcfg.channel_layouts))) {
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
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(ENOSYS);
|
||||
for (neg_step = 0; neg_step < neg->nb; neg_step++) {
|
||||
const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
|
||||
void *ia = FF_FIELD_AT(void *, m->offset, inlink->incfg);
|
||||
void *ib = FF_FIELD_AT(void *, m->offset, inlink->outcfg);
|
||||
void *oa = FF_FIELD_AT(void *, m->offset, outlink->incfg);
|
||||
void *ob = FF_FIELD_AT(void *, m->offset, outlink->outcfg);
|
||||
if ((ret = m->merge(ia, ib)) <= 0 ||
|
||||
(ret = m->merge(oa, ob)) <= 0) {
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
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(ENOSYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b,
|
|||
int alpha1=0, alpha2=0;
|
||||
int chroma1=0, chroma2=0;
|
||||
|
||||
av_assert2(check || (a->refcount && b->refcount));
|
||||
|
||||
if (a == b)
|
||||
return 1;
|
||||
|
||||
|
@ -132,43 +134,86 @@ static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int ff_can_merge_formats(const AVFilterFormats *a, const AVFilterFormats *b,
|
||||
enum AVMediaType type)
|
||||
|
||||
/**
|
||||
* Check the formats lists for compatibility for merging without actually
|
||||
* merging.
|
||||
*
|
||||
* @return 1 if they are compatible, 0 if not.
|
||||
*/
|
||||
static int can_merge_pix_fmts(const void *a, const void *b)
|
||||
{
|
||||
return merge_formats_internal((AVFilterFormats *)a,
|
||||
(AVFilterFormats *)b, type, 1);
|
||||
(AVFilterFormats *)b, AVMEDIA_TYPE_VIDEO, 1);
|
||||
}
|
||||
|
||||
int ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b,
|
||||
enum AVMediaType type)
|
||||
/**
|
||||
* Merge the formats lists if they are compatible and update all the
|
||||
* references of a and b to point to the combined list and free the old
|
||||
* lists as needed. The combined list usually contains the intersection of
|
||||
* the lists of a and b.
|
||||
*
|
||||
* Both a and b must have owners (i.e. refcount > 0) for these functions.
|
||||
*
|
||||
* @return 1 if merging succeeded, 0 if a and b are incompatible
|
||||
* and negative AVERROR code on failure.
|
||||
* a and b are unmodified if 0 is returned.
|
||||
*/
|
||||
static int merge_pix_fmts(void *a, void *b)
|
||||
{
|
||||
av_assert2(a->refcount && b->refcount);
|
||||
return merge_formats_internal(a, b, type, 0);
|
||||
return merge_formats_internal(a, b, AVMEDIA_TYPE_VIDEO, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* See can_merge_pix_fmts().
|
||||
*/
|
||||
static int can_merge_sample_fmts(const void *a, const void *b)
|
||||
{
|
||||
return merge_formats_internal((AVFilterFormats *)a,
|
||||
(AVFilterFormats *)b, AVMEDIA_TYPE_AUDIO, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* See merge_pix_fmts().
|
||||
*/
|
||||
static int merge_sample_fmts(void *a, void *b)
|
||||
{
|
||||
return merge_formats_internal(a, b, AVMEDIA_TYPE_AUDIO, 0);
|
||||
}
|
||||
|
||||
static int merge_samplerates_internal(AVFilterFormats *a,
|
||||
AVFilterFormats *b, int check)
|
||||
{
|
||||
av_assert2(check || (a->refcount && b->refcount));
|
||||
if (a == b) return 1;
|
||||
|
||||
MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ff_can_merge_samplerates(const AVFilterFormats *a, const AVFilterFormats *b)
|
||||
/**
|
||||
* See can_merge_pix_fmts().
|
||||
*/
|
||||
static int can_merge_samplerates(const void *a, const void *b)
|
||||
{
|
||||
return merge_samplerates_internal((AVFilterFormats *)a, (AVFilterFormats *)b, 1);
|
||||
}
|
||||
|
||||
int ff_merge_samplerates(AVFilterFormats *a, AVFilterFormats *b)
|
||||
/**
|
||||
* See merge_pix_fmts().
|
||||
*/
|
||||
static int merge_samplerates(void *a, void *b)
|
||||
{
|
||||
av_assert2(a->refcount && b->refcount);
|
||||
return merge_samplerates_internal(a, b, 0);
|
||||
}
|
||||
|
||||
int ff_merge_channel_layouts(AVFilterChannelLayouts *a,
|
||||
AVFilterChannelLayouts *b)
|
||||
/**
|
||||
* See merge_pix_fmts().
|
||||
*/
|
||||
static int merge_channel_layouts(void *va, void *vb)
|
||||
{
|
||||
AVFilterChannelLayouts *a = va;
|
||||
AVFilterChannelLayouts *b = vb;
|
||||
uint64_t *channel_layouts;
|
||||
unsigned a_all = a->all_layouts + a->all_counts;
|
||||
unsigned b_all = b->all_layouts + b->all_counts;
|
||||
|
@ -255,6 +300,51 @@ int ff_merge_channel_layouts(AVFilterChannelLayouts *a,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static const AVFilterFormatsMerger mergers_video[] = {
|
||||
{
|
||||
.offset = offsetof(AVFilterFormatsConfig, formats),
|
||||
.merge = merge_pix_fmts,
|
||||
.can_merge = can_merge_pix_fmts,
|
||||
},
|
||||
};
|
||||
|
||||
static const AVFilterFormatsMerger mergers_audio[] = {
|
||||
{
|
||||
.offset = offsetof(AVFilterFormatsConfig, channel_layouts),
|
||||
.merge = merge_channel_layouts,
|
||||
.can_merge = NULL,
|
||||
},
|
||||
{
|
||||
.offset = offsetof(AVFilterFormatsConfig, samplerates),
|
||||
.merge = merge_samplerates,
|
||||
.can_merge = can_merge_samplerates,
|
||||
},
|
||||
{
|
||||
.offset = offsetof(AVFilterFormatsConfig, formats),
|
||||
.merge = merge_sample_fmts,
|
||||
.can_merge = can_merge_sample_fmts,
|
||||
},
|
||||
};
|
||||
|
||||
static const AVFilterNegotiation negotiate_video = {
|
||||
.nb = FF_ARRAY_ELEMS(mergers_video),
|
||||
.mergers = mergers_video,
|
||||
};
|
||||
|
||||
static const AVFilterNegotiation negotiate_audio = {
|
||||
.nb = FF_ARRAY_ELEMS(mergers_audio),
|
||||
.mergers = mergers_audio,
|
||||
};
|
||||
|
||||
const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link)
|
||||
{
|
||||
switch (link->type) {
|
||||
case AVMEDIA_TYPE_VIDEO: return &negotiate_video;
|
||||
case AVMEDIA_TYPE_AUDIO: return &negotiate_audio;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ff_fmt_is_in(int fmt, const int *fmts)
|
||||
{
|
||||
const int *p;
|
||||
|
|
|
@ -69,6 +69,19 @@ struct AVFilterFormats {
|
|||
struct AVFilterFormats ***refs; ///< references to this list
|
||||
};
|
||||
|
||||
typedef struct AVFilterFormatMerger {
|
||||
unsigned offset;
|
||||
int (*merge)(void *a, void *b);
|
||||
int (*can_merge)(const void *a, const void *b);
|
||||
} AVFilterFormatsMerger;
|
||||
|
||||
typedef struct AVFilterNegotiation {
|
||||
unsigned nb;
|
||||
const AVFilterFormatsMerger *mergers;
|
||||
} AVFilterNegotiation;
|
||||
|
||||
const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link);
|
||||
|
||||
/**
|
||||
* A list of supported channel layouts.
|
||||
*
|
||||
|
@ -108,34 +121,6 @@ struct AVFilterChannelLayouts {
|
|||
#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
|
||||
(int)((l) & 0x7FFFFFFF) : 0)
|
||||
|
||||
/**
|
||||
* Check the formats/samplerates lists for compatibility for merging
|
||||
* without actually merging.
|
||||
*
|
||||
* @return 1 if they are compatible, 0 if not.
|
||||
*/
|
||||
int ff_can_merge_formats(const AVFilterFormats *a, const AVFilterFormats *b,
|
||||
enum AVMediaType type);
|
||||
int ff_can_merge_samplerates(const AVFilterFormats *a, const AVFilterFormats *b);
|
||||
|
||||
/**
|
||||
* Merge the formats/channel layouts/samplerates lists if they are compatible
|
||||
* and update all the references of a and b to point to the combined list and
|
||||
* free the old lists as needed. The combined list usually contains the
|
||||
* intersection of the lists of a and b.
|
||||
*
|
||||
* Both a and b must have owners (i.e. refcount > 0) for these functions.
|
||||
*
|
||||
* @return 1 if merging succeeded, 0 if a and b are incompatible
|
||||
* and negative AVERROR code on failure.
|
||||
* a and b are unmodified if 0 is returned.
|
||||
*/
|
||||
int ff_merge_channel_layouts(AVFilterChannelLayouts *a,
|
||||
AVFilterChannelLayouts *b);
|
||||
int ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b,
|
||||
enum AVMediaType type);
|
||||
int ff_merge_samplerates(AVFilterFormats *a, AVFilterFormats *b);
|
||||
|
||||
/**
|
||||
* Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
|
||||
* representing any channel layout (with known disposition)/sample rate.
|
||||
|
|
Loading…
Reference in New Issue
Block a user