/src/ffmpeg/libswscale/ops_chain.c
Line | Count | Source |
1 | | /** |
2 | | * Copyright (C) 2025 Niklas Haas |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "libavutil/avassert.h" |
22 | | #include "libavutil/mem.h" |
23 | | #include "libavutil/rational.h" |
24 | | |
25 | | #include "ops_chain.h" |
26 | | |
27 | | SwsOpChain *ff_sws_op_chain_alloc(void) |
28 | 0 | { |
29 | 0 | return av_mallocz(sizeof(SwsOpChain)); |
30 | 0 | } |
31 | | |
32 | | void ff_sws_op_chain_free_cb(void *ptr) |
33 | 0 | { |
34 | 0 | if (!ptr) |
35 | 0 | return; |
36 | | |
37 | 0 | SwsOpChain *chain = ptr; |
38 | 0 | for (int i = 0; i < chain->num_impl + 1; i++) { |
39 | 0 | if (chain->free[i]) |
40 | 0 | chain->free[i](&chain->impl[i].priv); |
41 | 0 | } |
42 | |
|
43 | 0 | av_free(chain); |
44 | 0 | } |
45 | | |
46 | | int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func, |
47 | | void (*free)(SwsOpPriv *), const SwsOpPriv *priv) |
48 | 0 | { |
49 | 0 | const int idx = chain->num_impl; |
50 | 0 | if (idx == SWS_MAX_OPS) |
51 | 0 | return AVERROR(EINVAL); |
52 | | |
53 | 0 | av_assert1(func); |
54 | 0 | chain->impl[idx].cont = func; |
55 | 0 | chain->impl[idx + 1].priv = *priv; |
56 | 0 | chain->free[idx + 1] = free; |
57 | 0 | chain->num_impl++; |
58 | 0 | return 0; |
59 | 0 | } |
60 | | |
61 | | #define q2pixel(type, q) ((q).den ? (type) (q).num / (q).den : 0) |
62 | | |
63 | | #if ARCH_AARCH64 |
64 | | int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out) |
65 | | { |
66 | | const SwsOp *op = params->op; |
67 | | const AVRational64 factor = op->scale.factor; |
68 | | switch (op->type) { |
69 | | case SWS_PIXEL_U8: out->priv.u8[0] = q2pixel(uint8_t, factor); break; |
70 | | case SWS_PIXEL_U16: out->priv.u16[0] = q2pixel(uint16_t, factor); break; |
71 | | case SWS_PIXEL_U32: out->priv.u32[0] = q2pixel(uint32_t, factor); break; |
72 | | case SWS_PIXEL_F32: out->priv.f32[0] = q2pixel(float, factor); break; |
73 | | default: return AVERROR(EINVAL); |
74 | | } |
75 | | |
76 | | return 0; |
77 | | } |
78 | | |
79 | | int ff_sws_setup_clamp(const SwsImplParams *params, SwsImplResult *out) |
80 | | { |
81 | | const SwsOp *op = params->op; |
82 | | for (int i = 0; i < 4; i++) { |
83 | | const AVRational64 limit = op->clamp.limit[i]; |
84 | | switch (op->type) { |
85 | | case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, limit); break; |
86 | | case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, limit); break; |
87 | | case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, limit); break; |
88 | | case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, limit); break; |
89 | | default: return AVERROR(EINVAL); |
90 | | } |
91 | | } |
92 | | |
93 | | return 0; |
94 | | } |
95 | | |
96 | | int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out) |
97 | | { |
98 | | const SwsOp *op = params->op; |
99 | | for (int i = 0; i < 4; i++) { |
100 | | const AVRational64 value = op->clear.value[i]; |
101 | | if (!value.den) |
102 | | continue; |
103 | | switch (op->type) { |
104 | | case SWS_PIXEL_U8: out->priv.u8[i] = q2pixel(uint8_t, value); break; |
105 | | case SWS_PIXEL_U16: out->priv.u16[i] = q2pixel(uint16_t, value); break; |
106 | | case SWS_PIXEL_U32: out->priv.u32[i] = q2pixel(uint32_t, value); break; |
107 | | case SWS_PIXEL_F32: out->priv.f32[i] = q2pixel(float, value); break; |
108 | | default: return AVERROR(EINVAL); |
109 | | } |
110 | | } |
111 | | |
112 | | return 0; |
113 | | } |
114 | | #endif |
115 | | |
116 | | int ff_sws_uop_lookup(SwsContext *ctx, const SwsUOpTable *const tables[], |
117 | | int num_tables, const SwsUOp *uop, const int block_size, |
118 | | SwsOpChain *chain) |
119 | 0 | { |
120 | 0 | const unsigned cpu_flags = av_get_cpu_flags(); |
121 | 0 | const SwsUOpEntry *match = NULL; |
122 | 0 | int ret; |
123 | |
|
124 | 0 | SwsImplParams params = { |
125 | 0 | .ctx = ctx, |
126 | 0 | .uop = uop |
127 | 0 | }; |
128 | |
|
129 | 0 | for (int n = 0; !match && n < num_tables; n++) { |
130 | 0 | const SwsUOpTable *table = params.table = tables[n]; |
131 | 0 | if (table->block_size && table->block_size != block_size || |
132 | 0 | table->cpu_flags & ~cpu_flags) |
133 | 0 | continue; |
134 | | |
135 | 0 | for (int i = 0; table->entries[i]; i++) { |
136 | 0 | const SwsUOpEntry *entry = table->entries[i]; |
137 | 0 | const SwsUOp entry_uop = { |
138 | 0 | .uop = entry->uop, |
139 | 0 | .type = entry->type, |
140 | 0 | .mask = entry->mask, |
141 | 0 | .par = entry->par, |
142 | 0 | }; |
143 | |
|
144 | 0 | if (ff_sws_uop_cmp(uop, &entry_uop) != 0) |
145 | 0 | continue; |
146 | 0 | if (entry->check && !entry->check(¶ms)) |
147 | 0 | continue; |
148 | | |
149 | 0 | match = entry; |
150 | 0 | break; |
151 | 0 | } |
152 | 0 | } |
153 | |
|
154 | 0 | if (!match) { |
155 | 0 | char name[64]; |
156 | 0 | ff_sws_uop_name(uop, name); |
157 | 0 | av_log(ctx, AV_LOG_DEBUG, "No implementation found for: %s\n", name); |
158 | 0 | return AVERROR(ENOTSUP); |
159 | 0 | } |
160 | | |
161 | 0 | SwsImplResult res = {0}; |
162 | 0 | if (match->setup) { |
163 | 0 | ret = match->setup(¶ms, &res); |
164 | 0 | if (ret < 0) |
165 | 0 | return ret; |
166 | 0 | } |
167 | | |
168 | 0 | ret = ff_sws_op_chain_append(chain, res.func ? res.func : match->func, |
169 | 0 | res.free, &res.priv); |
170 | 0 | if (ret < 0) { |
171 | 0 | if (res.free) |
172 | 0 | res.free(&res.priv); |
173 | 0 | return ret; |
174 | 0 | } |
175 | | |
176 | 0 | for (int i = 0; i < 4; i++) { |
177 | 0 | chain->over_read[i] = FFMAX(chain->over_read[i], res.over_read[i]); |
178 | 0 | chain->over_write[i] = FFMAX(chain->over_write[i], res.over_write[i]); |
179 | 0 | } |
180 | |
|
181 | 0 | chain->cpu_flags |= params.table->cpu_flags; |
182 | 0 | return 0; |
183 | 0 | } |
184 | | |
185 | | int ff_sws_setup_scalar(const SwsImplParams *params, SwsImplResult *out) |
186 | 0 | { |
187 | 0 | const SwsUOp *uop = params->uop; |
188 | 0 | const SwsPixel scalar = uop->data.scalar; |
189 | 0 | switch (uop->type) { |
190 | 0 | case SWS_PIXEL_U8: out->priv.u8[0] = scalar.u8; break; |
191 | 0 | case SWS_PIXEL_U16: out->priv.u16[0] = scalar.u16; break; |
192 | 0 | case SWS_PIXEL_U32: out->priv.u32[0] = scalar.u32; break; |
193 | 0 | case SWS_PIXEL_F32: out->priv.f32[0] = scalar.f32; break; |
194 | 0 | default: return AVERROR(EINVAL); |
195 | 0 | } |
196 | | |
197 | 0 | return 0; |
198 | 0 | } |
199 | | |
200 | | int ff_sws_setup_vec4(const SwsImplParams *params, SwsImplResult *out) |
201 | 0 | { |
202 | 0 | const SwsUOp *uop = params->uop; |
203 | 0 | for (int i = 0; i < 4; i++) { |
204 | 0 | const SwsPixel vi = uop->data.vec4[i]; |
205 | 0 | switch (uop->type) { |
206 | 0 | case SWS_PIXEL_U8: out->priv.u8[i] = vi.u8; break; |
207 | 0 | case SWS_PIXEL_U16: out->priv.u16[i] = vi.u16; break; |
208 | 0 | case SWS_PIXEL_U32: out->priv.u32[i] = vi.u32; break; |
209 | 0 | case SWS_PIXEL_F32: out->priv.f32[i] = vi.f32; break; |
210 | 0 | default: return AVERROR(EINVAL); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | 0 | return 0; |
215 | 0 | } |