lavfi: support multiple rounds of format negotiation.
Remove the temporary hack for amerge and replace it with a generic solution.
This commit is contained in:
parent
00da527b44
commit
125acd2152
@ -29,6 +29,11 @@ Format negotiation
|
|||||||
same format amongst a supported list, all it has to do is use a reference
|
same format amongst a supported list, all it has to do is use a reference
|
||||||
to the same list of formats.
|
to the same list of formats.
|
||||||
|
|
||||||
|
query_formats can leave some formats unset and return AVERROR(EAGAIN) to
|
||||||
|
cause the negotiation mechanism to try again later. That can be used by
|
||||||
|
filters with complex requirements to use the format negotiated on one link
|
||||||
|
to set the formats supported on another.
|
||||||
|
|
||||||
|
|
||||||
Buffer references ownership and permissions
|
Buffer references ownership and permissions
|
||||||
===========================================
|
===========================================
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libavutil/avassert.h"
|
#include "libavutil/avassert.h"
|
||||||
|
#include "libavutil/bprint.h"
|
||||||
#include "libavutil/channel_layout.h"
|
#include "libavutil/channel_layout.h"
|
||||||
#include "libavutil/opt.h"
|
#include "libavutil/opt.h"
|
||||||
#include "libavutil/pixdesc.h"
|
#include "libavutil/pixdesc.h"
|
||||||
@ -211,8 +212,9 @@ static int filter_query_formats(AVFilterContext *ctx)
|
|||||||
AVMEDIA_TYPE_VIDEO;
|
AVMEDIA_TYPE_VIDEO;
|
||||||
|
|
||||||
if ((ret = ctx->filter->query_formats(ctx)) < 0) {
|
if ((ret = ctx->filter->query_formats(ctx)) < 0) {
|
||||||
av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",
|
if (ret != AVERROR(EAGAIN))
|
||||||
ctx->name, av_err2str(ret));
|
av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",
|
||||||
|
ctx->name, av_err2str(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,26 +240,47 @@ static int filter_query_formats(AVFilterContext *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int formats_declared(AVFilterContext *f)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < f->nb_inputs; i++) {
|
||||||
|
if (!f->inputs[i]->out_formats)
|
||||||
|
return 0;
|
||||||
|
if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO &&
|
||||||
|
!(f->inputs[i]->out_samplerates &&
|
||||||
|
f->inputs[i]->out_channel_layouts))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < f->nb_outputs; i++) {
|
||||||
|
if (!f->outputs[i]->in_formats)
|
||||||
|
return 0;
|
||||||
|
if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO &&
|
||||||
|
!(f->outputs[i]->in_samplerates &&
|
||||||
|
f->outputs[i]->in_channel_layouts))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
||||||
{
|
{
|
||||||
int i, j, ret;
|
int i, j, ret;
|
||||||
int scaler_count = 0, resampler_count = 0;
|
int scaler_count = 0, resampler_count = 0;
|
||||||
|
int count_queried = 0, count_merged = 0, count_already_merged = 0,
|
||||||
|
count_delayed = 0;
|
||||||
|
|
||||||
for (j = 0; j < 2; j++) {
|
|
||||||
/* ask all the sub-filters for their supported media formats */
|
|
||||||
for (i = 0; i < graph->nb_filters; i++) {
|
for (i = 0; i < graph->nb_filters; i++) {
|
||||||
/* Call query_formats on sources first.
|
AVFilterContext *f = graph->filters[i];
|
||||||
This is a temporary workaround for amerge,
|
if (formats_declared(f))
|
||||||
until format renegociation is implemented. */
|
|
||||||
if (!graph->filters[i]->nb_inputs == j)
|
|
||||||
continue;
|
continue;
|
||||||
if (graph->filters[i]->filter->query_formats)
|
if (f->filter->query_formats)
|
||||||
ret = filter_query_formats(graph->filters[i]);
|
ret = filter_query_formats(f);
|
||||||
else
|
else
|
||||||
ret = ff_default_query_formats(graph->filters[i]);
|
ret = ff_default_query_formats(f);
|
||||||
if (ret < 0)
|
if (ret < 0 && ret != AVERROR(EAGAIN))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
count_queried++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* go through and merge as many format lists as possible */
|
/* go through and merge as many format lists as possible */
|
||||||
@ -271,20 +294,33 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||||||
if (!link)
|
if (!link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link->in_formats != link->out_formats &&
|
#define MERGE_DISPATCH(field, statement) \
|
||||||
!ff_merge_formats(link->in_formats, link->out_formats,
|
if (!(link->in_ ## field && link->out_ ## field)) { \
|
||||||
link->type))
|
count_delayed++; \
|
||||||
convert_needed = 1;
|
} else if (link->in_ ## field == link->out_ ## field) { \
|
||||||
if (link->type == AVMEDIA_TYPE_AUDIO) {
|
count_already_merged++; \
|
||||||
if (link->in_channel_layouts != link->out_channel_layouts &&
|
} else { \
|
||||||
!ff_merge_channel_layouts(link->in_channel_layouts,
|
count_merged++; \
|
||||||
link->out_channel_layouts))
|
statement \
|
||||||
convert_needed = 1;
|
|
||||||
if (link->in_samplerates != link->out_samplerates &&
|
|
||||||
!ff_merge_samplerates(link->in_samplerates,
|
|
||||||
link->out_samplerates))
|
|
||||||
convert_needed = 1;
|
|
||||||
}
|
}
|
||||||
|
MERGE_DISPATCH(formats,
|
||||||
|
if (!ff_merge_formats(link->in_formats, link->out_formats,
|
||||||
|
link->type))
|
||||||
|
convert_needed = 1;
|
||||||
|
)
|
||||||
|
if (link->type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
MERGE_DISPATCH(channel_layouts,
|
||||||
|
if (!ff_merge_channel_layouts(link->in_channel_layouts,
|
||||||
|
link->out_channel_layouts))
|
||||||
|
convert_needed = 1;
|
||||||
|
)
|
||||||
|
MERGE_DISPATCH(samplerates,
|
||||||
|
if (!ff_merge_samplerates(link->in_samplerates,
|
||||||
|
link->out_samplerates))
|
||||||
|
convert_needed = 1;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#undef MERGE_DISPATCH
|
||||||
|
|
||||||
if (convert_needed) {
|
if (convert_needed) {
|
||||||
AVFilterContext *convert;
|
AVFilterContext *convert;
|
||||||
@ -368,6 +404,25 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
av_log(graph, AV_LOG_DEBUG, "query_formats: "
|
||||||
|
"%d queried, %d merged, %d already done, %d delayed\n",
|
||||||
|
count_queried, count_merged, count_already_merged, count_delayed);
|
||||||
|
if (count_delayed) {
|
||||||
|
AVBPrint bp;
|
||||||
|
|
||||||
|
if (count_queried || count_merged)
|
||||||
|
return AVERROR(EAGAIN);
|
||||||
|
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
|
||||||
|
for (i = 0; i < graph->nb_filters; i++)
|
||||||
|
if (!formats_declared(graph->filters[i]))
|
||||||
|
av_bprintf(&bp, "%s%s", bp.len ? ", " : "",
|
||||||
|
graph->filters[i]->name);
|
||||||
|
av_log(graph, AV_LOG_ERROR,
|
||||||
|
"The following filters could not choose their formats: %s\n"
|
||||||
|
"Consider inserting the (a)format filter near their input or "
|
||||||
|
"output.\n", bp.str);
|
||||||
|
return AVERROR(EIO);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,7 +886,9 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* find supported formats from sub-filters, and merge along links */
|
/* find supported formats from sub-filters, and merge along links */
|
||||||
if ((ret = query_formats(graph, log_ctx)) < 0)
|
while ((ret = query_formats(graph, log_ctx)) == AVERROR(EAGAIN))
|
||||||
|
av_log(graph, AV_LOG_DEBUG, "query_formats not finished\n");
|
||||||
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Once everything is merged, it's possible that we'll still have
|
/* Once everything is merged, it's possible that we'll still have
|
||||||
|
Loading…
x
Reference in New Issue
Block a user