/src/mpv/video/mp_image.c
Line | Count | Source |
1 | | /* |
2 | | * This file is part of mpv. |
3 | | * |
4 | | * mpv is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * mpv is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | * GNU Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include <limits.h> |
19 | | #include <assert.h> |
20 | | |
21 | | #include <libavutil/mem.h> |
22 | | #include <libavutil/common.h> |
23 | | #include <libavutil/display.h> |
24 | | #include <libavutil/dovi_meta.h> |
25 | | #include <libavutil/bswap.h> |
26 | | #include <libavutil/hwcontext.h> |
27 | | #include <libavutil/intreadwrite.h> |
28 | | #include <libavutil/rational.h> |
29 | | #include <libavcodec/avcodec.h> |
30 | | #include <libavutil/mastering_display_metadata.h> |
31 | | #include <libplacebo/utils/libav.h> |
32 | | |
33 | | #include "mpv_talloc.h" |
34 | | |
35 | | #include "common/av_common.h" |
36 | | #include "common/common.h" |
37 | | #include "fmt-conversion.h" |
38 | | #include "hwdec.h" |
39 | | #include "mp_image.h" |
40 | | #include "osdep/threads.h" |
41 | | #include "sws_utils.h" |
42 | | #include "out/placebo/utils.h" |
43 | | |
44 | | // Determine strides, plane sizes, and total required size for an image |
45 | | // allocation. Returns total size on success, <0 on error. Unused planes |
46 | | // have out_stride/out_plane_size to 0, and out_plane_offset set to -1 up |
47 | | // until MP_MAX_PLANES-1. |
48 | | static int mp_image_layout(int imgfmt, int w, int h, int stride_align, |
49 | | int out_stride[MP_MAX_PLANES], |
50 | | int out_plane_offset[MP_MAX_PLANES], |
51 | | int out_plane_size[MP_MAX_PLANES]) |
52 | 41.4k | { |
53 | 41.4k | struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(imgfmt); |
54 | | |
55 | 41.4k | w = MP_ALIGN_UP(w, desc.align_x); |
56 | 41.4k | h = MP_ALIGN_UP(h, desc.align_y); |
57 | | |
58 | 41.4k | struct mp_image_params params = {.imgfmt = imgfmt, .w = w, .h = h}; |
59 | | |
60 | 41.4k | if (!mp_image_params_valid(¶ms) || desc.flags & MP_IMGFLAG_HWACCEL) |
61 | 26 | return -1; |
62 | | |
63 | | // Note: for non-mod-2 4:2:0 YUV frames, we have to allocate an additional |
64 | | // top/right border. This is needed for correct handling of such |
65 | | // images in filter and VO code (e.g. vo_vdpau or vo_gpu). |
66 | | |
67 | 207k | for (int n = 0; n < MP_MAX_PLANES; n++) { |
68 | 165k | int alloc_w = mp_chroma_div_up(w, desc.xs[n]); |
69 | 165k | int alloc_h = MP_ALIGN_UP(h, 32) >> desc.ys[n]; |
70 | 165k | int line_bytes = (alloc_w * desc.bpp[n] + 7) / 8; |
71 | 165k | out_stride[n] = MP_ALIGN_NPOT(line_bytes, stride_align); |
72 | 165k | out_plane_size[n] = out_stride[n] * alloc_h; |
73 | 165k | } |
74 | 41.4k | if (desc.flags & MP_IMGFLAG_PAL) |
75 | 0 | out_plane_size[1] = AVPALETTE_SIZE; |
76 | | |
77 | 41.4k | int sum = 0; |
78 | 207k | for (int n = 0; n < MP_MAX_PLANES; n++) { |
79 | 165k | out_plane_offset[n] = out_plane_size[n] ? sum : -1; |
80 | 165k | sum += out_plane_size[n]; |
81 | 165k | } |
82 | | |
83 | 41.4k | return sum; |
84 | 41.4k | } |
85 | | |
86 | | // Return the total size needed for an image allocation of the given |
87 | | // configuration (imgfmt, w, h must be set). Returns -1 on error. |
88 | | // Assumes the allocation is already aligned on stride_align (otherwise you |
89 | | // need to add padding yourself). |
90 | | int mp_image_get_alloc_size(int imgfmt, int w, int h, int stride_align) |
91 | 20.7k | { |
92 | 20.7k | int stride[MP_MAX_PLANES]; |
93 | 20.7k | int plane_offset[MP_MAX_PLANES]; |
94 | 20.7k | int plane_size[MP_MAX_PLANES]; |
95 | 20.7k | return mp_image_layout(imgfmt, w, h, stride_align, stride, plane_offset, |
96 | 20.7k | plane_size); |
97 | 20.7k | } |
98 | | |
99 | | // Fill the mpi->planes and mpi->stride fields of the given mpi with data |
100 | | // from buffer according to the mpi's w/h/imgfmt fields. See mp_image_from_buffer |
101 | | // aboud remarks how to allocate/use buffer/buffer_size. |
102 | | // This does not free the data. You are expected to setup refcounting by |
103 | | // setting mp_image.bufs before or after this function is called. |
104 | | // Returns true on success, false on failure. |
105 | | static bool mp_image_fill_alloc(struct mp_image *mpi, int stride_align, |
106 | | void *buffer, int buffer_size) |
107 | 20.7k | { |
108 | 20.7k | int stride[MP_MAX_PLANES]; |
109 | 20.7k | int plane_offset[MP_MAX_PLANES]; |
110 | 20.7k | int plane_size[MP_MAX_PLANES]; |
111 | 20.7k | int size = mp_image_layout(mpi->imgfmt, mpi->w, mpi->h, stride_align, |
112 | 20.7k | stride, plane_offset, plane_size); |
113 | 20.7k | if (size < 0 || size > buffer_size) |
114 | 0 | return false; |
115 | | |
116 | 20.7k | int align = MP_ALIGN_UP((uintptr_t)buffer, stride_align) - (uintptr_t)buffer; |
117 | 20.7k | if (buffer_size - size < align) |
118 | 0 | return false; |
119 | 20.7k | uint8_t *s = buffer; |
120 | 20.7k | s += align; |
121 | | |
122 | 103k | for (int n = 0; n < MP_MAX_PLANES; n++) { |
123 | 82.8k | mpi->planes[n] = plane_offset[n] >= 0 ? s + plane_offset[n] : NULL; |
124 | 82.8k | mpi->stride[n] = stride[n]; |
125 | 82.8k | } |
126 | | |
127 | 20.7k | return true; |
128 | 20.7k | } |
129 | | |
130 | | // Create a mp_image from the provided buffer. The mp_image is filled according |
131 | | // to the imgfmt/w/h parameters, and respecting the stride_align parameter to |
132 | | // align the plane start pointers and strides. Once the last reference to the |
133 | | // returned image is destroyed, free(free_opaque, buffer) is called. (Be aware |
134 | | // that this can happen from any thread.) |
135 | | // The allocated size of buffer must be given by buffer_size. buffer_size should |
136 | | // be at least the value returned by mp_image_get_alloc_size(). If buffer is not |
137 | | // already aligned to stride_align, the function will attempt to align the |
138 | | // pointer itself by incrementing the buffer pointer until their alignment is |
139 | | // achieved (if buffer_size is not large enough to allow aligning the buffer |
140 | | // safely, the function fails). To be safe, you may want to overallocate the |
141 | | // buffer by stride_align bytes, and include the overallocation in buffer_size. |
142 | | // Returns NULL on failure. On failure, the free() callback is not called. |
143 | | struct mp_image *mp_image_from_buffer(int imgfmt, int w, int h, int stride_align, |
144 | | uint8_t *buffer, int buffer_size, |
145 | | void *free_opaque, |
146 | | void (*free)(void *opaque, uint8_t *data)) |
147 | 0 | { |
148 | 0 | struct mp_image *mpi = mp_image_new_dummy_ref(NULL); |
149 | 0 | mp_image_setfmt(mpi, imgfmt); |
150 | 0 | mp_image_set_size(mpi, w, h); |
151 | |
|
152 | 0 | if (!mp_image_fill_alloc(mpi, stride_align, buffer, buffer_size)) |
153 | 0 | goto fail; |
154 | | |
155 | 0 | mpi->bufs[0] = av_buffer_create(buffer, buffer_size, free, free_opaque, 0); |
156 | 0 | if (!mpi->bufs[0]) |
157 | 0 | goto fail; |
158 | | |
159 | 0 | return mpi; |
160 | | |
161 | 0 | fail: |
162 | 0 | talloc_free(mpi); |
163 | 0 | return NULL; |
164 | 0 | } |
165 | | |
166 | | static bool mp_image_alloc_planes(struct mp_image *mpi) |
167 | 20.7k | { |
168 | 20.7k | mp_assert(!mpi->planes[0]); |
169 | 20.7k | mp_assert(!mpi->bufs[0]); |
170 | | |
171 | 20.7k | int align = MP_IMAGE_BYTE_ALIGN; |
172 | | |
173 | 20.7k | int size = mp_image_get_alloc_size(mpi->imgfmt, mpi->w, mpi->h, align); |
174 | 20.7k | if (size < 0) |
175 | 26 | return false; |
176 | | |
177 | | // Note: mp_image_pool assumes this creates only 1 AVBufferRef. |
178 | 20.7k | mpi->bufs[0] = av_buffer_alloc(size + align); |
179 | 20.7k | if (!mpi->bufs[0]) |
180 | 0 | return false; |
181 | | |
182 | 20.7k | if (!mp_image_fill_alloc(mpi, align, mpi->bufs[0]->data, mpi->bufs[0]->size)) { |
183 | 0 | av_buffer_unref(&mpi->bufs[0]); |
184 | 0 | return false; |
185 | 0 | } |
186 | | |
187 | 20.7k | return true; |
188 | 20.7k | } |
189 | | |
190 | | void mp_image_sethwfmt(struct mp_image *mpi, enum mp_imgfmt hw_fmt, enum mp_imgfmt sw_fmt) |
191 | 413k | { |
192 | 413k | struct mp_imgfmt_desc fmt = mp_imgfmt_get_desc(sw_fmt ? sw_fmt : hw_fmt); |
193 | 413k | mpi->params.imgfmt = hw_fmt; |
194 | 413k | mpi->params.hw_subfmt = sw_fmt; |
195 | 413k | mpi->fmt = fmt; |
196 | 413k | mpi->imgfmt = hw_fmt; |
197 | 413k | mpi->num_planes = fmt.num_planes; |
198 | 413k | mpi->params.repr.alpha = (fmt.flags & MP_IMGFLAG_ALPHA) ? PL_ALPHA_INDEPENDENT |
199 | 413k | #if PL_API_VER >= 344 |
200 | 413k | : PL_ALPHA_NONE; |
201 | | #else |
202 | | : PL_ALPHA_UNKNOWN; |
203 | | #endif |
204 | | // Calculate bit encoding from all components (excluding alpha) |
205 | 413k | struct pl_bit_encoding bits = {0}; |
206 | 413k | const int num_comps = mp_imgfmt_desc_get_num_comps(&fmt); |
207 | 1.60M | for (int c = 0; c < MPMIN(num_comps, 3); c++) { |
208 | 1.19M | struct pl_bit_encoding cbits = { |
209 | 1.19M | .sample_depth = fmt.comps[c].size, |
210 | 1.19M | .color_depth = fmt.comps[c].size - abs(fmt.comps[c].pad), |
211 | 1.19M | .bit_shift = MPMAX(fmt.comps[c].pad, 0), |
212 | 1.19M | }; |
213 | | |
214 | 1.19M | if (bits.sample_depth && !pl_bit_encoding_equal(&bits, &cbits)) { |
215 | | // Bit encoding differs between components, cannot handle this |
216 | 1.35k | bits = (struct pl_bit_encoding) {0}; |
217 | 1.35k | break; |
218 | 1.35k | } |
219 | | |
220 | 1.18M | bits = cbits; |
221 | 1.18M | } |
222 | 413k | mpi->params.repr.bits = bits; |
223 | 413k | } |
224 | | |
225 | | void mp_image_setfmt(struct mp_image *mpi, enum mp_imgfmt fmt) |
226 | 44.5k | { |
227 | 44.5k | mp_image_sethwfmt(mpi, fmt, IMGFMT_NONE); |
228 | 44.5k | } |
229 | | |
230 | | static void mp_image_destructor(void *ptr) |
231 | 1.14M | { |
232 | 1.14M | mp_image_t *mpi = ptr; |
233 | 5.73M | for (int p = 0; p < MP_MAX_PLANES; p++) |
234 | 4.58M | av_buffer_unref(&mpi->bufs[p]); |
235 | 1.14M | av_buffer_unref(&mpi->hwctx); |
236 | 1.14M | av_buffer_unref(&mpi->icc_profile); |
237 | 1.14M | av_buffer_unref(&mpi->a53_cc); |
238 | 1.14M | av_buffer_unref(&mpi->dovi); |
239 | 1.14M | av_buffer_unref(&mpi->film_grain); |
240 | 1.23M | for (int n = 0; n < mpi->num_ff_side_data; n++) |
241 | 92.0k | av_buffer_unref(&mpi->ff_side_data[n].buf); |
242 | 1.14M | talloc_free(mpi->ff_side_data); |
243 | 1.14M | } |
244 | | |
245 | | int mp_chroma_div_up(int size, int shift) |
246 | 628k | { |
247 | 628k | return (size + (1 << shift) - 1) >> shift; |
248 | 628k | } |
249 | | |
250 | | // Return the storage width in pixels of the given plane. |
251 | | int mp_image_plane_w(struct mp_image *mpi, int plane) |
252 | 203k | { |
253 | 203k | return mp_chroma_div_up(mpi->w, mpi->fmt.xs[plane]); |
254 | 203k | } |
255 | | |
256 | | // Return the storage height in pixels of the given plane. |
257 | | int mp_image_plane_h(struct mp_image *mpi, int plane) |
258 | 203k | { |
259 | 203k | return mp_chroma_div_up(mpi->h, mpi->fmt.ys[plane]); |
260 | 203k | } |
261 | | |
262 | | // Caller has to make sure this doesn't exceed the allocated plane data/strides. |
263 | | void mp_image_set_size(struct mp_image *mpi, int w, int h) |
264 | 462k | { |
265 | 462k | mp_assert(w >= 0 && h >= 0); |
266 | 462k | mpi->w = mpi->params.w = w; |
267 | 462k | mpi->h = mpi->params.h = h; |
268 | 462k | } |
269 | | |
270 | | void mp_image_set_params(struct mp_image *image, |
271 | | const struct mp_image_params *params) |
272 | 1.31k | { |
273 | | // possibly initialize other stuff |
274 | 1.31k | mp_image_setfmt(image, params->imgfmt); |
275 | 1.31k | mp_image_set_size(image, params->w, params->h); |
276 | 1.31k | image->params = *params; |
277 | 1.31k | } |
278 | | |
279 | | struct mp_image *mp_image_alloc(int imgfmt, int w, int h) |
280 | 20.7k | { |
281 | 20.7k | struct mp_image *mpi = talloc_zero(NULL, struct mp_image); |
282 | 20.7k | talloc_set_destructor(mpi, mp_image_destructor); |
283 | | |
284 | 20.7k | mp_image_set_size(mpi, w, h); |
285 | 20.7k | mp_image_setfmt(mpi, imgfmt); |
286 | 20.7k | if (!mp_image_alloc_planes(mpi)) { |
287 | 26 | talloc_free(mpi); |
288 | 26 | return NULL; |
289 | 26 | } |
290 | 20.7k | return mpi; |
291 | 20.7k | } |
292 | | |
293 | | int mp_image_approx_byte_size(struct mp_image *img) |
294 | 0 | { |
295 | 0 | int total = sizeof(*img); |
296 | |
|
297 | 0 | for (int n = 0; n < MP_MAX_PLANES; n++) { |
298 | 0 | struct AVBufferRef *buf = img->bufs[n]; |
299 | 0 | if (buf) |
300 | 0 | total += buf->size; |
301 | 0 | } |
302 | |
|
303 | 0 | return total; |
304 | 0 | } |
305 | | |
306 | | struct mp_image *mp_image_new_copy(struct mp_image *img) |
307 | 0 | { |
308 | 0 | struct mp_image *new = mp_image_alloc(img->imgfmt, img->w, img->h); |
309 | 0 | if (!new) |
310 | 0 | return NULL; |
311 | 0 | mp_image_copy(new, img); |
312 | 0 | mp_image_copy_attributes(new, img); |
313 | 0 | return new; |
314 | 0 | } |
315 | | |
316 | | // Make dst take over the image data of src, and free src. |
317 | | // This is basically a safe version of *dst = *src; free(src); |
318 | | // Only works with ref-counted images, and can't change image size/format. |
319 | | void mp_image_steal_data(struct mp_image *dst, struct mp_image *src) |
320 | 0 | { |
321 | 0 | mp_assert(dst->imgfmt == src->imgfmt && dst->w == src->w && dst->h == src->h); |
322 | 0 | mp_assert(dst->bufs[0] && src->bufs[0]); |
323 | | |
324 | 0 | mp_image_destructor(dst); // unref old |
325 | 0 | talloc_free_children(dst); |
326 | |
|
327 | 0 | *dst = *src; |
328 | |
|
329 | 0 | *src = (struct mp_image){0}; |
330 | 0 | talloc_free(src); |
331 | 0 | } |
332 | | |
333 | | // Unref most data buffer (and clear the data array), but leave other fields |
334 | | // allocated. In particular, mp_image.hwctx is preserved. |
335 | | void mp_image_unref_data(struct mp_image *img) |
336 | 0 | { |
337 | 0 | for (int n = 0; n < MP_MAX_PLANES; n++) { |
338 | 0 | img->planes[n] = NULL; |
339 | 0 | img->stride[n] = 0; |
340 | 0 | av_buffer_unref(&img->bufs[n]); |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | | static void ref_buffer(AVBufferRef **dst) |
345 | 9.80M | { |
346 | 9.80M | if (*dst) { |
347 | 2.58M | *dst = av_buffer_ref(*dst); |
348 | 2.58M | MP_HANDLE_OOM(*dst); |
349 | 2.58M | } |
350 | 9.80M | } |
351 | | |
352 | | // Return a new reference to img. The returned reference is owned by the caller, |
353 | | // while img is left untouched. |
354 | | struct mp_image *mp_image_new_ref(struct mp_image *img) |
355 | 1.07M | { |
356 | 1.07M | if (!img) |
357 | 0 | return NULL; |
358 | | |
359 | 1.07M | if (!img->bufs[0]) |
360 | 0 | return mp_image_new_copy(img); |
361 | | |
362 | 1.07M | struct mp_image *new = talloc_ptrtype(NULL, new); |
363 | 1.07M | talloc_set_destructor(new, mp_image_destructor); |
364 | 1.07M | *new = *img; |
365 | | |
366 | 5.39M | for (int p = 0; p < MP_MAX_PLANES; p++) |
367 | 4.31M | ref_buffer(&new->bufs[p]); |
368 | | |
369 | 1.07M | ref_buffer(&new->hwctx); |
370 | 1.07M | ref_buffer(&new->icc_profile); |
371 | 1.07M | ref_buffer(&new->a53_cc); |
372 | 1.07M | ref_buffer(&new->dovi); |
373 | 1.07M | ref_buffer(&new->film_grain); |
374 | | |
375 | 1.07M | new->ff_side_data = talloc_memdup(NULL, new->ff_side_data, |
376 | 1.07M | new->num_ff_side_data * sizeof(new->ff_side_data[0])); |
377 | 1.17M | for (int n = 0; n < new->num_ff_side_data; n++) |
378 | 92.0k | ref_buffer(&new->ff_side_data[n].buf); |
379 | | |
380 | 1.07M | return new; |
381 | 1.07M | } |
382 | | |
383 | | struct free_args { |
384 | | void *arg; |
385 | | void (*free)(void *arg); |
386 | | }; |
387 | | |
388 | | static void call_free(void *opaque, uint8_t *data) |
389 | 0 | { |
390 | 0 | struct free_args *args = opaque; |
391 | 0 | args->free(args->arg); |
392 | 0 | talloc_free(args); |
393 | 0 | } |
394 | | |
395 | | // Create a new mp_image based on img, but don't set any buffers. |
396 | | // Using this is only valid until the original img is unreferenced (including |
397 | | // implicit unreferencing of the data by mp_image_make_writeable()), unless |
398 | | // a new reference is set. |
399 | | struct mp_image *mp_image_new_dummy_ref(struct mp_image *img) |
400 | 46.0k | { |
401 | 46.0k | struct mp_image *new = talloc_ptrtype(NULL, new); |
402 | 46.0k | talloc_set_destructor(new, mp_image_destructor); |
403 | 46.0k | *new = img ? *img : (struct mp_image){0}; |
404 | 230k | for (int p = 0; p < MP_MAX_PLANES; p++) |
405 | 184k | new->bufs[p] = NULL; |
406 | 46.0k | new->hwctx = NULL; |
407 | 46.0k | new->icc_profile = NULL; |
408 | 46.0k | new->a53_cc = NULL; |
409 | 46.0k | new->dovi = NULL; |
410 | 46.0k | new->film_grain = NULL; |
411 | 46.0k | new->num_ff_side_data = 0; |
412 | 46.0k | new->ff_side_data = NULL; |
413 | 46.0k | return new; |
414 | 46.0k | } |
415 | | |
416 | | // Return a reference counted reference to img. If the reference count reaches |
417 | | // 0, call free(free_arg). The data passed by img must not be free'd before |
418 | | // that. The new reference will be writeable. |
419 | | // On allocation failure, unref the frame and return NULL. |
420 | | // This is only used for hw decoding; this is important, because libav* expects |
421 | | // all plane data to be accounted for by AVBufferRefs. |
422 | | struct mp_image *mp_image_new_custom_ref(struct mp_image *img, void *free_arg, |
423 | | void (*free)(void *arg)) |
424 | 0 | { |
425 | 0 | struct mp_image *new = mp_image_new_dummy_ref(img); |
426 | |
|
427 | 0 | struct free_args *args = talloc_ptrtype(NULL, args); |
428 | 0 | *args = (struct free_args){free_arg, free}; |
429 | 0 | new->bufs[0] = av_buffer_create(NULL, 0, call_free, args, |
430 | 0 | AV_BUFFER_FLAG_READONLY); |
431 | 0 | if (new->bufs[0]) |
432 | 0 | return new; |
433 | 0 | talloc_free(new); |
434 | 0 | return NULL; |
435 | 0 | } |
436 | | |
437 | | bool mp_image_is_writeable(struct mp_image *img) |
438 | 28.6k | { |
439 | 28.6k | if (!img->bufs[0]) |
440 | 0 | return true; // not ref-counted => always considered writeable |
441 | 57.2k | for (int p = 0; p < MP_MAX_PLANES; p++) { |
442 | 57.2k | if (!img->bufs[p]) |
443 | 28.6k | break; |
444 | 28.6k | if (!av_buffer_is_writable(img->bufs[p])) |
445 | 0 | return false; |
446 | 28.6k | } |
447 | 28.6k | return true; |
448 | 28.6k | } |
449 | | |
450 | | // Make the image data referenced by img writeable. This allocates new data |
451 | | // if the data wasn't already writeable, and img->planes[] and img->stride[] |
452 | | // will be set to the copy. |
453 | | // Returns success; if false is returned, the image could not be made writeable. |
454 | | bool mp_image_make_writeable(struct mp_image *img) |
455 | 72 | { |
456 | 72 | if (mp_image_is_writeable(img)) |
457 | 72 | return true; |
458 | | |
459 | 0 | struct mp_image *new = mp_image_new_copy(img); |
460 | 0 | if (!new) |
461 | 0 | return false; |
462 | 0 | mp_image_steal_data(img, new); |
463 | 0 | mp_assert(mp_image_is_writeable(img)); |
464 | 0 | return true; |
465 | 0 | } |
466 | | |
467 | | // Helper function: unrefs *p_img, and sets *p_img to a new ref of new_value. |
468 | | // Only unrefs *p_img and sets it to NULL if out of memory. |
469 | | void mp_image_setrefp(struct mp_image **p_img, struct mp_image *new_value) |
470 | 53 | { |
471 | 53 | if (*p_img != new_value) { |
472 | 53 | talloc_free(*p_img); |
473 | 53 | *p_img = new_value ? mp_image_new_ref(new_value) : NULL; |
474 | 53 | } |
475 | 53 | } |
476 | | |
477 | | // Mere helper function (mp_image can be directly free'd with talloc_free) |
478 | | void mp_image_unrefp(struct mp_image **p_img) |
479 | 1.91M | { |
480 | 1.91M | talloc_free(*p_img); |
481 | 1.91M | *p_img = NULL; |
482 | 1.91M | } |
483 | | |
484 | | void memcpy_pic(void *dst, const void *src, int bytesPerLine, int height, |
485 | | int dstStride, int srcStride) |
486 | 77.9k | { |
487 | 77.9k | if (bytesPerLine == dstStride && dstStride == srcStride && height) { |
488 | 65.3k | if (srcStride < 0) { |
489 | 0 | src = (uint8_t*)src + (height - 1) * srcStride; |
490 | 0 | dst = (uint8_t*)dst + (height - 1) * dstStride; |
491 | 0 | srcStride = -srcStride; |
492 | 0 | } |
493 | | |
494 | 65.3k | memcpy(dst, src, srcStride * (height - 1) + bytesPerLine); |
495 | 65.3k | } else { |
496 | 9.75M | for (int i = 0; i < height; i++) { |
497 | 9.74M | memcpy(dst, src, bytesPerLine); |
498 | 9.74M | src = (uint8_t*)src + srcStride; |
499 | 9.74M | dst = (uint8_t*)dst + dstStride; |
500 | 9.74M | } |
501 | 12.6k | } |
502 | 77.9k | } |
503 | | |
504 | | void mp_image_copy(struct mp_image *dst, struct mp_image *src) |
505 | 28.4k | { |
506 | 28.4k | mp_assert(dst->imgfmt == src->imgfmt); |
507 | 28.4k | mp_assert(dst->w == src->w && dst->h == src->h); |
508 | 28.4k | mp_assert(mp_image_is_writeable(dst)); |
509 | 105k | for (int n = 0; n < dst->num_planes; n++) { |
510 | 77.1k | int line_bytes = (mp_image_plane_w(dst, n) * dst->fmt.bpp[n] + 7) / 8; |
511 | 77.1k | int plane_h = mp_image_plane_h(dst, n); |
512 | 77.1k | memcpy_pic(dst->planes[n], src->planes[n], line_bytes, plane_h, |
513 | 77.1k | dst->stride[n], src->stride[n]); |
514 | 77.1k | } |
515 | 28.4k | if (dst->fmt.flags & MP_IMGFLAG_PAL) |
516 | 0 | memcpy(dst->planes[1], src->planes[1], AVPALETTE_SIZE); |
517 | 28.4k | } |
518 | | |
519 | | static enum pl_color_system mp_image_params_get_forced_csp(struct mp_image_params *params) |
520 | 196k | { |
521 | 196k | int imgfmt = params->hw_subfmt ? params->hw_subfmt : params->imgfmt; |
522 | 196k | enum pl_color_system csp = mp_imgfmt_get_forced_csp(imgfmt); |
523 | | |
524 | 196k | if (csp == PL_COLOR_SYSTEM_RGB && params->repr.sys == PL_COLOR_SYSTEM_XYZ) |
525 | 1.09k | csp = PL_COLOR_SYSTEM_XYZ; |
526 | | |
527 | 196k | return csp; |
528 | 196k | } |
529 | | |
530 | | static void assign_bufref(AVBufferRef **dst, AVBufferRef *new) |
531 | 203k | { |
532 | 203k | av_buffer_unref(dst); |
533 | 203k | if (new) { |
534 | 0 | *dst = av_buffer_ref(new); |
535 | 0 | MP_HANDLE_OOM(*dst); |
536 | 0 | } |
537 | 203k | } |
538 | | |
539 | | void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src) |
540 | 50.9k | { |
541 | 50.9k | mp_assert(dst != src); |
542 | | |
543 | 50.9k | dst->pict_type = src->pict_type; |
544 | 50.9k | dst->fields = src->fields; |
545 | 50.9k | dst->pts = src->pts; |
546 | 50.9k | dst->dts = src->dts; |
547 | 50.9k | dst->pkt_duration = src->pkt_duration; |
548 | 50.9k | dst->params.vflip = src->params.vflip; |
549 | 50.9k | dst->params.rotate = src->params.rotate; |
550 | 50.9k | dst->params.stereo3d = src->params.stereo3d; |
551 | 50.9k | dst->params.p_w = src->params.p_w; |
552 | 50.9k | dst->params.p_h = src->params.p_h; |
553 | 50.9k | dst->params.color = src->params.color; |
554 | 50.9k | dst->params.repr = src->params.repr; |
555 | 50.9k | dst->params.light = src->params.light; |
556 | 50.9k | dst->params.chroma_location = src->params.chroma_location; |
557 | 50.9k | dst->params.crop = src->params.crop; |
558 | 50.9k | dst->nominal_fps = src->nominal_fps; |
559 | 50.9k | dst->params.primaries_orig = src->params.primaries_orig; |
560 | 50.9k | dst->params.transfer_orig = src->params.transfer_orig; |
561 | 50.9k | dst->params.sys_orig = src->params.sys_orig; |
562 | | |
563 | | // ensure colorspace consistency |
564 | 50.9k | enum pl_color_system dst_forced_csp = mp_image_params_get_forced_csp(&dst->params); |
565 | 50.9k | if (mp_image_params_get_forced_csp(&src->params) != dst_forced_csp) { |
566 | 7.03k | dst->params.repr.sys = dst_forced_csp != PL_COLOR_SYSTEM_UNKNOWN ? |
567 | 4.60k | dst_forced_csp : |
568 | 7.03k | mp_csp_guess_colorspace(src->w, src->h); |
569 | 7.03k | } |
570 | | |
571 | 50.9k | if ((dst->fmt.flags & MP_IMGFLAG_PAL) && (src->fmt.flags & MP_IMGFLAG_PAL)) { |
572 | 0 | if (dst->planes[1] && src->planes[1]) { |
573 | 0 | if (mp_image_make_writeable(dst)) |
574 | 0 | memcpy(dst->planes[1], src->planes[1], AVPALETTE_SIZE); |
575 | 0 | } |
576 | 0 | } |
577 | 50.9k | assign_bufref(&dst->icc_profile, src->icc_profile); |
578 | 50.9k | assign_bufref(&dst->dovi, src->dovi); |
579 | 50.9k | assign_bufref(&dst->film_grain, src->film_grain); |
580 | 50.9k | assign_bufref(&dst->a53_cc, src->a53_cc); |
581 | | |
582 | 50.9k | for (int n = 0; n < dst->num_ff_side_data; n++) |
583 | 0 | av_buffer_unref(&dst->ff_side_data[n].buf); |
584 | | |
585 | 50.9k | MP_RESIZE_ARRAY(NULL, dst->ff_side_data, src->num_ff_side_data); |
586 | 50.9k | dst->num_ff_side_data = src->num_ff_side_data; |
587 | | |
588 | 50.9k | for (int n = 0; n < dst->num_ff_side_data; n++) { |
589 | 0 | dst->ff_side_data[n].type = src->ff_side_data[n].type; |
590 | 0 | dst->ff_side_data[n].buf = av_buffer_ref(src->ff_side_data[n].buf); |
591 | 0 | MP_HANDLE_OOM(dst->ff_side_data[n].buf); |
592 | 0 | } |
593 | 50.9k | } |
594 | | |
595 | | // Crop the given image to (x0, y0)-(x1, y1) (bottom/right border exclusive) |
596 | | // x0/y0 must be naturally aligned. |
597 | | void mp_image_crop(struct mp_image *img, int x0, int y0, int x1, int y1) |
598 | 71.7k | { |
599 | 71.7k | mp_assert(x0 >= 0 && y0 >= 0); |
600 | 71.7k | mp_assert(x0 <= x1 && y0 <= y1); |
601 | 71.7k | mp_assert(x1 <= img->w && y1 <= img->h); |
602 | 71.7k | mp_assert(!(x0 & (img->fmt.align_x - 1))); |
603 | 71.7k | mp_assert(!(y0 & (img->fmt.align_y - 1))); |
604 | | |
605 | 260k | for (int p = 0; p < img->num_planes; ++p) { |
606 | 189k | img->planes[p] += (y0 >> img->fmt.ys[p]) * img->stride[p] + |
607 | 189k | (x0 >> img->fmt.xs[p]) * img->fmt.bpp[p] / 8; |
608 | 189k | } |
609 | 71.7k | mp_image_set_size(img, x1 - x0, y1 - y0); |
610 | 71.7k | } |
611 | | |
612 | | void mp_image_crop_rc(struct mp_image *img, struct mp_rect rc) |
613 | 8 | { |
614 | 8 | mp_image_crop(img, rc.x0, rc.y0, rc.x1, rc.y1); |
615 | 8 | } |
616 | | |
617 | | // Repeatedly write count patterns of src[0..src_size] to p. |
618 | | static void memset_pattern(void *p, size_t count, uint8_t *src, size_t src_size) |
619 | 5.96M | { |
620 | 5.96M | mp_assert(src_size >= 1); |
621 | | |
622 | 5.96M | if (src_size == 1) { |
623 | 4.30M | memset(p, src[0], count); |
624 | 4.30M | } else if (src_size == 2) { // >8 bit YUV => common, be slightly less naive |
625 | 1.21M | uint16_t val; |
626 | 1.21M | memcpy(&val, src, 2); |
627 | 1.21M | uint16_t *p16 = p; |
628 | 362M | while (count--) |
629 | 361M | *p16++ = val; |
630 | 1.21M | } else { |
631 | 137M | while (count--) { |
632 | 137M | memcpy(p, src, src_size); |
633 | 137M | p = (char *)p + src_size; |
634 | 137M | } |
635 | 440k | } |
636 | 5.96M | } |
637 | | |
638 | | static bool endian_swap_bytes(void *d, size_t bytes, size_t word_size) |
639 | 3.76k | { |
640 | 3.76k | if (word_size != 2 && word_size != 4) |
641 | 0 | return false; |
642 | | |
643 | 3.76k | size_t num_words = bytes / word_size; |
644 | 3.76k | uint8_t *ud = d; |
645 | | |
646 | 3.76k | switch (word_size) { |
647 | 3.76k | case 2: |
648 | 6.72k | for (size_t x = 0; x < num_words; x++) |
649 | 3.76k | AV_WL16(ud + x * 2, AV_RB16(ud + x * 2)); |
650 | 3.76k | break; |
651 | 0 | case 4: |
652 | 0 | for (size_t x = 0; x < num_words; x++) |
653 | 0 | AV_WL32(ud + x * 2, AV_RB32(ud + x * 2)); |
654 | 0 | break; |
655 | 0 | default: |
656 | 0 | MP_ASSERT_UNREACHABLE(); |
657 | 3.76k | } |
658 | | |
659 | 3.76k | return true; |
660 | 3.76k | } |
661 | | |
662 | | // Bottom/right border is allowed not to be aligned, but it might implicitly |
663 | | // overwrite pixel data until the alignment (align_x/align_y) is reached. |
664 | | // Alpha is cleared to 0 (fully transparent). |
665 | | void mp_image_clear(struct mp_image *img, int x0, int y0, int x1, int y1) |
666 | 48.1k | { |
667 | 48.1k | mp_assert(x0 >= 0 && y0 >= 0); |
668 | 48.1k | mp_assert(x0 <= x1 && y0 <= y1); |
669 | 48.1k | mp_assert(x1 <= img->w && y1 <= img->h); |
670 | 48.1k | mp_assert(!(x0 & (img->fmt.align_x - 1))); |
671 | 48.1k | mp_assert(!(y0 & (img->fmt.align_y - 1))); |
672 | | |
673 | 48.1k | struct mp_image area = *img; |
674 | 48.1k | struct mp_imgfmt_desc *fmt = &area.fmt; |
675 | 48.1k | mp_image_crop(&area, x0, y0, x1, y1); |
676 | | |
677 | | // "Black" color for each plane. |
678 | 48.1k | uint8_t plane_clear[MP_MAX_PLANES][8] = {0}; |
679 | 48.1k | int plane_size[MP_MAX_PLANES] = {0}; |
680 | 48.1k | int misery = 1; // pixel group width |
681 | | |
682 | | // YUV integer chroma needs special consideration, and technically luma is |
683 | | // usually not 0 either. |
684 | 48.1k | if ((fmt->flags & (MP_IMGFLAG_HAS_COMPS | MP_IMGFLAG_PACKED_SS_YUV)) && |
685 | 48.1k | (fmt->flags & MP_IMGFLAG_TYPE_MASK) == MP_IMGFLAG_TYPE_UINT && |
686 | 48.1k | (fmt->flags & MP_IMGFLAG_COLOR_MASK) == MP_IMGFLAG_COLOR_YUV) |
687 | 30.8k | { |
688 | 30.8k | uint64_t plane_clear_i[MP_MAX_PLANES] = {0}; |
689 | | |
690 | | // Need to handle "multiple" pixels with packed YUV. |
691 | 30.8k | uint8_t luma_offsets[4] = {0}; |
692 | 30.8k | if (fmt->flags & MP_IMGFLAG_PACKED_SS_YUV) { |
693 | 156 | misery = fmt->align_x; |
694 | 156 | if (misery <= MP_ARRAY_SIZE(luma_offsets)) // ignore if out of bounds |
695 | 156 | mp_imgfmt_get_packed_yuv_locations(fmt->id, luma_offsets); |
696 | 156 | } |
697 | | |
698 | 154k | for (int c = 0; c < 4; c++) { |
699 | 123k | struct mp_imgfmt_comp_desc *cd = &fmt->comps[c]; |
700 | 123k | int plane_bits = fmt->bpp[cd->plane] * misery; |
701 | 123k | if (plane_bits <= 64 && plane_bits % 8u == 0 && cd->size) { |
702 | 89.9k | plane_size[cd->plane] = plane_bits / 8u; |
703 | 89.9k | int depth = cd->size + MPMIN(cd->pad, 0); |
704 | 89.9k | double m, o; |
705 | 89.9k | mp_get_csp_uint_mul(area.params.repr.sys, |
706 | 89.9k | area.params.repr.levels, |
707 | 89.9k | depth, c + 1, &m, &o); |
708 | 89.9k | uint64_t val = MPCLAMP(lrint((0 - o) / m), 0, 1ull << depth); |
709 | 89.9k | plane_clear_i[cd->plane] |= val << cd->offset; |
710 | 90.1k | for (int x = 1; x < (c ? 0 : misery); x++) |
711 | 156 | plane_clear_i[cd->plane] |= val << luma_offsets[x]; |
712 | 89.9k | } |
713 | 123k | } |
714 | | |
715 | 154k | for (int p = 0; p < MP_MAX_PLANES; p++) { |
716 | 123k | if (!plane_clear_i[p]) |
717 | 49.8k | plane_size[p] = 0; |
718 | 123k | memcpy(&plane_clear[p][0], &plane_clear_i[p], 8); // endian dependent |
719 | | |
720 | 123k | if (fmt->endian_shift) { |
721 | 3.76k | endian_swap_bytes(&plane_clear[p][0], plane_size[p], |
722 | 3.76k | 1 << fmt->endian_shift); |
723 | 3.76k | } |
724 | 123k | } |
725 | 30.8k | } |
726 | | |
727 | 174k | for (int p = 0; p < area.num_planes; p++) { |
728 | 126k | int p_h = mp_image_plane_h(&area, p); |
729 | 126k | int p_w = mp_image_plane_w(&area, p); |
730 | 8.91M | for (int y = 0; y < p_h; y++) { |
731 | 8.78M | void *ptr = area.planes[p] + (ptrdiff_t)area.stride[p] * y; |
732 | 8.78M | if (plane_size[p]) { |
733 | 5.96M | memset_pattern(ptr, p_w / misery, plane_clear[p], plane_size[p]); |
734 | 5.96M | } else { |
735 | 2.82M | memset(ptr, 0, mp_image_plane_bytes(&area, p, 0, area.w)); |
736 | 2.82M | } |
737 | 8.78M | } |
738 | 126k | } |
739 | 48.1k | } |
740 | | |
741 | | void mp_image_clear_rc(struct mp_image *mpi, struct mp_rect rc) |
742 | 0 | { |
743 | 0 | mp_image_clear(mpi, rc.x0, rc.y0, rc.x1, rc.y1); |
744 | 0 | } |
745 | | |
746 | | // Clear the are of the image _not_ covered by rc. |
747 | | void mp_image_clear_rc_inv(struct mp_image *mpi, struct mp_rect rc) |
748 | 0 | { |
749 | 0 | struct mp_rect clr[4]; |
750 | 0 | int cnt = mp_rect_subtract(&(struct mp_rect){0, 0, mpi->w, mpi->h}, &rc, clr); |
751 | 0 | for (int n = 0; n < cnt; n++) |
752 | 0 | mp_image_clear_rc(mpi, clr[n]); |
753 | 0 | } |
754 | | |
755 | | void mp_image_vflip(struct mp_image *img) |
756 | 0 | { |
757 | 0 | for (int p = 0; p < img->num_planes; p++) { |
758 | 0 | int plane_h = mp_image_plane_h(img, p); |
759 | 0 | img->planes[p] = img->planes[p] + img->stride[p] * (plane_h - 1); |
760 | 0 | img->stride[p] = -img->stride[p]; |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | | bool mp_image_crop_valid(const struct mp_image_params *p) |
765 | 634k | { |
766 | 634k | return p->crop.x1 > p->crop.x0 && p->crop.y1 > p->crop.y0 && |
767 | 630k | p->crop.x0 >= 0 && p->crop.y0 >= 0 && |
768 | 630k | p->crop.x1 <= p->w && p->crop.y1 <= p->h; |
769 | 634k | } |
770 | | |
771 | | // Display size derived from image size and pixel aspect ratio. |
772 | | void mp_image_params_get_dsize(const struct mp_image_params *p, |
773 | | int *d_w, int *d_h) |
774 | 64.2k | { |
775 | 64.2k | if (mp_image_crop_valid(p)) |
776 | 61.0k | { |
777 | 61.0k | *d_w = mp_rect_w(p->crop); |
778 | 61.0k | *d_h = mp_rect_h(p->crop); |
779 | 61.0k | } else { |
780 | 3.21k | *d_w = p->w; |
781 | 3.21k | *d_h = p->h; |
782 | 3.21k | } |
783 | | |
784 | 64.2k | if (p->p_w > p->p_h && p->p_h >= 1) |
785 | 19.2k | *d_w = MPCLAMP(*d_w * (int64_t)p->p_w / p->p_h, 1, INT_MAX); |
786 | 64.2k | if (p->p_h > p->p_w && p->p_w >= 1) |
787 | 5.06k | *d_h = MPCLAMP(*d_h * (int64_t)p->p_h / p->p_w, 1, INT_MAX); |
788 | 64.2k | } |
789 | | |
790 | | void mp_image_params_set_dsize(struct mp_image_params *p, int d_w, int d_h) |
791 | 37.0k | { |
792 | 37.0k | AVRational ds = av_div_q((AVRational){d_w, d_h}, (AVRational){p->w, p->h}); |
793 | 37.0k | p->p_w = ds.num; |
794 | 37.0k | p->p_h = ds.den; |
795 | 37.0k | } |
796 | | |
797 | | char *mp_image_params_to_str_buf(char *b, size_t bs, |
798 | | const struct mp_image_params *p) |
799 | 213k | { |
800 | 213k | if (p && p->imgfmt) { |
801 | 213k | snprintf(b, bs, "%dx%d", p->w, p->h); |
802 | 213k | if (p->p_w != p->p_h || !p->p_w) |
803 | 59.3k | mp_snprintf_cat(b, bs, " [%d:%d]", p->p_w, p->p_h); |
804 | 213k | mp_snprintf_cat(b, bs, " %s", mp_imgfmt_to_name(p->imgfmt)); |
805 | 213k | if (p->hw_subfmt) |
806 | 0 | mp_snprintf_cat(b, bs, "[%s]", mp_imgfmt_to_name(p->hw_subfmt)); |
807 | 213k | mp_snprintf_cat(b, bs, " %s/%s/%s/%s/%s", |
808 | 213k | m_opt_choice_str(pl_csp_names, p->repr.sys), |
809 | 213k | m_opt_choice_str(pl_csp_prim_names, p->color.primaries), |
810 | 213k | m_opt_choice_str(pl_csp_trc_names, p->color.transfer), |
811 | 213k | m_opt_choice_str(pl_csp_levels_names, p->repr.levels), |
812 | 213k | m_opt_choice_str(mp_csp_light_names, p->light)); |
813 | 213k | mp_snprintf_cat(b, bs, " CL=%s", |
814 | 213k | m_opt_choice_str(pl_chroma_names, p->chroma_location)); |
815 | 213k | if (mp_image_crop_valid(p)) { |
816 | 211k | mp_snprintf_cat(b, bs, " crop=%dx%d+%d+%d", mp_rect_w(p->crop), |
817 | 211k | mp_rect_h(p->crop), p->crop.x0, p->crop.y0); |
818 | 211k | } |
819 | 213k | if (p->rotate) |
820 | 622 | mp_snprintf_cat(b, bs, " rot=%d", p->rotate); |
821 | 213k | if (p->stereo3d > 0) { |
822 | 0 | mp_snprintf_cat(b, bs, " stereo=%s", |
823 | 0 | MP_STEREO3D_NAME_DEF(p->stereo3d, "?")); |
824 | 0 | } |
825 | 213k | if (p->repr.alpha) { |
826 | 202k | mp_snprintf_cat(b, bs, " A=%s", |
827 | 202k | m_opt_choice_str(pl_alpha_names, p->repr.alpha)); |
828 | 202k | } |
829 | 213k | } else { |
830 | 0 | snprintf(b, bs, "???"); |
831 | 0 | } |
832 | 213k | return b; |
833 | 213k | } |
834 | | |
835 | | // Return whether the image parameters are valid. |
836 | | // Some non-essential fields are allowed to be unset (like colorspace flags). |
837 | | bool mp_image_params_valid(const struct mp_image_params *p) |
838 | 41.4k | { |
839 | | // av_image_check_size has similar checks and triggers around 16000*16000 |
840 | | // It's mostly needed to deal with the fact that offsets are sometimes |
841 | | // ints. We also should (for now) do the same as FFmpeg, to be sure large |
842 | | // images don't crash with libswscale or when wrapping with AVFrame and |
843 | | // passing the result to filters. |
844 | 41.4k | if (p->w <= 0 || p->h <= 0 || (p->w + 128LL) * (p->h + 128LL) >= INT_MAX / 8) |
845 | 26 | return false; |
846 | | |
847 | 41.4k | if (p->p_w < 0 || p->p_h < 0) |
848 | 0 | return false; |
849 | | |
850 | 41.4k | if (p->rotate < 0 || p->rotate >= 360) |
851 | 0 | return false; |
852 | | |
853 | 41.4k | struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(p->imgfmt); |
854 | 41.4k | if (!desc.id) |
855 | 0 | return false; |
856 | | |
857 | 41.4k | if (p->hw_subfmt && !(desc.flags & MP_IMGFLAG_HWACCEL)) |
858 | 0 | return false; |
859 | | |
860 | 41.4k | return true; |
861 | 41.4k | } |
862 | | |
863 | | bool mp_image_params_equal(const struct mp_image_params *p1, |
864 | | const struct mp_image_params *p2) |
865 | 3.06M | { |
866 | 3.06M | return p1->imgfmt == p2->imgfmt && |
867 | 2.71M | p1->hw_subfmt == p2->hw_subfmt && |
868 | 2.71M | p1->w == p2->w && p1->h == p2->h && |
869 | 2.68M | p1->p_w == p2->p_w && p1->p_h == p2->p_h && |
870 | 2.67M | p1->force_window == p2->force_window && |
871 | 2.67M | pl_color_space_equal(&p1->color, &p2->color) && |
872 | 2.67M | pl_color_repr_equal(&p1->repr, &p2->repr) && |
873 | 2.67M | p1->light == p2->light && |
874 | 2.67M | p1->chroma_location == p2->chroma_location && |
875 | 2.67M | p1->vflip == p2->vflip && |
876 | 2.67M | p1->rotate == p2->rotate && |
877 | 2.67M | p1->stereo3d == p2->stereo3d && |
878 | 2.67M | mp_rect_equals(&p1->crop, &p2->crop); |
879 | 3.06M | } |
880 | | |
881 | | bool mp_image_params_static_equal(const struct mp_image_params *p1, |
882 | | const struct mp_image_params *p2) |
883 | 525k | { |
884 | | // Compare only static video parameters, excluding dynamic metadata. |
885 | 525k | struct mp_image_params a = *p1; |
886 | 525k | struct mp_image_params b = *p2; |
887 | 525k | a.repr.dovi = b.repr.dovi = NULL; |
888 | 525k | a.color.hdr = b.color.hdr = (struct pl_hdr_metadata){0}; |
889 | 525k | return mp_image_params_equal(&a, &b); |
890 | 525k | } |
891 | | |
892 | | void mp_image_params_update_dynamic(struct mp_image_params *dst, |
893 | | const struct mp_image_params *src, |
894 | | bool has_peak_detect_values) |
895 | 332k | { |
896 | 332k | dst->repr.dovi = src->repr.dovi; |
897 | | // Don't overwrite peak-detected HDR metadata if available. |
898 | 332k | float max_pq_y = dst->color.hdr.max_pq_y; |
899 | 332k | float avg_pq_y = dst->color.hdr.avg_pq_y; |
900 | 332k | dst->color.hdr = src->color.hdr; |
901 | 332k | if (has_peak_detect_values) { |
902 | 0 | dst->color.hdr.max_pq_y = max_pq_y; |
903 | 0 | dst->color.hdr.avg_pq_y = avg_pq_y; |
904 | 0 | } |
905 | 332k | } |
906 | | |
907 | | // Restore color system, transfer, and primaries to their original values |
908 | | // before dovi mapping. |
909 | | void mp_image_params_restore_dovi_mapping(struct mp_image_params *params) |
910 | 0 | { |
911 | 0 | if (params->repr.sys != PL_COLOR_SYSTEM_DOLBYVISION) |
912 | 0 | return; |
913 | 0 | params->color.primaries = params->primaries_orig; |
914 | 0 | params->color.transfer = params->transfer_orig; |
915 | 0 | params->repr.sys = params->sys_orig; |
916 | 0 | if (!pl_color_transfer_is_hdr(params->transfer_orig)) |
917 | 0 | params->color.hdr = (struct pl_hdr_metadata){0}; |
918 | 0 | if (params->transfer_orig != PL_COLOR_TRC_PQ) |
919 | 0 | params->color.hdr.max_pq_y = params->color.hdr.avg_pq_y = 0; |
920 | 0 | } |
921 | | |
922 | | // Set most image parameters, but not image format or size. |
923 | | // Display size is used to set the PAR. |
924 | | void mp_image_set_attributes(struct mp_image *image, |
925 | | const struct mp_image_params *params) |
926 | 0 | { |
927 | 0 | struct mp_image_params nparams = *params; |
928 | 0 | nparams.imgfmt = image->imgfmt; |
929 | 0 | nparams.w = image->w; |
930 | 0 | nparams.h = image->h; |
931 | 0 | if (nparams.imgfmt != params->imgfmt) { |
932 | 0 | nparams.repr = (struct pl_color_repr){0}; |
933 | 0 | nparams.color = (struct pl_color_space){0}; |
934 | 0 | } |
935 | 0 | mp_image_set_params(image, &nparams); |
936 | 0 | } |
937 | | |
938 | | static enum pl_color_levels infer_levels(enum mp_imgfmt imgfmt) |
939 | 15.2k | { |
940 | 15.2k | switch (imgfmt2pixfmt(imgfmt)) { |
941 | 0 | case AV_PIX_FMT_YUVJ420P: |
942 | 0 | case AV_PIX_FMT_YUVJ411P: |
943 | 0 | case AV_PIX_FMT_YUVJ422P: |
944 | 0 | case AV_PIX_FMT_YUVJ444P: |
945 | 0 | case AV_PIX_FMT_YUVJ440P: |
946 | 780 | case AV_PIX_FMT_GRAY8: |
947 | 782 | case AV_PIX_FMT_YA8: |
948 | 782 | case AV_PIX_FMT_GRAY9LE: |
949 | 782 | case AV_PIX_FMT_GRAY9BE: |
950 | 782 | case AV_PIX_FMT_GRAY10LE: |
951 | 782 | case AV_PIX_FMT_GRAY10BE: |
952 | 782 | case AV_PIX_FMT_GRAY12LE: |
953 | 782 | case AV_PIX_FMT_GRAY12BE: |
954 | 782 | case AV_PIX_FMT_GRAY14LE: |
955 | 782 | case AV_PIX_FMT_GRAY14BE: |
956 | 1.01k | case AV_PIX_FMT_GRAY16LE: |
957 | 1.01k | case AV_PIX_FMT_GRAY16BE: |
958 | 1.01k | case AV_PIX_FMT_YA16BE: |
959 | 1.01k | case AV_PIX_FMT_YA16LE: |
960 | 1.01k | return PL_COLOR_LEVELS_FULL; |
961 | 14.2k | default: |
962 | 14.2k | return PL_COLOR_LEVELS_LIMITED; |
963 | 15.2k | } |
964 | 15.2k | } |
965 | | |
966 | | // If details like params->colorspace/colorlevels are missing, guess them from |
967 | | // the other settings. Also, even if they are set, make them consistent with |
968 | | // the colorspace as implied by the pixel format. |
969 | | void mp_image_params_guess_csp(struct mp_image_params *params) |
970 | 94.3k | { |
971 | 94.3k | enum pl_color_system forced_csp = mp_image_params_get_forced_csp(params); |
972 | 94.3k | if (forced_csp == PL_COLOR_SYSTEM_UNKNOWN) { // YUV/other |
973 | 69.2k | if (params->repr.sys != PL_COLOR_SYSTEM_BT_601 && |
974 | 24.4k | params->repr.sys != PL_COLOR_SYSTEM_BT_709 && |
975 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_BT_2020_NC && |
976 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_BT_2020_C && |
977 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_BT_2100_PQ && |
978 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_BT_2100_HLG && |
979 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_DOLBYVISION && |
980 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_SMPTE_240M && |
981 | 18.2k | params->repr.sys != PL_COLOR_SYSTEM_YCGCO |
982 | 18.2k | #if PL_API_VER >= 358 |
983 | 18.2k | && params->repr.sys != PL_COLOR_SYSTEM_YCGCO_RE |
984 | 18.2k | && params->repr.sys != PL_COLOR_SYSTEM_YCGCO_RO |
985 | 69.2k | #endif |
986 | 69.2k | ) { |
987 | | // Makes no sense, so guess instead |
988 | | // YCGCO should be separate, but libavcodec disagrees |
989 | 18.2k | params->repr.sys = PL_COLOR_SYSTEM_UNKNOWN; |
990 | 18.2k | } |
991 | 69.2k | if (params->repr.sys == PL_COLOR_SYSTEM_UNKNOWN) |
992 | 18.2k | params->repr.sys = mp_csp_guess_colorspace(params->w, params->h); |
993 | 69.2k | if (params->repr.levels == PL_COLOR_LEVELS_UNKNOWN) { |
994 | 15.2k | if (params->color.transfer == PL_COLOR_TRC_V_LOG) { |
995 | 0 | params->repr.levels = PL_COLOR_LEVELS_FULL; |
996 | 15.2k | } else { |
997 | 15.2k | params->repr.levels = infer_levels(params->imgfmt); |
998 | 15.2k | } |
999 | 15.2k | } |
1000 | 69.2k | if (params->color.primaries == PL_COLOR_PRIM_UNKNOWN) { |
1001 | | // Guess based on the colormatrix as a first priority |
1002 | 18.8k | if (params->repr.sys == PL_COLOR_SYSTEM_BT_2020_NC || |
1003 | 18.8k | params->repr.sys == PL_COLOR_SYSTEM_BT_2020_C) { |
1004 | 7 | params->color.primaries = PL_COLOR_PRIM_BT_2020; |
1005 | 18.8k | } else if (params->repr.sys == PL_COLOR_SYSTEM_BT_709) { |
1006 | 2.32k | params->color.primaries = PL_COLOR_PRIM_BT_709; |
1007 | 16.4k | } else { |
1008 | | // Ambiguous colormatrix for BT.601, guess based on res |
1009 | 16.4k | params->color.primaries = mp_csp_guess_primaries(params->w, params->h); |
1010 | 16.4k | } |
1011 | 18.8k | } |
1012 | 69.2k | if (params->color.transfer == PL_COLOR_TRC_UNKNOWN) |
1013 | 18.7k | params->color.transfer = params->repr.levels == PL_COLOR_LEVELS_LIMITED ? |
1014 | 17.3k | PL_COLOR_TRC_BT_1886 : PL_COLOR_TRC_SRGB; |
1015 | 69.2k | } else if (forced_csp == PL_COLOR_SYSTEM_RGB) { |
1016 | 20.4k | params->repr.sys = PL_COLOR_SYSTEM_RGB; |
1017 | 20.4k | params->repr.levels = PL_COLOR_LEVELS_FULL; |
1018 | | |
1019 | | // The majority of RGB content is either sRGB or (rarely) some other |
1020 | | // color space which we don't even handle, like AdobeRGB or |
1021 | | // ProPhotoRGB. The only reasonable thing we can do is assume it's |
1022 | | // sRGB and hope for the best, which should usually just work out fine. |
1023 | | // Note: sRGB primaries = BT.709 primaries |
1024 | 20.4k | if (params->color.primaries == PL_COLOR_PRIM_UNKNOWN) |
1025 | 5.16k | params->color.primaries = PL_COLOR_PRIM_BT_709; |
1026 | 20.4k | if (params->color.transfer == PL_COLOR_TRC_UNKNOWN) |
1027 | 5.19k | params->color.transfer = PL_COLOR_TRC_SRGB; |
1028 | 20.4k | } else if (forced_csp == PL_COLOR_SYSTEM_XYZ) { |
1029 | 4.62k | params->repr.sys = PL_COLOR_SYSTEM_XYZ; |
1030 | 4.62k | params->repr.levels = PL_COLOR_LEVELS_FULL; |
1031 | | // Force gamma to ST428 as this is the only correct for DCDM X'Y'Z' |
1032 | 4.62k | params->color.transfer = PL_COLOR_TRC_ST428; |
1033 | | // Don't care about primaries, they shouldn't be used, or if anything |
1034 | | // MP_CSP_PRIM_ST428 should be defined. |
1035 | 4.62k | } else { |
1036 | | // We have no clue. |
1037 | 0 | params->repr.sys = PL_COLOR_SYSTEM_UNKNOWN; |
1038 | 0 | params->repr.levels = PL_COLOR_LEVELS_UNKNOWN; |
1039 | 0 | params->color.primaries = PL_COLOR_PRIM_UNKNOWN; |
1040 | 0 | params->color.transfer = PL_COLOR_TRC_UNKNOWN; |
1041 | 0 | } |
1042 | | |
1043 | | // If the signal peak is unknown, we're forced to pick the TRC's |
1044 | | // nominal range as the signal peak to prevent clipping |
1045 | 94.3k | pl_color_space_infer(¶ms->color); |
1046 | | |
1047 | 94.3k | if (!pl_color_space_is_hdr(¶ms->color)) { |
1048 | | // Some clips have leftover HDR metadata after conversion to SDR, so to |
1049 | | // avoid blowing up the tone mapping code, strip/sanitize it |
1050 | 94.2k | params->color.hdr = pl_hdr_metadata_empty; |
1051 | 94.2k | } |
1052 | | |
1053 | 94.3k | if (mp_imgfmt_is_subsampled(params->hw_subfmt ? params->hw_subfmt : params->imgfmt)) { |
1054 | 30.4k | if (params->chroma_location == PL_CHROMA_UNKNOWN) { |
1055 | 2.70k | if (params->repr.levels == PL_COLOR_LEVELS_LIMITED) |
1056 | 2.40k | params->chroma_location = PL_CHROMA_LEFT; |
1057 | 2.70k | if (params->repr.levels == PL_COLOR_LEVELS_FULL) |
1058 | 301 | params->chroma_location = PL_CHROMA_CENTER; |
1059 | 2.70k | } |
1060 | 63.8k | } else { |
1061 | | // Set to center for non-subsampled formats. |
1062 | 63.8k | params->chroma_location = PL_CHROMA_CENTER; |
1063 | 63.8k | } |
1064 | | |
1065 | 94.3k | if (params->light == MP_CSP_LIGHT_AUTO) { |
1066 | | // HLG is always scene-referred (using its own OOTF), everything else |
1067 | | // we assume is display-referred by default. |
1068 | 25.8k | if (params->color.transfer == PL_COLOR_TRC_HLG) { |
1069 | 0 | params->light = MP_CSP_LIGHT_SCENE_HLG; |
1070 | 25.8k | } else { |
1071 | 25.8k | params->light = MP_CSP_LIGHT_DISPLAY; |
1072 | 25.8k | } |
1073 | 25.8k | } |
1074 | 94.3k | } |
1075 | | |
1076 | | // Create a new mp_image reference to av_frame. |
1077 | | struct mp_image *mp_image_from_av_frame(struct AVFrame *src) |
1078 | 368k | { |
1079 | 368k | struct mp_image *dst = &(struct mp_image){0}; |
1080 | 368k | AVFrameSideData *sd; |
1081 | | |
1082 | 1.84M | for (int p = 0; p < MP_MAX_PLANES; p++) |
1083 | 1.47M | dst->bufs[p] = src->buf[p]; |
1084 | | |
1085 | 368k | dst->hwctx = src->hw_frames_ctx; |
1086 | | |
1087 | 368k | if (dst->hwctx) { |
1088 | 0 | AVHWFramesContext *fctx = (void *)dst->hwctx->data; |
1089 | 0 | dst->params.hw_subfmt = pixfmt2imgfmt(fctx->sw_format); |
1090 | 0 | } |
1091 | | |
1092 | 368k | mp_image_sethwfmt(dst, pixfmt2imgfmt(src->format), dst->params.hw_subfmt); |
1093 | 368k | mp_image_set_size(dst, src->width, src->height); |
1094 | | |
1095 | 368k | dst->params.p_w = src->sample_aspect_ratio.num; |
1096 | 368k | dst->params.p_h = src->sample_aspect_ratio.den; |
1097 | | |
1098 | 1.84M | for (int i = 0; i < 4; i++) { |
1099 | 1.47M | dst->planes[i] = src->data[i]; |
1100 | 1.47M | dst->stride[i] = src->linesize[i]; |
1101 | 1.47M | } |
1102 | | |
1103 | 368k | dst->pict_type = src->pict_type; |
1104 | | |
1105 | 368k | dst->params.crop.x0 = src->crop_left; |
1106 | 368k | dst->params.crop.y0 = src->crop_top; |
1107 | 368k | dst->params.crop.x1 = src->width - src->crop_right; |
1108 | 368k | dst->params.crop.y1 = src->height - src->crop_bottom; |
1109 | | |
1110 | 368k | dst->fields = 0; |
1111 | 368k | if (src->flags & AV_FRAME_FLAG_INTERLACED) |
1112 | 4.79k | dst->fields |= MP_IMGFIELD_INTERLACED; |
1113 | 368k | if (src->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) |
1114 | 22.3k | dst->fields |= MP_IMGFIELD_TOP_FIRST; |
1115 | 368k | if (src->repeat_pict == 1) |
1116 | 192 | dst->fields |= MP_IMGFIELD_REPEAT_FIRST; |
1117 | | |
1118 | 368k | dst->params.repr.sys = pl_system_from_av(src->colorspace); |
1119 | 368k | dst->params.repr.levels = pl_levels_from_av(src->color_range); |
1120 | | |
1121 | 368k | dst->params.color = (struct pl_color_space){ |
1122 | 368k | .primaries = pl_primaries_from_av(src->color_primaries), |
1123 | 368k | .transfer = pl_transfer_from_av(src->color_trc), |
1124 | 368k | }; |
1125 | | |
1126 | 368k | dst->params.chroma_location = pl_chroma_from_av(src->chroma_location); |
1127 | | |
1128 | 368k | if (src->opaque_ref) { |
1129 | 0 | struct mp_image_params *p = (void *)src->opaque_ref->data; |
1130 | 0 | dst->params.stereo3d = p->stereo3d; |
1131 | | // Might be incorrect if colorspace changes. |
1132 | 0 | dst->params.light = p->light; |
1133 | | #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(60, 11, 100) || PL_API_VER < 356 |
1134 | | dst->params.repr.alpha = p->repr.alpha; |
1135 | | #endif |
1136 | 0 | } |
1137 | | |
1138 | 368k | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(60, 11, 100) && PL_API_VER >= 356 |
1139 | | // mp_image_setfmt sets to PL_ALPHA_INDEPENDENT, if format has alpha. |
1140 | 368k | if (dst->params.repr.alpha == PL_ALPHA_INDEPENDENT) |
1141 | 192k | dst->params.repr.alpha = pl_alpha_from_av(src->alpha_mode); |
1142 | 368k | #endif |
1143 | | |
1144 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_DISPLAYMATRIX); |
1145 | 368k | if (sd) { |
1146 | 86 | int32_t *matrix = (int32_t *) sd->data; |
1147 | | // determinant |
1148 | 86 | int vflip = ((int64_t)matrix[0] * (int64_t)matrix[4] |
1149 | 86 | - (int64_t)matrix[1] * (int64_t)matrix[3]) < 0; |
1150 | 86 | double r = av_display_rotation_get(matrix); |
1151 | 86 | if (!isnan(r)) { |
1152 | 86 | dst->params.rotate = (((int)(-r) % 360) + 360) % 360; |
1153 | 86 | dst->params.vflip = vflip; |
1154 | 86 | } |
1155 | 86 | } |
1156 | | |
1157 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_ICC_PROFILE); |
1158 | 368k | if (sd) |
1159 | 6 | dst->icc_profile = sd->buf; |
1160 | | |
1161 | 368k | AVFrameSideData *mdm = av_frame_get_side_data(src, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); |
1162 | 368k | AVFrameSideData *clm = av_frame_get_side_data(src, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); |
1163 | 368k | AVFrameSideData *dhp = av_frame_get_side_data(src, AV_FRAME_DATA_DYNAMIC_HDR_PLUS); |
1164 | 368k | pl_map_hdr_metadata(&dst->params.color.hdr, &(struct pl_av_hdr_metadata) { |
1165 | 368k | .mdm = (void *)(mdm ? mdm->data : NULL), |
1166 | 368k | .clm = (void *)(clm ? clm->data : NULL), |
1167 | 368k | .dhp = (void *)(dhp ? dhp->data : NULL), |
1168 | 368k | }); |
1169 | | |
1170 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_A53_CC); |
1171 | 368k | if (sd) |
1172 | 1.66k | dst->a53_cc = sd->buf; |
1173 | | |
1174 | 368k | dst->params.primaries_orig = dst->params.color.primaries; |
1175 | 368k | dst->params.transfer_orig = dst->params.color.transfer; |
1176 | 368k | dst->params.sys_orig = dst->params.repr.sys; |
1177 | 368k | AVBufferRef *dovi = NULL; |
1178 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_DOVI_METADATA); |
1179 | 368k | if (sd) { |
1180 | 0 | #ifdef PL_HAVE_LAV_DOLBY_VISION |
1181 | 0 | const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->buf->data; |
1182 | 0 | const AVDOVIRpuDataHeader *header = av_dovi_get_header(metadata); |
1183 | 0 | if (header->disable_residual_flag) { |
1184 | 0 | dst->dovi = dovi = av_buffer_alloc(sizeof(struct pl_dovi_metadata)); |
1185 | 0 | MP_HANDLE_OOM(dovi); |
1186 | 0 | #if PL_API_VER >= 343 |
1187 | 0 | pl_map_avdovi_metadata(&dst->params.color, &dst->params.repr, |
1188 | 0 | (void *)dst->dovi->data, metadata); |
1189 | | #else |
1190 | | struct pl_frame frame; |
1191 | | frame.repr = dst->params.repr; |
1192 | | frame.color = dst->params.color; |
1193 | | pl_frame_map_avdovi_metadata(&frame, (void *)dst->dovi->data, metadata); |
1194 | | dst->params.repr = frame.repr; |
1195 | | dst->params.color = frame.color; |
1196 | | #endif |
1197 | 0 | } |
1198 | 0 | #endif |
1199 | 0 | } |
1200 | | |
1201 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_DOVI_RPU_BUFFER); |
1202 | 368k | if (sd) { |
1203 | 0 | pl_hdr_metadata_from_dovi_rpu(&dst->params.color.hdr, sd->buf->data, |
1204 | 0 | sd->buf->size); |
1205 | 0 | } |
1206 | | |
1207 | 368k | sd = av_frame_get_side_data(src, AV_FRAME_DATA_FILM_GRAIN_PARAMS); |
1208 | 368k | if (sd) |
1209 | 0 | dst->film_grain = sd->buf; |
1210 | | |
1211 | 411k | for (int n = 0; n < src->nb_side_data; n++) { |
1212 | 42.8k | sd = src->side_data[n]; |
1213 | 42.8k | struct mp_ff_side_data mpsd = { |
1214 | 42.8k | .type = sd->type, |
1215 | 42.8k | .buf = sd->buf, |
1216 | 42.8k | }; |
1217 | 42.8k | MP_TARRAY_APPEND(NULL, dst->ff_side_data, dst->num_ff_side_data, mpsd); |
1218 | 42.8k | } |
1219 | | |
1220 | 368k | struct mp_image *res = mp_image_new_ref(dst); |
1221 | | |
1222 | | // Allocated, but non-refcounted data. |
1223 | 368k | talloc_free(dst->ff_side_data); |
1224 | 368k | av_buffer_unref(&dovi); |
1225 | | |
1226 | 368k | return res; |
1227 | 368k | } |
1228 | | |
1229 | | |
1230 | | // Convert the mp_image reference to a AVFrame reference. |
1231 | | struct AVFrame *mp_image_to_av_frame(struct mp_image *src) |
1232 | 0 | { |
1233 | 0 | struct mp_image *new_ref = mp_image_new_ref(src); |
1234 | 0 | AVFrame *dst = av_frame_alloc(); |
1235 | 0 | if (!dst || !new_ref) { |
1236 | 0 | talloc_free(new_ref); |
1237 | 0 | av_frame_free(&dst); |
1238 | 0 | return NULL; |
1239 | 0 | } |
1240 | | |
1241 | 0 | for (int p = 0; p < MP_MAX_PLANES; p++) { |
1242 | 0 | dst->buf[p] = new_ref->bufs[p]; |
1243 | 0 | new_ref->bufs[p] = NULL; |
1244 | 0 | } |
1245 | |
|
1246 | 0 | dst->hw_frames_ctx = new_ref->hwctx; |
1247 | 0 | new_ref->hwctx = NULL; |
1248 | |
|
1249 | 0 | dst->format = imgfmt2pixfmt(src->imgfmt); |
1250 | 0 | dst->width = src->w; |
1251 | 0 | dst->height = src->h; |
1252 | |
|
1253 | 0 | dst->crop_left = src->params.crop.x0; |
1254 | 0 | dst->crop_top = src->params.crop.y0; |
1255 | 0 | dst->crop_right = dst->width - src->params.crop.x1; |
1256 | 0 | dst->crop_bottom = dst->height - src->params.crop.y1; |
1257 | |
|
1258 | 0 | dst->sample_aspect_ratio.num = src->params.p_w; |
1259 | 0 | dst->sample_aspect_ratio.den = src->params.p_h; |
1260 | |
|
1261 | 0 | for (int i = 0; i < 4; i++) { |
1262 | 0 | dst->data[i] = src->planes[i]; |
1263 | 0 | dst->linesize[i] = src->stride[i]; |
1264 | 0 | } |
1265 | 0 | dst->extended_data = dst->data; |
1266 | |
|
1267 | 0 | dst->pict_type = src->pict_type; |
1268 | 0 | if (src->fields & MP_IMGFIELD_INTERLACED) |
1269 | 0 | dst->flags |= AV_FRAME_FLAG_INTERLACED; |
1270 | 0 | if (src->fields & MP_IMGFIELD_TOP_FIRST) |
1271 | 0 | dst->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; |
1272 | 0 | if (src->fields & MP_IMGFIELD_REPEAT_FIRST) |
1273 | 0 | dst->repeat_pict = 1; |
1274 | | |
1275 | | // Image params without dovi mapped; should be passed as side data instead |
1276 | 0 | struct mp_image_params params = src->params; |
1277 | 0 | mp_image_params_restore_dovi_mapping(¶ms); |
1278 | 0 | pl_avframe_set_repr(dst, params.repr); |
1279 | |
|
1280 | 0 | dst->chroma_location = pl_chroma_to_av(params.chroma_location); |
1281 | |
|
1282 | 0 | dst->opaque_ref = av_buffer_alloc(sizeof(struct mp_image_params)); |
1283 | 0 | MP_HANDLE_OOM(dst->opaque_ref); |
1284 | 0 | *(struct mp_image_params *)dst->opaque_ref->data = params; |
1285 | |
|
1286 | 0 | if (src->icc_profile) { |
1287 | 0 | AVFrameSideData *sd = |
1288 | 0 | av_frame_new_side_data_from_buf(dst, AV_FRAME_DATA_ICC_PROFILE, |
1289 | 0 | new_ref->icc_profile); |
1290 | 0 | MP_HANDLE_OOM(sd); |
1291 | 0 | new_ref->icc_profile = NULL; |
1292 | 0 | } |
1293 | | |
1294 | 0 | pl_avframe_set_color(dst, params.color); |
1295 | |
|
1296 | 0 | { |
1297 | 0 | AVFrameSideData *sd = av_frame_new_side_data(dst, |
1298 | 0 | AV_FRAME_DATA_DISPLAYMATRIX, |
1299 | 0 | sizeof(int32_t) * 9); |
1300 | 0 | MP_HANDLE_OOM(sd); |
1301 | 0 | av_display_rotation_set((int32_t *)sd->data, params.rotate); |
1302 | 0 | } |
1303 | | |
1304 | | // Add back side data, but only for types which are not specially handled |
1305 | | // above. Keep in mind that the types above will be out of sync anyway. |
1306 | 0 | for (int n = 0; n < new_ref->num_ff_side_data; n++) { |
1307 | 0 | struct mp_ff_side_data *mpsd = &new_ref->ff_side_data[n]; |
1308 | 0 | if (!av_frame_get_side_data(dst, mpsd->type)) { |
1309 | 0 | AVFrameSideData *sd = av_frame_new_side_data_from_buf(dst, mpsd->type, |
1310 | 0 | mpsd->buf); |
1311 | 0 | MP_HANDLE_OOM(sd); |
1312 | 0 | mpsd->buf = NULL; |
1313 | 0 | } |
1314 | 0 | } |
1315 | | |
1316 | 0 | talloc_free(new_ref); |
1317 | |
|
1318 | 0 | if (dst->format == AV_PIX_FMT_NONE) |
1319 | 0 | av_frame_free(&dst); |
1320 | 0 | return dst; |
1321 | 0 | } |
1322 | | |
1323 | | // Same as mp_image_to_av_frame(), but unref img. (It does so even on failure.) |
1324 | | struct AVFrame *mp_image_to_av_frame_and_unref(struct mp_image *img) |
1325 | 0 | { |
1326 | 0 | AVFrame *frame = mp_image_to_av_frame(img); |
1327 | 0 | talloc_free(img); |
1328 | 0 | return frame; |
1329 | 0 | } |
1330 | | |
1331 | | void memset_pic(void *dst, int fill, int bytesPerLine, int height, int stride) |
1332 | 0 | { |
1333 | 0 | if (bytesPerLine == stride && height) { |
1334 | 0 | memset(dst, fill, stride * (height - 1) + bytesPerLine); |
1335 | 0 | } else { |
1336 | 0 | for (int i = 0; i < height; i++) { |
1337 | 0 | memset(dst, fill, bytesPerLine); |
1338 | 0 | dst = (uint8_t *)dst + stride; |
1339 | 0 | } |
1340 | 0 | } |
1341 | 0 | } |
1342 | | |
1343 | | void memset16_pic(void *dst, int fill, int unitsPerLine, int height, int stride) |
1344 | 0 | { |
1345 | 0 | if (fill == 0) { |
1346 | 0 | memset_pic(dst, 0, unitsPerLine * 2, height, stride); |
1347 | 0 | } else { |
1348 | 0 | for (int i = 0; i < height; i++) { |
1349 | 0 | uint16_t *line = dst; |
1350 | 0 | uint16_t *end = line + unitsPerLine; |
1351 | 0 | while (line < end) |
1352 | 0 | *line++ = fill; |
1353 | 0 | dst = (uint8_t *)dst + stride; |
1354 | 0 | } |
1355 | 0 | } |
1356 | 0 | } |
1357 | | |
1358 | | // Pixel at the given luma position on the given plane. x/y always refer to |
1359 | | // non-subsampled coordinates (even if plane is chroma). |
1360 | | // The coordinates must be aligned to mp_imgfmt_desc.align_x/y (these are byte |
1361 | | // and chroma boundaries). |
1362 | | // You cannot access e.g. individual luma pixels on the luma plane with yuv420p. |
1363 | | void *mp_image_pixel_ptr(struct mp_image *img, int plane, int x, int y) |
1364 | 291k | { |
1365 | 291k | mp_assert(MP_IS_ALIGNED(x, img->fmt.align_x)); |
1366 | 291k | mp_assert(MP_IS_ALIGNED(y, img->fmt.align_y)); |
1367 | 291k | return mp_image_pixel_ptr_ny(img, plane, x, y); |
1368 | 291k | } |
1369 | | |
1370 | | // Like mp_image_pixel_ptr(), but do not require alignment on Y coordinates if |
1371 | | // the plane does not require it. Use with care. |
1372 | | // Useful for addressing luma rows. |
1373 | | void *mp_image_pixel_ptr_ny(struct mp_image *img, int plane, int x, int y) |
1374 | 459k | { |
1375 | 459k | mp_assert(MP_IS_ALIGNED(x, img->fmt.align_x)); |
1376 | 459k | mp_assert(MP_IS_ALIGNED(y, 1 << img->fmt.ys[plane])); |
1377 | 459k | return img->planes[plane] + |
1378 | 459k | img->stride[plane] * (ptrdiff_t)(y >> img->fmt.ys[plane]) + |
1379 | 459k | (x >> img->fmt.xs[plane]) * (size_t)img->fmt.bpp[plane] / 8; |
1380 | 459k | } |
1381 | | |
1382 | | // Return size of pixels [x0, x0+w-1] in bytes. The coordinates refer to non- |
1383 | | // subsampled pixels (basically plane 0), and the size is rounded to chroma |
1384 | | // and byte alignment boundaries for the entire image, even if plane!=0. |
1385 | | // x0!=0 is useful for rounding (e.g. 8 bpp, x0=7, w=7 => 0..15 => 2 bytes). |
1386 | | size_t mp_image_plane_bytes(struct mp_image *img, int plane, int x0, int w) |
1387 | 2.82M | { |
1388 | 2.82M | int x1 = MP_ALIGN_UP(x0 + w, img->fmt.align_x); |
1389 | 2.82M | x0 = MP_ALIGN_DOWN(x0, img->fmt.align_x); |
1390 | 2.82M | size_t bpp = img->fmt.bpp[plane]; |
1391 | 2.82M | int xs = img->fmt.xs[plane]; |
1392 | 2.82M | return (x1 >> xs) * bpp / 8 - (x0 >> xs) * bpp / 8; |
1393 | 2.82M | } |