mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-11-06 05:17:42 +00:00
swscale/graph: add plane copy metadata
This can be set opportunistically by passes which are effectively memcopies. Information about end-to-end plane copies will also propagate upwards to the SwsGraph, and can be used there by the caller. The reason we need to solve it this way is deeply tied to the way SwsGraph is designed; specifically the fact that it can be used with arbitrary frames and also lives per-field (rather than per-frame), meaning that we can't just directly mutate the output frame somehow from the run() call to ref the output planes. Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
1 parent
4af33ec418
commit
6b38a4035a
2 files changed
+61
-7
No files matched your search
+42
-7
@@ -207,6 +207,7 @@ int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt,
|
||||
pass->output->height = height;
|
||||
pass->output->width = width;
|
||||
pass->output->width_align = 1;
|
||||
memset(pass->output->plane_copy, -1, sizeof(pass->output->plane_copy));
|
||||
|
||||
if (!align) {
|
||||
pass->slice_h = pass->lines;
|
||||
@@ -242,6 +243,13 @@ void ff_sws_pass_link_output(SwsPass *dst, const SwsPass *src)
|
||||
keep->width_align = FFMAX(keep->width_align, drop->width_align);
|
||||
keep->width_pad = FFMAX(keep->width_pad, drop->width_pad);
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(keep->plane_copy); i++) {
|
||||
if (keep->plane_copy[i] < 0)
|
||||
keep->plane_copy[i] = drop->plane_copy[i];
|
||||
else if (drop->plane_copy[i] >= 0)
|
||||
av_assert1(keep->plane_copy[i] == drop->plane_copy[i]);
|
||||
}
|
||||
|
||||
av_refstruct_replace(&dst->output, src->output);
|
||||
}
|
||||
|
||||
@@ -790,15 +798,41 @@ static int init_passes(SwsGraph *graph)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pass)
|
||||
return 0;
|
||||
if (!pass) {
|
||||
/* No passes were added, so no operations were necessary */
|
||||
graph->noop = 1;
|
||||
|
||||
/* No passes were added, so no operations were necessary */
|
||||
graph->noop = 1;
|
||||
const int nb_planes = av_pix_fmt_count_planes(dst.format);
|
||||
for (int i = 0; i < nb_planes; i++)
|
||||
graph->plane_copy[i] = i;
|
||||
|
||||
/* Add threaded memcpy pass */
|
||||
return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
|
||||
pass, 0, 1, run_copy, NULL, NULL, NULL, &pass);
|
||||
/* Add threaded memcpy pass */
|
||||
return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
|
||||
pass, 0, 1, run_copy, NULL, NULL, NULL, &pass);
|
||||
}
|
||||
|
||||
/* Compute end-to-end plane copy map */
|
||||
for (int n = 0; n < graph->num_passes; n++) {
|
||||
const SwsPass *pass = graph->passes[n];
|
||||
/* This pass writes to an output buffer other than the image
|
||||
* output, or copies from the output of a different pass */
|
||||
if (pass->output->avframe || pass->input)
|
||||
continue;
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(graph->plane_copy); i++) {
|
||||
const int idx = pass->output->plane_copy[i];
|
||||
if (idx < 0)
|
||||
continue;
|
||||
if (graph->plane_copy[i] < 0) {
|
||||
graph->plane_copy[i] = idx;
|
||||
av_log(graph->ctx, AV_LOG_DEBUG, "Plane %d passthrough from "
|
||||
"plane %d\n", i, idx);
|
||||
} else {
|
||||
av_assert0(graph->plane_copy[i] == idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
|
||||
@@ -845,6 +879,7 @@ int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst,
|
||||
graph->opts_copy = *ctx;
|
||||
av_assert0(src->interlaced == dst->interlaced);
|
||||
av_assert0(src->field == dst->field);
|
||||
memset(graph->plane_copy, -1, sizeof(graph->plane_copy));
|
||||
|
||||
if (ctx->threads == 1) {
|
||||
graph->num_threads = 1;
|
||||
|
||||
@@ -66,6 +66,15 @@ typedef struct SwsPassBuffer {
|
||||
/* Optional allocation hints for optimal performance */
|
||||
int width_align; /* Align width to multiple of this */
|
||||
int width_pad; /* Extra padding pixels */
|
||||
|
||||
/**
|
||||
* Map of planes which are directly copied from the pass input. These
|
||||
* may be promoted from a memcpy to a refcopy.
|
||||
*
|
||||
* Each entry maps the output index to the corresponding input plane
|
||||
* index, or -1 for no copythrough.
|
||||
*/
|
||||
int plane_copy[4];
|
||||
} SwsPassBuffer;
|
||||
|
||||
/**
|
||||
@@ -130,6 +139,16 @@ typedef struct SwsGraph {
|
||||
|
||||
AVBufferRef *hw_frames_ref;
|
||||
|
||||
/**
|
||||
* Map of planes which directly copied from the input. These may be
|
||||
* promoted from a memcpy to a refcopy. This requires special handling
|
||||
* by the caller.
|
||||
*
|
||||
* Each entry maps the output index to the corresponding input plane
|
||||
* index, or -1 for no copythrough.
|
||||
*/
|
||||
int plane_copy[4];
|
||||
|
||||
/** Sorted sequence of filter passes to apply */
|
||||
SwsPass **passes;
|
||||
int num_passes;
|
||||
|
||||
Reference in new issue
Block a user