You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-10 06:10:52 +02:00
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:
@@ -456,49 +456,42 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||||||
|
|
||||||
for (j = 0; j < filter->nb_inputs; j++) {
|
for (j = 0; j < filter->nb_inputs; j++) {
|
||||||
AVFilterLink *link = filter->inputs[j];
|
AVFilterLink *link = filter->inputs[j];
|
||||||
|
const AVFilterNegotiation *neg;
|
||||||
|
unsigned neg_step;
|
||||||
int convert_needed = 0;
|
int convert_needed = 0;
|
||||||
|
|
||||||
if (!link)
|
if (!link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link->incfg.formats != link->outcfg.formats
|
neg = ff_filter_get_negotiation(link);
|
||||||
&& link->incfg.formats && link->outcfg.formats)
|
av_assert0(neg);
|
||||||
if (!ff_can_merge_formats(link->incfg.formats, link->outcfg.formats,
|
for (neg_step = 1; neg_step < neg->nb; neg_step++) {
|
||||||
link->type))
|
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;
|
convert_needed = 1;
|
||||||
if (link->type == AVMEDIA_TYPE_AUDIO) {
|
break;
|
||||||
if (link->incfg.samplerates != link->outcfg.samplerates
|
}
|
||||||
&& link->incfg.samplerates && link->outcfg.samplerates)
|
}
|
||||||
if (!ff_can_merge_samplerates(link->incfg.samplerates,
|
for (neg_step = 0; neg_step < neg->nb; neg_step++) {
|
||||||
link->outcfg.samplerates))
|
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;
|
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) {
|
if (convert_needed) {
|
||||||
AVFilterContext *convert;
|
AVFilterContext *convert;
|
||||||
const AVFilter *filter;
|
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-> incfg.channel_layouts->refcount > 0);
|
||||||
av_assert0(outlink->outcfg.channel_layouts->refcount > 0);
|
av_assert0(outlink->outcfg.channel_layouts->refcount > 0);
|
||||||
}
|
}
|
||||||
if (CHECKED_MERGE(formats, inlink->incfg.formats,
|
for (neg_step = 0; neg_step < neg->nb; neg_step++) {
|
||||||
inlink->outcfg.formats, inlink->type) ||
|
const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
|
||||||
CHECKED_MERGE(formats, outlink->incfg.formats,
|
void *ia = FF_FIELD_AT(void *, m->offset, inlink->incfg);
|
||||||
outlink->outcfg.formats, outlink->type) ||
|
void *ib = FF_FIELD_AT(void *, m->offset, inlink->outcfg);
|
||||||
inlink->type == AVMEDIA_TYPE_AUDIO &&
|
void *oa = FF_FIELD_AT(void *, m->offset, outlink->incfg);
|
||||||
(CHECKED_MERGE(samplerates, inlink->incfg.samplerates,
|
void *ob = FF_FIELD_AT(void *, m->offset, outlink->outcfg);
|
||||||
inlink->outcfg.samplerates) ||
|
if ((ret = m->merge(ia, ib)) <= 0 ||
|
||||||
CHECKED_MERGE(channel_layouts, inlink->incfg.channel_layouts,
|
(ret = m->merge(oa, ob)) <= 0) {
|
||||||
inlink->outcfg.channel_layouts)) ||
|
if (ret < 0)
|
||||||
outlink->type == AVMEDIA_TYPE_AUDIO &&
|
return ret;
|
||||||
(CHECKED_MERGE(samplerates, outlink->incfg.samplerates,
|
av_log(log_ctx, AV_LOG_ERROR,
|
||||||
outlink->outcfg.samplerates) ||
|
"Impossible to convert between the formats supported by the filter "
|
||||||
CHECKED_MERGE(channel_layouts, outlink->incfg.channel_layouts,
|
"'%s' and the filter '%s'\n", link->src->name, link->dst->name);
|
||||||
outlink->outcfg.channel_layouts))) {
|
return AVERROR(ENOSYS);
|
||||||
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 alpha1=0, alpha2=0;
|
||||||
int chroma1=0, chroma2=0;
|
int chroma1=0, chroma2=0;
|
||||||
|
|
||||||
|
av_assert2(check || (a->refcount && b->refcount));
|
||||||
|
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -132,43 +134,86 @@ static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b,
|
|||||||
return 1;
|
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,
|
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, AVMEDIA_TYPE_VIDEO, 0);
|
||||||
return merge_formats_internal(a, b, type, 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,
|
static int merge_samplerates_internal(AVFilterFormats *a,
|
||||||
AVFilterFormats *b, int check)
|
AVFilterFormats *b, int check)
|
||||||
{
|
{
|
||||||
|
av_assert2(check || (a->refcount && b->refcount));
|
||||||
if (a == b) return 1;
|
if (a == b) return 1;
|
||||||
|
|
||||||
MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1);
|
MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1);
|
||||||
return 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);
|
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);
|
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;
|
uint64_t *channel_layouts;
|
||||||
unsigned a_all = a->all_layouts + a->all_counts;
|
unsigned a_all = a->all_layouts + a->all_counts;
|
||||||
unsigned b_all = b->all_layouts + b->all_counts;
|
unsigned b_all = b->all_layouts + b->all_counts;
|
||||||
@@ -255,6 +300,51 @@ int ff_merge_channel_layouts(AVFilterChannelLayouts *a,
|
|||||||
return 1;
|
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)
|
int ff_fmt_is_in(int fmt, const int *fmts)
|
||||||
{
|
{
|
||||||
const int *p;
|
const int *p;
|
||||||
|
@@ -69,6 +69,19 @@ struct AVFilterFormats {
|
|||||||
struct AVFilterFormats ***refs; ///< references to this list
|
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.
|
* A list of supported channel layouts.
|
||||||
*
|
*
|
||||||
@@ -108,34 +121,6 @@ struct AVFilterChannelLayouts {
|
|||||||
#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
|
#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
|
||||||
(int)((l) & 0x7FFFFFFF) : 0)
|
(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 --
|
* Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
|
||||||
* representing any channel layout (with known disposition)/sample rate.
|
* representing any channel layout (with known disposition)/sample rate.
|
||||||
|
Reference in New Issue
Block a user