[ffmpeg] branch master updated (16ee3d8d99 -> 67f3627267)
This is an automated email from the git hooks/post-receive script. Git pushed a change to branch master in repository ffmpeg. from 16ee3d8d99 avformat/mov: fix cases where we discard iamf packets from enabled streams new 79334c8ca1 swscale/ops: add subsampling shift to SwsOpExec new bca806d4f9 swscale/ops: avoid stack copies of SwsImg new 62dc591a80 swscale/ops: correctly shift pointers for last row handling new 363779a4bb swscale/ops: don't set src/dst_frame_ptr in op_pass_run() new d89765eb28 swscale/graph: simplify output buffer management new e9d1ed3fdc swscale/graph: avoid stack copies of SwsImg new 5121665463 swscale/graph: use AVFrame to track internal allocation new 846823b174 swscale/graph: don't pointlessly align data buffers new 4d7b1c3685 swscale/graph: move frame->field init logic to SwsGraph new 67f3627267 swscale/graph: nuke SwsImg The 10 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "add" were already present in the repository and have only been added to this reference. Summary of changes: libswscale/graph.c | 212 +++++++++++++++++++++++++----------------- libswscale/graph.h | 40 +++----- libswscale/ops.c | 114 +++++++++++------------ libswscale/ops_internal.h | 9 +- libswscale/swscale.c | 38 +------- libswscale/x86/ops_common.asm | 4 + 6 files changed, 206 insertions(+), 211 deletions(-)
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 79334c8ca1f62a2b78a682a8eae5f89eebe90112 Author: Niklas Haas <git@haasn.dev> AuthorDate: Fri Feb 27 10:30:00 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/ops: add subsampling shift to SwsOpExec Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/ops.c | 12 ++++++++++-- libswscale/ops_internal.h | 9 +++++++-- libswscale/x86/ops_common.asm | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 3aba144246..0b10692a82 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -982,24 +982,32 @@ static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, for (int i = 0; i < p->planes_in; i++) { const int idx = p->idx_in[i]; - const int sub_x = (idx == 1 || idx == 2) ? indesc->log2_chroma_w : 0; + const int chroma = idx == 1 || idx == 2; + const int sub_x = chroma ? indesc->log2_chroma_w : 0; + const int sub_y = chroma ? indesc->log2_chroma_h : 0; const int plane_w = (aligned_w + sub_x) >> sub_x; const int plane_pad = (comp->over_read + sub_x) >> sub_x; const int plane_size = plane_w * p->pixel_bits_in >> 3; if (comp->slice_align) p->memcpy_in |= plane_size + plane_pad > in.linesize[i]; exec->in_stride[i] = in.linesize[i]; + exec->in_sub_y[i] = sub_y; + exec->in_sub_x[i] = sub_x; } for (int i = 0; i < p->planes_out; i++) { const int idx = p->idx_out[i]; - const int sub_x = (idx == 1 || idx == 2) ? outdesc->log2_chroma_w : 0; + const int chroma = idx == 1 || idx == 2; + const int sub_x = chroma ? outdesc->log2_chroma_w : 0; + const int sub_y = chroma ? outdesc->log2_chroma_h : 0; const int plane_w = (aligned_w + sub_x) >> sub_x; const int plane_pad = (comp->over_write + sub_x) >> sub_x; const int plane_size = plane_w * p->pixel_bits_out >> 3; if (comp->slice_align) p->memcpy_out |= plane_size + plane_pad > out.linesize[i]; exec->out_stride[i] = out.linesize[i]; + exec->out_sub_y[i] = sub_y; + exec->out_sub_x[i] = sub_x; } /* Pre-fill pointer bump for the main section only; this value does not diff --git a/libswscale/ops_internal.h b/libswscale/ops_internal.h index 1276b78617..e07ef5285f 100644 --- a/libswscale/ops_internal.h +++ b/libswscale/ops_internal.h @@ -76,13 +76,18 @@ typedef struct SwsOpExec { int32_t block_size_in; /* Size of a block of pixels in bytes */ int32_t block_size_out; + /* Subsampling factors for each plane */ + uint8_t in_sub_y[4], out_sub_y[4]; + uint8_t in_sub_x[4], out_sub_x[4]; + const AVFrame *src_frame_ptr; const AVFrame *dst_frame_ptr; } SwsOpExec; static_assert(sizeof(SwsOpExec) == 24 * sizeof(void *) + - 6 * sizeof(int32_t) + - 2 * sizeof(void *), + 6 * sizeof(int32_t) + + 16 * sizeof(uint8_t) + + 2 * sizeof(void *), "SwsOpExec layout mismatch"); /** diff --git a/libswscale/x86/ops_common.asm b/libswscale/x86/ops_common.asm index 23ccda4da3..6da33448f8 100644 --- a/libswscale/x86/ops_common.asm +++ b/libswscale/x86/ops_common.asm @@ -137,6 +137,10 @@ struc SwsOpExec .slice_h resd 1 .block_size_in resd 1 .block_size_out resd 1 + .in_sub_y4 resb 4 + .out_sub_y4 resb 4 + .in_sub_x4 resb 4 + .out_sub_x4 resb 4 .in_hwframe_ref resq 1 .out_hwframe_ref resq 1 endstruc
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit bca806d4f9cfb2acd032937cef346e1b5b1e9aab Author: Niklas Haas <git@haasn.dev> AuthorDate: Fri Feb 27 10:48:06 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/ops: avoid stack copies of SwsImg Instead, precompute the correctly swizzled data and stride in setup() and just reference the SwsOpExec fields directly. To avoid the stack copies in handle_tail() we can introduce a temporary array to hold just the pointers. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/ops.c | 102 +++++++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 56 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 0b10692a82..517a029064 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -935,27 +935,21 @@ static void op_pass_free(void *ptr) av_free(p); } -static inline SwsImg img_shift_idx(const SwsImg *base, const int y, - const int plane_idx[4]) +static inline void get_row_data(const SwsOpPass *p, const int y, + const uint8_t *in[4], uint8_t *out[4]) { - SwsImg img = *base; - for (int i = 0; i < 4; i++) { - const int idx = plane_idx[i]; - if (idx >= 0) { - const int yshift = y >> ff_fmt_vshift(base->fmt, idx); - img.data[i] = base->data[idx] + yshift * base->linesize[idx]; - } else { - img.data[i] = NULL; - } - } - return img; + const SwsOpExec *base = &p->exec_base; + for (int i = 0; i < p->planes_in; i++) + in[i] = base->in[i] + (y >> base->in_sub_y[i]) * base->in_stride[i]; + for (int i = 0; i < p->planes_out; i++) + out[i] = base->out[i] + (y >> base->out_sub_y[i]) * base->out_stride[i]; } -static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, +static void op_pass_setup(const SwsImg *out, const SwsImg *in, const SwsPass *pass) { - const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in_base->fmt); - const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out_base->fmt); + const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->fmt); + const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt); SwsOpPass *p = pass->priv; SwsOpExec *exec = &p->exec_base; @@ -974,12 +968,6 @@ static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, p->memcpy_in = false; p->memcpy_out = false; - const SwsImg in = img_shift_idx(in_base, 0, p->idx_in); - const SwsImg out = img_shift_idx(out_base, 0, p->idx_out); - - exec->src_frame_ptr = in.frame_ptr; - exec->dst_frame_ptr = out.frame_ptr; - for (int i = 0; i < p->planes_in; i++) { const int idx = p->idx_in[i]; const int chroma = idx == 1 || idx == 2; @@ -989,8 +977,9 @@ static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, const int plane_pad = (comp->over_read + sub_x) >> sub_x; const int plane_size = plane_w * p->pixel_bits_in >> 3; if (comp->slice_align) - p->memcpy_in |= plane_size + plane_pad > in.linesize[i]; - exec->in_stride[i] = in.linesize[i]; + p->memcpy_in |= plane_size + plane_pad > in->linesize[idx]; + exec->in[i] = in->data[idx]; + exec->in_stride[i] = in->linesize[idx]; exec->in_sub_y[i] = sub_y; exec->in_sub_x[i] = sub_x; } @@ -1004,8 +993,9 @@ static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, const int plane_pad = (comp->over_write + sub_x) >> sub_x; const int plane_size = plane_w * p->pixel_bits_out >> 3; if (comp->slice_align) - p->memcpy_out |= plane_size + plane_pad > out.linesize[i]; - exec->out_stride[i] = out.linesize[i]; + p->memcpy_out |= plane_size + plane_pad > out->linesize[idx]; + exec->out[i] = out->data[idx]; + exec->out_stride[i] = out->linesize[idx]; exec->out_sub_y[i] = sub_y; exec->out_sub_x[i] = sub_x; } @@ -1015,44 +1005,49 @@ static void op_pass_setup(const SwsImg *out_base, const SwsImg *in_base, * process a single line */ const int blocks_main = p->num_blocks - p->memcpy_out; for (int i = 0; i < 4; i++) { - exec->in_bump[i] = in.linesize[i] - blocks_main * exec->block_size_in; - exec->out_bump[i] = out.linesize[i] - blocks_main * exec->block_size_out; + exec->in_bump[i] = exec->in_stride[i] - blocks_main * exec->block_size_in; + exec->out_bump[i] = exec->out_stride[i] - blocks_main * exec->block_size_out; } + + exec->src_frame_ptr = in->frame_ptr; + exec->dst_frame_ptr = out->frame_ptr; } /* Dispatch kernel over the last column of the image using memcpy */ static av_always_inline void handle_tail(const SwsOpPass *p, SwsOpExec *exec, - const SwsImg *out_base, const bool copy_out, - const SwsImg *in_base, const bool copy_in, + const bool copy_out, const bool copy_in, int y, const int h) { DECLARE_ALIGNED_64(uint8_t, tmp)[2][4][sizeof(uint32_t[128])]; + const SwsOpExec *base = &p->exec_base; const SwsCompiledOp *comp = &p->comp; const int tail_size_in = p->tail_size_in; const int tail_size_out = p->tail_size_out; const int bx = p->num_blocks - 1; - SwsImg in = img_shift_idx(in_base, y, p->idx_in); - SwsImg out = img_shift_idx(out_base, y, p->idx_out); + const uint8_t *in_data[4]; + uint8_t *out_data[4]; + get_row_data(p, y, in_data, out_data); + for (int i = 0; i < p->planes_in; i++) { - in.data[i] += p->tail_off_in; + in_data[i] += p->tail_off_in; if (copy_in) { exec->in[i] = (void *) tmp[0][i]; exec->in_stride[i] = sizeof(tmp[0][i]); } else { - exec->in[i] = in.data[i]; + exec->in[i] = in_data[i]; } } for (int i = 0; i < p->planes_out; i++) { - out.data[i] += p->tail_off_out; + out_data[i] += p->tail_off_out; if (copy_out) { exec->out[i] = (void *) tmp[1][i]; exec->out_stride[i] = sizeof(tmp[1][i]); } else { - exec->out[i] = out.data[i]; + exec->out[i] = out_data[i]; } } @@ -1060,8 +1055,8 @@ handle_tail(const SwsOpPass *p, SwsOpExec *exec, if (copy_in) { for (int i = 0; i < p->planes_in; i++) { av_assert2(tmp[0][i] + tail_size_in < (uint8_t *) tmp[1]); - memcpy(tmp[0][i], in.data[i], tail_size_in); - in.data[i] += in.linesize[i]; + memcpy(tmp[0][i], in_data[i], tail_size_in); + in_data[i] += base->in_stride[i]; /* exec->in_stride was clobbered */ } } @@ -1070,39 +1065,33 @@ handle_tail(const SwsOpPass *p, SwsOpExec *exec, if (copy_out) { for (int i = 0; i < p->planes_out; i++) { av_assert2(tmp[1][i] + tail_size_out < (uint8_t *) tmp[2]); - memcpy(out.data[i], tmp[1][i], tail_size_out); - out.data[i] += out.linesize[i]; + memcpy(out_data[i], tmp[1][i], tail_size_out); + out_data[i] += base->out_stride[i]; } } for (int i = 0; i < 4; i++) { if (!copy_in && exec->in[i]) - exec->in[i] += in.linesize[i]; + exec->in[i] += exec->in_stride[i]; if (!copy_out && exec->out[i]) - exec->out[i] += out.linesize[i]; + exec->out[i] += exec->out_stride[i]; } } } -static void op_pass_run(const SwsImg *out_base, const SwsImg *in_base, - const int y, const int h, const SwsPass *pass) +static void op_pass_run(const SwsImg *out, const SwsImg *in, const int y, + const int h, const SwsPass *pass) { const SwsOpPass *p = pass->priv; const SwsCompiledOp *comp = &p->comp; - const SwsImg in = img_shift_idx(in_base, y, p->idx_in); - const SwsImg out = img_shift_idx(out_base, y, p->idx_out); /* Fill exec metadata for this slice */ DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base; exec.slice_y = y; exec.slice_h = h; - for (int i = 0; i < 4; i++) { - exec.in[i] = in.data[i]; - exec.out[i] = out.data[i]; - } - exec.src_frame_ptr = in_base->frame_ptr; - exec.dst_frame_ptr = out_base->frame_ptr; + exec.src_frame_ptr = in->frame_ptr; + exec.dst_frame_ptr = out->frame_ptr; /** * To ensure safety, we need to consider the following: @@ -1129,22 +1118,23 @@ static void op_pass_run(const SwsImg *out_base, const SwsImg *in_base, const int h_main = h - memcpy_in; /* Handle main section */ + get_row_data(p, y, exec.in, exec.out); comp->func(&exec, comp->priv, 0, y, blocks_main, y + h_main); if (memcpy_in) { /* Safe part of last row */ for (int i = 0; i < 4; i++) { - exec.in[i] += h_main * in.linesize[i]; - exec.out[i] += h_main * out.linesize[i]; + exec.in[i] += h_main * exec.in_stride[i]; + exec.out[i] += h_main * exec.out_stride[i]; } comp->func(&exec, comp->priv, 0, y + h_main, num_blocks - 1, y + h); } /* Handle last column via memcpy, takes over `exec` so call these last */ if (memcpy_out) - handle_tail(p, &exec, out_base, true, in_base, false, y, h_main); + handle_tail(p, &exec, true, false, y, h_main); if (memcpy_in) - handle_tail(p, &exec, out_base, memcpy_out, in_base, true, y + h_main, 1); + handle_tail(p, &exec, memcpy_out, true, y + h_main, 1); } static int rw_planes(const SwsOp *op)
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 62dc591a80af9c96739a79196b16e2d652721ca1 Author: Niklas Haas <git@haasn.dev> AuthorDate: Fri Feb 27 11:00:39 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/ops: correctly shift pointers for last row handling The current logic didn't take into account the possible plane shift. Just re-compute the correctly shifted pointers using the row position. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/ops.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 517a029064..61926c4b38 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -1123,10 +1123,7 @@ static void op_pass_run(const SwsImg *out, const SwsImg *in, const int y, if (memcpy_in) { /* Safe part of last row */ - for (int i = 0; i < 4; i++) { - exec.in[i] += h_main * exec.in_stride[i]; - exec.out[i] += h_main * exec.out_stride[i]; - } + get_row_data(p, y + h_main, exec.in, exec.out); comp->func(&exec, comp->priv, 0, y + h_main, num_blocks - 1, y + h); }
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 363779a4bb1c42432934222cc5f647eba826d13c Author: Niklas Haas <git@haasn.dev> AuthorDate: Thu Feb 26 18:15:02 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/ops: don't set src/dst_frame_ptr in op_pass_run() Already set by setup(). Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/ops.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index 61926c4b38..8a93d93d00 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -1090,9 +1090,6 @@ static void op_pass_run(const SwsImg *out, const SwsImg *in, const int y, exec.slice_y = y; exec.slice_h = h; - exec.src_frame_ptr = in->frame_ptr; - exec.dst_frame_ptr = out->frame_ptr; - /** * To ensure safety, we need to consider the following: *
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit d89765eb28e6b2cab4f920ee30be558649911b35 Author: Niklas Haas <git@haasn.dev> AuthorDate: Sat Feb 21 16:50:40 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: simplify output buffer management This function was originally written to support the use case of e.g. partially allocated planes that implicitly reference the original input image, but I've decided that this is stupid and doesn't currently work anyways. Plus, I have plans to kill SwsImg, so we need to simplify this mess. Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 1c3a089cfe..55636a2816 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -844,23 +844,6 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color) ff_color_update_dynamic(&graph->src.color, color); } -static SwsImg pass_output(const SwsPass *pass, const SwsImg *fallback) -{ - if (!pass) - return *fallback; - - SwsImg img = pass->output->img; - img.frame_ptr = fallback->frame_ptr; - for (int i = 0; i < FF_ARRAY_ELEMS(img.data); i++) { - if (!img.data[i]) { - img.data[i] = fallback->data[i]; - img.linesize[i] = fallback->linesize[i]; - } - } - - return img; -} - void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input) { av_assert0(output->fmt == graph->dst.hw_format || @@ -871,8 +854,8 @@ void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input for (int i = 0; i < graph->num_passes; i++) { const SwsPass *pass = graph->passes[i]; graph->exec.pass = pass; - graph->exec.input = pass_output(pass->input, input); - graph->exec.output = pass_output(pass, output); + graph->exec.input = pass->input ? pass->input->output->img : *input; + graph->exec.output = pass->output->buf[0] ? pass->output->img : *output; if (pass->setup) pass->setup(&graph->exec.output, &graph->exec.input, pass); avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0);
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit e9d1ed3fdcfd649070a2f06a88ec51d6ec78932f Author: Niklas Haas <git@haasn.dev> AuthorDate: Thu Feb 26 16:49:19 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: avoid stack copies of SwsImg In the process of nuking this abstraction in favor of AVFrame. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 70 ++++++++++++++++++++++++++++++++---------------------- libswscale/graph.h | 8 ------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 55636a2816..07248f2ba6 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -157,26 +157,37 @@ static int pass_append(SwsGraph *graph, enum AVPixelFormat fmt, int w, int h, return 0; } -static void run_copy(const SwsImg *out_base, const SwsImg *in_base, - int y, int h, const SwsPass *pass) +static void img_shift(const SwsImg *img, const int y, uint8_t *data[4]) { - SwsImg in = ff_sws_img_shift(in_base, y); - SwsImg out = ff_sws_img_shift(out_base, y); - - for (int i = 0; i < FF_ARRAY_ELEMS(out.data) && out.data[i]; i++) { - const int lines = h >> ff_fmt_vshift(in.fmt, i); - av_assert1(in.data[i]); + for (int i = 0; i < 4; i++) { + if (img->data[i]) + data[i] = img->data[i] + (y >> ff_fmt_vshift(img->fmt, i)) * img->linesize[i]; + else + data[i] = NULL; + } +} - if (in.data[i] == out.data[i]) { - av_assert0(in.linesize[i] == out.linesize[i]); - } else if (in.linesize[i] == out.linesize[i]) { - memcpy(out.data[i], in.data[i], lines * out.linesize[i]); +static void run_copy(const SwsImg *out, const SwsImg *in, int y, int h, + const SwsPass *pass) +{ + uint8_t *in_data[4], *out_data[4]; + img_shift(in, y, in_data); + img_shift(out, y, out_data); + + for (int i = 0; i < 4 && out_data[i]; i++) { + const int lines = h >> ff_fmt_vshift(in->fmt, i); + av_assert1(in_data[i]); + + if (in_data[i] == out_data[i]) { + av_assert0(in->linesize[i] == out->linesize[i]); + } else if (in->linesize[i] == out->linesize[i]) { + memcpy(out_data[i], in_data[i], lines * out->linesize[i]); } else { - const int linesize = FFMIN(out.linesize[i], in.linesize[i]); + const int linesize = FFMIN(out->linesize[i], in->linesize[i]); for (int j = 0; j < lines; j++) { - memcpy(out.data[i], in.data[i], linesize); - in.data[i] += in.linesize[i]; - out.data[i] += out.linesize[i]; + memcpy(out_data[i], in_data[i], linesize); + in_data[i] += in->linesize[i]; + out_data[i] += out->linesize[i]; } } } @@ -266,26 +277,28 @@ static inline SwsContext *slice_ctx(const SwsPass *pass, int y) return sws; } -static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base, +static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass) { SwsContext *sws = slice_ctx(pass, y); SwsInternal *c = sws_internal(sws); - const SwsImg in = ff_sws_img_shift(in_base, y); + uint8_t *in_data[4]; + img_shift(in, y, in_data); - c->convert_unscaled(c, (const uint8_t *const *) in.data, in.linesize, y, h, + c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h, out->data, out->linesize); } -static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in, +static void run_legacy_swscale(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass) { SwsContext *sws = slice_ctx(pass, y); SwsInternal *c = sws_internal(sws); - const SwsImg out = ff_sws_img_shift(out_base, y); + uint8_t *out_data[4]; + img_shift(out, y, out_data); ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0, - sws->src_h, out.data, out.linesize, y, h); + sws->src_h, out_data, out->linesize, y, h); } static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos, @@ -621,15 +634,16 @@ static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass ff_sws_lut3d_update(lut, &pass->graph->src.color); } -static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base, - int y, int h, const SwsPass *pass) +static void run_lut3d(const SwsImg *out, const SwsImg *in, int y, int h, + const SwsPass *pass) { SwsLut3D *lut = pass->priv; - const SwsImg in = ff_sws_img_shift(in_base, y); - const SwsImg out = ff_sws_img_shift(out_base, y); + uint8_t *in_data[4], *out_data[4]; + img_shift(in, y, in_data); + img_shift(out, y, out_data); - ff_sws_lut3d_apply(lut, in.data[0], in.linesize[0], out.data[0], - out.linesize[0], pass->width, h); + ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0], + out->linesize[0], pass->width, h); } static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, diff --git a/libswscale/graph.h b/libswscale/graph.h index c93c37a98e..94b2051d94 100644 --- a/libswscale/graph.h +++ b/libswscale/graph.h @@ -45,14 +45,6 @@ static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int p return (plane == 1 || plane == 2) ? desc->log2_chroma_h : 0; } -static av_const inline SwsImg ff_sws_img_shift(const SwsImg *base, const int y) -{ - SwsImg img = *base; - for (int i = 0; i < 4 && img.data[i]; i++) - img.data[i] += (y >> ff_fmt_vshift(img.fmt, i)) * img.linesize[i]; - return img; -} - typedef struct SwsPass SwsPass; typedef struct SwsGraph SwsGraph;
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 5121665463b66332c0d32644bf7eeea52e635a63 Author: Niklas Haas <git@haasn.dev> AuthorDate: Thu Feb 26 18:07:58 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: use AVFrame to track internal allocation This commit replaces the AVBufferRef inside SwsPassBuffer by an AVFrame, in anticipation of the SwsImg removal. Incidentally, we could also now just use av_frame_get_buffer() here, but at the cost of breaking the 1:1 relationship between planes and buffers, which is required for per-plane refcopies. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 68 ++++++++++++++++++++++++++++++++---------------------- libswscale/graph.h | 2 +- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 07248f2ba6..68050408bf 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -38,42 +38,29 @@ #include "graph.h" #include "ops.h" -static int buffer_get_sizes(SwsPassBuffer *buffer, size_t sizes[4]) +/* Allocates one buffer per plane */ +static int frame_alloc_planes(AVFrame *dst) { - const int align = av_cpu_max_align(); - const int format = buffer->img.fmt; - const int width = FFALIGN(buffer->width, align); - const int height = buffer->height; - int ret; - - ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL); + int ret = av_image_check_size2(dst->width, dst->height, INT64_MAX, + dst->format, 0, NULL); if (ret < 0) return ret; - int *linesize = buffer->img.linesize; - ret = av_image_fill_linesizes(linesize, format, width); + const int align = av_cpu_max_align(); + const int aligned_w = FFALIGN(dst->width, align); + ret = av_image_fill_linesizes(dst->linesize, dst->format, aligned_w); if (ret < 0) return ret; ptrdiff_t linesize1[4]; for (int i = 0; i < 4; i++) - linesize1[i] = linesize[i] = FFALIGN(linesize[i], align); - - return av_image_fill_plane_sizes(sizes, format, height, linesize1); -} - -static int pass_alloc_output(SwsPass *pass) -{ - if (!pass || pass->output->buf[0]) - return 0; + linesize1[i] = dst->linesize[i] = FFALIGN(dst->linesize[i], align); size_t sizes[4]; - SwsPassBuffer *output = pass->output; - int ret = buffer_get_sizes(output, sizes); + ret = av_image_fill_plane_sizes(sizes, dst->format, dst->height, linesize1); if (ret < 0) return ret; - const int align = av_cpu_max_align(); for (int i = 0; i < 4; i++) { if (!sizes[i]) break; @@ -83,17 +70,44 @@ static int pass_alloc_output(SwsPass *pass) AVBufferRef *buf = av_buffer_alloc(sizes[i] + align); if (!buf) return AVERROR(ENOMEM); - output->img.data[i] = (uint8_t *) FFALIGN((uintptr_t) buf->data, align); - output->buf[i] = buf; + dst->data[i] = (uint8_t *) FFALIGN((uintptr_t) buf->data, align); + dst->buf[i] = buf; + } + + return 0; +} + +static int pass_alloc_output(SwsPass *pass) +{ + if (!pass || pass->output->frame) + return 0; + + SwsPassBuffer *buffer = pass->output; + AVFrame *frame = av_frame_alloc(); + if (!frame) + return AVERROR(ENOMEM); + frame->format = pass->format; + frame->width = buffer->width; + frame->height = buffer->height; + + int ret = frame_alloc_planes(frame); + if (ret < 0) { + av_frame_free(&frame); + return ret; } + + buffer->frame = frame; + buffer->img.fmt = pass->format; + buffer->img.frame_ptr = frame; + memcpy(buffer->img.data, frame->data, sizeof(frame->data)); + memcpy(buffer->img.linesize, frame->linesize, sizeof(frame->linesize)); return 0; } static void free_buffer(AVRefStructOpaque opaque, void *obj) { SwsPassBuffer *buffer = obj; - for (int i = 0; i < FF_ARRAY_ELEMS(buffer->buf); i++) - av_buffer_unref(&buffer->buf[i]); + av_frame_free(&buffer->frame); } SwsPass *ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, @@ -869,7 +883,7 @@ void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input const SwsPass *pass = graph->passes[i]; graph->exec.pass = pass; graph->exec.input = pass->input ? pass->input->output->img : *input; - graph->exec.output = pass->output->buf[0] ? pass->output->img : *output; + graph->exec.output = pass->output->frame ? pass->output->img : *output; if (pass->setup) pass->setup(&graph->exec.output, &graph->exec.input, pass); avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0); diff --git a/libswscale/graph.h b/libswscale/graph.h index 94b2051d94..e231938e72 100644 --- a/libswscale/graph.h +++ b/libswscale/graph.h @@ -61,7 +61,7 @@ typedef void (*sws_filter_run_t)(const SwsImg *out, const SwsImg *in, typedef struct SwsPassBuffer { SwsImg img; int width, height; /* dimensions of this buffer */ - AVBufferRef *buf[4]; /* one per plane */ + AVFrame *frame; /* backing storage for frame data */ } SwsPassBuffer; /**
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 846823b174703acae204cc6f9dfa5ba6f794436f Author: Niklas Haas <git@haasn.dev> AuthorDate: Thu Feb 26 20:21:59 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: don't pointlessly align data buffers Since d67d81a3748aa877c9c9, enabling asm explicitly requires aligned malloc, so this FFALIGN accomplishes nothing. Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 68050408bf..97cd6adbb2 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -64,13 +64,10 @@ static int frame_alloc_planes(AVFrame *dst) for (int i = 0; i < 4; i++) { if (!sizes[i]) break; - if (sizes[i] > SIZE_MAX - align) - return AVERROR(EINVAL); - - AVBufferRef *buf = av_buffer_alloc(sizes[i] + align); + AVBufferRef *buf = av_buffer_alloc(sizes[i]); if (!buf) return AVERROR(ENOMEM); - dst->data[i] = (uint8_t *) FFALIGN((uintptr_t) buf->data, align); + dst->data[i] = buf->data; dst->buf[i] = buf; }
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 4d7b1c3685038321975d575fca1e498183d69139 Author: Niklas Haas <git@haasn.dev> AuthorDate: Thu Feb 26 19:13:13 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: move frame->field init logic to SwsGraph And have ff_sws_graph_run() just take a bare AVFrame. This will help with an upcoming change, aside from being a bit friendlier towards API users in general. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 48 +++++++++++++++++++++++++++++++++++++++++------- libswscale/graph.h | 5 +++-- libswscale/swscale.c | 38 +------------------------------------- 3 files changed, 45 insertions(+), 46 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 97cd6adbb2..5469012f37 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -869,18 +869,52 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color) ff_color_update_dynamic(&graph->src.color, color); } -void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input) +static SwsImg get_field(const AVFrame *frame, int field) { - av_assert0(output->fmt == graph->dst.hw_format || - output->fmt == graph->dst.format); - av_assert0(input->fmt == graph->src.hw_format || - input->fmt == graph->src.format); + SwsImg img = {0}; + + img.frame_ptr = frame; + img.fmt = frame->format; + for (int i = 0; i < 4; i++) { + img.data[i] = frame->data[i]; + img.linesize[i] = frame->linesize[i]; + } + + if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) { + av_assert1(!field); + return img; + } + + if (field == FIELD_BOTTOM) { + /* Odd rows, offset by one line */ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + for (int i = 0; i < 4; i++) { + if (img.data[i]) + img.data[i] += img.linesize[i]; + if (desc->flags & AV_PIX_FMT_FLAG_PAL) + break; + } + } + + /* Take only every second line */ + for (int i = 0; i < 4; i++) + img.linesize[i] <<= 1; + + return img; +} + +void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src) +{ + av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format); + av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format); + SwsImg input = get_field(src, graph->field); + SwsImg output = get_field(dst, graph->field); for (int i = 0; i < graph->num_passes; i++) { const SwsPass *pass = graph->passes[i]; graph->exec.pass = pass; - graph->exec.input = pass->input ? pass->input->output->img : *input; - graph->exec.output = pass->output->frame ? pass->output->img : *output; + graph->exec.input = pass->input ? pass->input->output->img : input; + graph->exec.output = pass->output->frame ? pass->output->img : output; if (pass->setup) pass->setup(&graph->exec.output, &graph->exec.input, pass); avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0); diff --git a/libswscale/graph.h b/libswscale/graph.h index e231938e72..6d3db640fd 100644 --- a/libswscale/graph.h +++ b/libswscale/graph.h @@ -189,8 +189,9 @@ int ff_sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat * int field, SwsGraph **graph); /** - * Dispatch the filter graph on a single field. Internally threaded. + * Dispatch the filter graph on a single field of the given frames. Internally + * threaded. */ -void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input); +void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src); #endif /* SWSCALE_GRAPH_H */ diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 5dbd93e0a2..b04df78a5d 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1321,40 +1321,6 @@ int sws_receive_slice(SwsContext *sws, unsigned int slice_start, dst, c->frame_dst->linesize, slice_start, slice_height); } -static SwsImg get_frame_img(const AVFrame *frame, int field) -{ - SwsImg img = {0}; - - img.frame_ptr = frame; - img.fmt = frame->format; - for (int i = 0; i < 4; i++) { - img.data[i] = frame->data[i]; - img.linesize[i] = frame->linesize[i]; - } - - if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) { - av_assert1(!field); - return img; - } - - if (field == FIELD_BOTTOM) { - /* Odd rows, offset by one line */ - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); - for (int i = 0; i < 4; i++) { - if (img.data[i]) - img.data[i] += img.linesize[i]; - if (desc->flags & AV_PIX_FMT_FLAG_PAL) - break; - } - } - - /* Take only every second line */ - for (int i = 0; i < 4; i++) - img.linesize[i] <<= 1; - - return img; -} - /* Subset of av_frame_ref() that only references (video) data buffers */ static int frame_ref(AVFrame *dst, const AVFrame *src) { @@ -1419,9 +1385,7 @@ int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src) for (int field = 0; field < 2; field++) { SwsGraph *graph = c->graph[field]; - SwsImg input = get_frame_img(src, field); - SwsImg output = get_frame_img(dst, field); - ff_sws_graph_run(graph, &output, &input); + ff_sws_graph_run(graph, dst, src); if (!graph->dst.interlaced) break; }
This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg. commit 67f36272671be9405248386bfbc467a6a772d5ce Author: Niklas Haas <git@haasn.dev> AuthorDate: Fri Feb 27 11:02:38 2026 +0100 Commit: Niklas Haas <ffmpeg@haasn.dev> CommitDate: Fri Feb 27 16:18:34 2026 +0000 swscale/graph: nuke SwsImg This has now become fully redundant with AVFrame, especially since the existence of SwsPassBuffer. Delete it, simplifying a lot of things and avoiding reinventing the wheel everywhere. Also generally reduces overhead, since there is less redundant copying going on. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <git@haasn.dev> --- libswscale/graph.c | 98 +++++++++++++++++++++++++++--------------------------- libswscale/graph.h | 27 ++++++--------- libswscale/ops.c | 12 +++---- 3 files changed, 66 insertions(+), 71 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index 5469012f37..6a17a12496 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -94,10 +94,6 @@ static int pass_alloc_output(SwsPass *pass) } buffer->frame = frame; - buffer->img.fmt = pass->format; - buffer->img.frame_ptr = frame; - memcpy(buffer->img.data, frame->data, sizeof(frame->data)); - memcpy(buffer->img.linesize, frame->linesize, sizeof(frame->linesize)); return 0; } @@ -141,9 +137,8 @@ SwsPass *ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, } /* Align output buffer to include extra slice padding */ - pass->output->img.fmt = fmt; - pass->output->width = pass->width; - pass->output->height = pass->slice_h * pass->num_slices; + pass->output->width = pass->width; + pass->output->height = pass->slice_h * pass->num_slices; ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass); if (ret < 0) @@ -168,25 +163,25 @@ static int pass_append(SwsGraph *graph, enum AVPixelFormat fmt, int w, int h, return 0; } -static void img_shift(const SwsImg *img, const int y, uint8_t *data[4]) +static void frame_shift(const AVFrame *f, const int y, uint8_t *data[4]) { for (int i = 0; i < 4; i++) { - if (img->data[i]) - data[i] = img->data[i] + (y >> ff_fmt_vshift(img->fmt, i)) * img->linesize[i]; + if (f->data[i]) + data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i]; else data[i] = NULL; } } -static void run_copy(const SwsImg *out, const SwsImg *in, int y, int h, +static void run_copy(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { uint8_t *in_data[4], *out_data[4]; - img_shift(in, y, in_data); - img_shift(out, y, out_data); + frame_shift(in, y, in_data); + frame_shift(out, y, out_data); for (int i = 0; i < 4 && out_data[i]; i++) { - const int lines = h >> ff_fmt_vshift(in->fmt, i); + const int lines = h >> ff_fmt_vshift(in->format, i); av_assert1(in_data[i]); if (in_data[i] == out_data[i]) { @@ -204,7 +199,7 @@ static void run_copy(const SwsImg *out, const SwsImg *in, int y, int h, } } -static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h, +static void run_rgb0(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { SwsInternal *c = pass->priv; @@ -225,7 +220,7 @@ static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h, } } -static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h, +static void run_xyz2rgb(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { const SwsInternal *c = pass->priv; @@ -234,7 +229,7 @@ static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h, pass->width, h); } -static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h, +static void run_rgb2xyz(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { const SwsInternal *c = pass->priv; @@ -255,7 +250,7 @@ static void free_legacy_swscale(void *priv) sws_free_context(&sws); } -static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in, +static void setup_legacy_swscale(const AVFrame *out, const AVFrame *in, const SwsPass *pass) { SwsContext *sws = pass->priv; @@ -288,25 +283,25 @@ static inline SwsContext *slice_ctx(const SwsPass *pass, int y) return sws; } -static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in, +static void run_legacy_unscaled(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { SwsContext *sws = slice_ctx(pass, y); SwsInternal *c = sws_internal(sws); uint8_t *in_data[4]; - img_shift(in, y, in_data); + frame_shift(in, y, in_data); c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h, out->data, out->linesize); } -static void run_legacy_swscale(const SwsImg *out, const SwsImg *in, +static void run_legacy_swscale(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { SwsContext *sws = slice_ctx(pass, y); SwsInternal *c = sws_internal(sws); uint8_t *out_data[4]; - img_shift(out, y, out_data); + frame_shift(out, y, out_data); ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0, sws->src_h, out_data, out->linesize, y, h); @@ -637,7 +632,7 @@ static void free_lut3d(void *priv) ff_sws_lut3d_free(&lut); } -static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass) +static void setup_lut3d(const AVFrame *out, const AVFrame *in, const SwsPass *pass) { SwsLut3D *lut = pass->priv; @@ -645,13 +640,13 @@ static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass ff_sws_lut3d_update(lut, &pass->graph->src.color); } -static void run_lut3d(const SwsImg *out, const SwsImg *in, int y, int h, +static void run_lut3d(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass) { SwsLut3D *lut = pass->priv; uint8_t *in_data[4], *out_data[4]; - img_shift(in, y, in_data); - img_shift(out, y, out_data); + frame_shift(in, y, in_data); + frame_shift(out, y, out_data); ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0], out->linesize[0], pass->width, h); @@ -769,7 +764,7 @@ static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, const int slice_y = jobnr * pass->slice_h; const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y); - pass->run(&graph->exec.output, &graph->exec.input, slice_y, slice_h, pass); + pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass); } int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, @@ -786,6 +781,14 @@ int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat * graph->field = field; graph->opts_copy = *ctx; + for (int i = 0; i < FF_ARRAY_ELEMS(graph->field_tmp); i++) { + graph->field_tmp[i] = av_frame_alloc(); + if (!graph->field_tmp[i]) { + ret = AVERROR(ENOMEM); + goto error; + } + } + ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph, sws_graph_worker, NULL, ctx->threads); if (ret == AVERROR(ENOSYS)) @@ -824,6 +827,9 @@ void ff_sws_graph_free(SwsGraph **pgraph) } av_free(graph->passes); + for (int i = 0; i < FF_ARRAY_ELEMS(graph->field_tmp); i++) + av_frame_free(&graph->field_tmp[i]); + av_free(graph); *pgraph = NULL; } @@ -869,28 +875,22 @@ void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color) ff_color_update_dynamic(&graph->src.color, color); } -static SwsImg get_field(const AVFrame *frame, int field) +static const AVFrame *get_field(SwsGraph *graph, const AVFrame *frame, + AVFrame *restrict tmp) { - SwsImg img = {0}; - - img.frame_ptr = frame; - img.fmt = frame->format; - for (int i = 0; i < 4; i++) { - img.data[i] = frame->data[i]; - img.linesize[i] = frame->linesize[i]; - } - if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) { - av_assert1(!field); - return img; + av_assert1(!graph->field); + return frame; } - if (field == FIELD_BOTTOM) { + *tmp = *frame; + + if (graph->field == FIELD_BOTTOM) { /* Odd rows, offset by one line */ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); for (int i = 0; i < 4; i++) { - if (img.data[i]) - img.data[i] += img.linesize[i]; + if (tmp->data[i]) + tmp->data[i] += frame->linesize[i]; if (desc->flags & AV_PIX_FMT_FLAG_PAL) break; } @@ -898,25 +898,25 @@ static SwsImg get_field(const AVFrame *frame, int field) /* Take only every second line */ for (int i = 0; i < 4; i++) - img.linesize[i] <<= 1; + tmp->linesize[i] <<= 1; - return img; + return tmp; } void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src) { av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format); av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format); - SwsImg input = get_field(src, graph->field); - SwsImg output = get_field(dst, graph->field); + const AVFrame *src_field = get_field(graph, src, graph->field_tmp[0]); + const AVFrame *dst_field = get_field(graph, dst, graph->field_tmp[1]); for (int i = 0; i < graph->num_passes; i++) { const SwsPass *pass = graph->passes[i]; graph->exec.pass = pass; - graph->exec.input = pass->input ? pass->input->output->img : input; - graph->exec.output = pass->output->frame ? pass->output->img : output; + graph->exec.input = pass->input ? pass->input->output->frame : src_field; + graph->exec.output = pass->output->frame ? pass->output->frame : dst_field; if (pass->setup) - pass->setup(&graph->exec.output, &graph->exec.input, pass); + pass->setup(graph->exec.output, graph->exec.input, pass); avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0); } } diff --git a/libswscale/graph.h b/libswscale/graph.h index 6d3db640fd..9ddf2ad1c9 100644 --- a/libswscale/graph.h +++ b/libswscale/graph.h @@ -29,16 +29,6 @@ #include "swscale.h" #include "format.h" -/** - * Represents a view into a single field of frame data. - */ -typedef struct SwsImg { - enum AVPixelFormat fmt; - uint8_t *data[4]; /* points to y=0 */ - int linesize[4]; - const AVFrame *frame_ptr; /* Pointer to the original AVframe */ -} SwsImg; - static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); @@ -52,16 +42,15 @@ typedef struct SwsGraph SwsGraph; * Output `h` lines of filtered data. `out` and `in` point to the * start of the image buffer for this pass. */ -typedef void (*sws_filter_run_t)(const SwsImg *out, const SwsImg *in, +typedef void (*sws_filter_run_t)(const AVFrame *out, const AVFrame *in, int y, int h, const SwsPass *pass); /** * Represents an allocated output buffer for a filter pass. */ typedef struct SwsPassBuffer { - SwsImg img; int width, height; /* dimensions of this buffer */ - AVFrame *frame; /* backing storage for frame data */ + AVFrame *frame; } SwsPassBuffer; /** @@ -97,7 +86,7 @@ struct SwsPass { /** * Called once from the main thread before running the filter. Optional. */ - void (*setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass); + void (*setup)(const AVFrame *out, const AVFrame *in, const SwsPass *pass); /** * Optional private state and associated free() function. @@ -134,14 +123,20 @@ typedef struct SwsGraph { SwsFormat src, dst; int field; + /** + * Temporary storage to hold individual fields of the input frames. + * No actual ownership over the data. + */ + AVFrame *field_tmp[2]; + /** * Temporary execution state inside ff_sws_graph_run(); used to pass * data to worker threads. */ struct { const SwsPass *pass; /* current filter pass */ - SwsImg input; /* current filter pass input/output */ - SwsImg output; + const AVFrame *input; /* current filter pass input/output */ + const AVFrame *output; } exec; } SwsGraph; diff --git a/libswscale/ops.c b/libswscale/ops.c index 8a93d93d00..b3db758682 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -945,11 +945,11 @@ static inline void get_row_data(const SwsOpPass *p, const int y, out[i] = base->out[i] + (y >> base->out_sub_y[i]) * base->out_stride[i]; } -static void op_pass_setup(const SwsImg *out, const SwsImg *in, +static void op_pass_setup(const AVFrame *out, const AVFrame *in, const SwsPass *pass) { - const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->fmt); - const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt); + const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->format); + const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format); SwsOpPass *p = pass->priv; SwsOpExec *exec = &p->exec_base; @@ -1009,8 +1009,8 @@ static void op_pass_setup(const SwsImg *out, const SwsImg *in, exec->out_bump[i] = exec->out_stride[i] - blocks_main * exec->block_size_out; } - exec->src_frame_ptr = in->frame_ptr; - exec->dst_frame_ptr = out->frame_ptr; + exec->src_frame_ptr = in; + exec->dst_frame_ptr = out; } /* Dispatch kernel over the last column of the image using memcpy */ @@ -1079,7 +1079,7 @@ handle_tail(const SwsOpPass *p, SwsOpExec *exec, } } -static void op_pass_run(const SwsImg *out, const SwsImg *in, const int y, +static void op_pass_run(const AVFrame *out, const AVFrame *in, const int y, const int h, const SwsPass *pass) { const SwsOpPass *p = pass->priv;
participants (2)
-
ffmpeg-git -
Niklas Haas