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