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