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 <assert.h>
19 #include <string.h>
20 
21 #include <libavcodec/avcodec.h>
22 #include <libavutil/imgutils.h>
23 #include <libavutil/pixfmt.h>
24 #include <libavutil/pixdesc.h>
25 
26 #include "config.h"
27 
28 #include "video/img_format.h"
29 #include "video/mp_image.h"
30 #include "video/fmt-conversion.h"
31 
32 struct mp_imgfmt_entry {
33     const char *name;
34     // Valid if flags!=0.
35     // This can be incomplete, and missing fields are filled in:
36     //  - sets num_planes and bpp[], derived from comps[] (rounds to bytes)
37     //  - sets MP_IMGFLAG_GRAY, derived from comps[]
38     //  - sets MP_IMGFLAG_ALPHA, derived from comps[]
39     //  - sets align_x/y if 0, derived from chroma shift
40     //  - sets xs[]/ys[] always, derived from num_planes/chroma_shift
41     //  - sets MP_IMGFLAG_HAS_COMPS|MP_IMGFLAG_NE if num_planes>0
42     //  - sets MP_IMGFLAG_TYPE_UINT if no other type set
43     //  - sets id to mp_imgfmt_list[] implied format
44     struct mp_imgfmt_desc desc;
45 };
46 
47 #define FRINGE_GBRP(def, dname, b)                                          \
48     [def - IMGFMT_CUST_BASE] = {                                            \
49         .name = dname,                                                      \
50         .desc = { .flags = MP_IMGFLAG_COLOR_RGB,                            \
51                   .comps = { {2, 0, 8, (b) - 8}, {0, 0, 8, (b) - 8},        \
52                              {1, 0, 8, (b) - 8}, }, }}
53 
54 #define FLOAT_YUV(def, dname, xs, ys, a)                                    \
55     [def - IMGFMT_CUST_BASE] = {                                            \
56         .name = dname,                                                      \
57         .desc = { .flags = MP_IMGFLAG_COLOR_YUV | MP_IMGFLAG_TYPE_FLOAT,    \
58                    .chroma_xs = xs, .chroma_ys = ys,                        \
59                    .comps = { {0, 0, 32}, {1, 0, 32}, {2, 0, 32},           \
60                               {3 * (a), 0, 32 * (a)} }, }}
61 
62 static const struct mp_imgfmt_entry mp_imgfmt_list[] = {
63     // not in ffmpeg
64     [IMGFMT_VDPAU_OUTPUT - IMGFMT_CUST_BASE] = {
65         .name = "vdpau_output",
66         .desc = {
67             .flags = MP_IMGFLAG_NE | MP_IMGFLAG_RGB | MP_IMGFLAG_HWACCEL,
68         },
69     },
70     [IMGFMT_RGB30 - IMGFMT_CUST_BASE] = {
71         .name = "rgb30",
72         .desc = {
73             .flags = MP_IMGFLAG_RGB,
74             .comps = { {0, 20, 10}, {0, 10, 10}, {0, 0, 10} },
75         },
76     },
77     [IMGFMT_YAP8 - IMGFMT_CUST_BASE] = {
78         .name = "yap8",
79         .desc = {
80             .flags = MP_IMGFLAG_COLOR_YUV,
81             .comps = { {0, 0, 8}, {0}, {0}, {1, 0, 8} },
82         },
83     },
84     [IMGFMT_YAP16 - IMGFMT_CUST_BASE] = {
85         .name = "yap16",
86         .desc = {
87             .flags = MP_IMGFLAG_COLOR_YUV,
88             .comps = { {0, 0, 16}, {0}, {0}, {1, 0, 16} },
89         },
90     },
91     [IMGFMT_Y1 - IMGFMT_CUST_BASE] = {
92         .name = "y1",
93         .desc = {
94             .flags = MP_IMGFLAG_COLOR_RGB,
95             .comps = { {0, 0, 8, -7} },
96         },
97     },
98     [IMGFMT_YAPF - IMGFMT_CUST_BASE] = {
99         .name = "grayaf32", // try to mimic ffmpeg naming convention
100         .desc = {
101             .flags = MP_IMGFLAG_COLOR_YUV | MP_IMGFLAG_TYPE_FLOAT,
102             .comps = { {0, 0, 32}, {0}, {0}, {1, 0, 32} },
103         },
104     },
105     FLOAT_YUV(IMGFMT_444PF,  "yuv444pf",  0, 0, 0),
106     FLOAT_YUV(IMGFMT_444APF, "yuva444pf", 0, 0, 1),
107     FLOAT_YUV(IMGFMT_420PF,  "yuv420pf",  1, 1, 0),
108     FLOAT_YUV(IMGFMT_420APF, "yuva420pf", 1, 1, 1),
109     FLOAT_YUV(IMGFMT_422PF,  "yuv422pf",  1, 0, 0),
110     FLOAT_YUV(IMGFMT_422APF, "yuva422pf", 1, 0, 1),
111     FLOAT_YUV(IMGFMT_440PF,  "yuv440pf",  0, 1, 0),
112     FLOAT_YUV(IMGFMT_440APF, "yuva440pf", 0, 1, 1),
113     FLOAT_YUV(IMGFMT_410PF,  "yuv410pf",  2, 2, 0),
114     FLOAT_YUV(IMGFMT_410APF, "yuva410pf", 2, 2, 1),
115     FLOAT_YUV(IMGFMT_411PF,  "yuv411pf",  2, 0, 0),
116     FLOAT_YUV(IMGFMT_411APF, "yuva411pf", 2, 0, 1),
117     FRINGE_GBRP(IMGFMT_GBRP1, "gbrp1", 1),
118     FRINGE_GBRP(IMGFMT_GBRP2, "gbrp2", 2),
119     FRINGE_GBRP(IMGFMT_GBRP3, "gbrp3", 3),
120     FRINGE_GBRP(IMGFMT_GBRP4, "gbrp4", 4),
121     FRINGE_GBRP(IMGFMT_GBRP5, "gbrp5", 5),
122     FRINGE_GBRP(IMGFMT_GBRP6, "gbrp6", 6),
123     // in FFmpeg, but FFmpeg names have an annoying "_vld" suffix
124     [IMGFMT_VIDEOTOOLBOX - IMGFMT_CUST_BASE] = {
125         .name = "videotoolbox",
126     },
127     [IMGFMT_VAAPI - IMGFMT_CUST_BASE] = {
128         .name = "vaapi",
129     },
130 };
131 
get_mp_desc(int imgfmt)132 static const struct mp_imgfmt_entry *get_mp_desc(int imgfmt)
133 {
134     if (imgfmt < IMGFMT_CUST_BASE)
135         return NULL;
136     int index = imgfmt - IMGFMT_CUST_BASE;
137     if (index >= MP_ARRAY_SIZE(mp_imgfmt_list))
138         return NULL;
139     const struct mp_imgfmt_entry *e = &mp_imgfmt_list[index];
140     return e->name ? e : NULL;
141 }
142 
mp_imgfmt_name_list(void)143 char **mp_imgfmt_name_list(void)
144 {
145     int count = IMGFMT_END - IMGFMT_START;
146     char **list = talloc_zero_array(NULL, char *, count + 1);
147     int num = 0;
148     for (int n = IMGFMT_START; n < IMGFMT_END; n++) {
149         const char *name = mp_imgfmt_to_name(n);
150         if (strcmp(name, "unknown") != 0)
151             list[num++] = talloc_strdup(list, name);
152     }
153     return list;
154 }
155 
mp_imgfmt_from_name(bstr name)156 int mp_imgfmt_from_name(bstr name)
157 {
158     if (bstr_equals0(name, "none"))
159         return 0;
160     for (int n = 0; n < MP_ARRAY_SIZE(mp_imgfmt_list); n++) {
161         const struct mp_imgfmt_entry *p = &mp_imgfmt_list[n];
162         if (p->name && bstr_equals0(name, p->name))
163             return IMGFMT_CUST_BASE + n;
164     }
165     return pixfmt2imgfmt(av_get_pix_fmt(mp_tprintf(80, "%.*s", BSTR_P(name))));
166 }
167 
mp_imgfmt_to_name_buf(char * buf,size_t buf_size,int fmt)168 char *mp_imgfmt_to_name_buf(char *buf, size_t buf_size, int fmt)
169 {
170     const struct mp_imgfmt_entry *p = get_mp_desc(fmt);
171     const char *name = p ? p->name : NULL;
172     if (!name) {
173         const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(imgfmt2pixfmt(fmt));
174         if (pixdesc)
175             name = pixdesc->name;
176     }
177     if (!name)
178         name = "unknown";
179     snprintf(buf, buf_size, "%s", name);
180     int len = strlen(buf);
181     if (len > 2 && buf[len - 2] == MP_SELECT_LE_BE('l', 'b') && buf[len - 1] == 'e')
182         buf[len - 2] = '\0';
183     return buf;
184 }
185 
fill_pixdesc_layout(struct mp_imgfmt_desc * desc,enum AVPixelFormat fmt,const AVPixFmtDescriptor * pd)186 static void fill_pixdesc_layout(struct mp_imgfmt_desc *desc,
187                                 enum AVPixelFormat fmt,
188                                 const AVPixFmtDescriptor *pd)
189 {
190     if (pd->flags & AV_PIX_FMT_FLAG_PAL ||
191         pd->flags & AV_PIX_FMT_FLAG_HWACCEL)
192         goto fail;
193 
194     bool has_alpha = pd->flags & AV_PIX_FMT_FLAG_ALPHA;
195     if (pd->nb_components != 1 + has_alpha &&
196         pd->nb_components != 3 + has_alpha)
197         goto fail;
198 
199     // Very convenient: we assume we're always on little endian, and FFmpeg
200     // explicitly marks big endian formats => don't need to guess whether a
201     // format is little endian, or not affected by byte order.
202     bool is_be = pd->flags & AV_PIX_FMT_FLAG_BE;
203     bool is_ne = MP_SELECT_LE_BE(false, true) == is_be;
204 
205     // Packed sub-sampled YUV is very... special.
206     bool is_packed_ss_yuv = pd->log2_chroma_w && !pd->log2_chroma_h &&
207         pd->comp[1].plane == 0 && pd->comp[2].plane == 0 &&
208         pd->nb_components == 3;
209 
210     if (is_packed_ss_yuv)
211         desc->bpp[0] = pd->comp[1].step * 8;
212 
213     // Determine if there are any byte overlaps => relevant for determining
214     // access unit for endian, since pixdesc does not expose this, and assumes
215     // a weird model where you do separate memory fetches for each component.
216     bool any_shared_bytes = !!(pd->flags & AV_PIX_FMT_FLAG_BITSTREAM);
217     for (int c = 0; c < pd->nb_components; c++) {
218         for (int i = 0; i < c; i++) {
219             const AVComponentDescriptor *d1 = &pd->comp[c];
220             const AVComponentDescriptor *d2 = &pd->comp[i];
221             if (d1->plane == d2->plane) {
222                 if (d1->offset + (d1->depth + 7) / 8u > d2->offset &&
223                     d2->offset + (d2->depth + 7) / 8u > d1->offset)
224                     any_shared_bytes = true;
225             }
226         }
227     }
228 
229     int el_bits = (pd->flags & AV_PIX_FMT_FLAG_BITSTREAM) ? 1 : 8;
230     for (int c = 0; c < pd->nb_components; c++) {
231         const AVComponentDescriptor *d = &pd->comp[c];
232         if (d->plane >= MP_MAX_PLANES)
233             goto fail;
234 
235         desc->num_planes = MPMAX(desc->num_planes, d->plane + 1);
236 
237         int plane_bits = desc->bpp[d->plane];
238         int c_bits = d->step * el_bits;
239 
240         // The first component wins, because either all components result in
241         // the same value, or luma wins (luma always comes before chroma).
242         if (plane_bits) {
243             if (c_bits > plane_bits)
244                 goto fail; // inconsistent
245         } else {
246             desc->bpp[d->plane] = plane_bits = c_bits;
247         }
248 
249         int shift = d->shift;
250         // What the fuck: for some inexplicable reason, MONOB uses shift=7
251         // in pixdesc, which is basically out of bounds. Pixdesc bug?
252         // Make it behave like MONOW. (No, the bit-order is not different.)
253         if (fmt == AV_PIX_FMT_MONOBLACK)
254             shift = 0;
255 
256         int offset = d->offset * el_bits;
257         // The pixdesc logic for reading and endian swapping is as follows
258         // (reverse engineered from av_read_image_line2()):
259         // - determine a word size that will include the component fully;
260         //   this includes the "active" bits and the amount "shifted" away
261         //   (for example shift=7/depth=18 => 32 bit word reading [31:0])
262         // - the same format can use different word sizes (e.g. bgr565: the R
263         //   component at offset 0 is read as 8 bit; BG is read as 16 bits)
264         // - if BE flag is set, swap the word before proceeding
265         // - extract via shift and mask derived by depth
266         int word = mp_round_next_power_of_2(MPMAX(d->depth + shift, 8));
267         // The purpose of this is unknown. It's an absurdity fished out of
268         // av_read_image_line2()'s implementation. It seems technically
269         // unnecessary, and provides no information. On the other hand, it
270         // compensates for seemingly bogus packed integer pixdescs; this
271         // is "why" some formats use d->offset = -1.
272         if (is_be && el_bits == 8 && word == 8)
273             offset += 8;
274         // Pixdesc's model sometimes requires accesses with varying word-sizes,
275         // as seen in bgr565 and other formats. Also, it makes you read some
276         // formats with multiple endian-dependent accesses, where accessing a
277         // larger unit would make more sense. (Consider X2RGB10BE, for which
278         // pixdesc wants you to perform 3 * 2 byte accesses, and swap each of
279         // the read 16 bit words. What you really want is to swap the entire 4
280         // byte thing, and then extract the components with bit shifts).
281         // This is complete bullshit, so we transform it into word swaps before
282         // further processing. Care needs to be taken to not change formats like
283         // P010 or YA16 (prefer component accesses for them; P010 isn't even
284         // representable, because endian_shift is for all planes).
285         // As a heuristic, assume that if any components share a byte, the whole
286         // pixel is read as a single memory access and endian swapped at once.
287         int access_size = 8;
288         if (plane_bits > 8) {
289             if (any_shared_bytes) {
290                 access_size = plane_bits;
291                 if (is_be && word != access_size) {
292                     // Before: offset = 8*byte_offset (with word bits of data)
293                     // After: offset = bit_offset into swapped endian_size word
294                     offset = access_size - word - offset;
295                 }
296             } else {
297                 access_size = word;
298             }
299         }
300         int endian_size = (access_size && !is_ne) ? access_size : 8;
301         int endian_shift = mp_log2(endian_size) - 3;
302         if (!MP_IS_POWER_OF_2(endian_size) || endian_shift < 0 || endian_shift > 3)
303             goto fail;
304         if (desc->endian_shift && desc->endian_shift != endian_shift)
305             goto fail;
306         desc->endian_shift = endian_shift;
307 
308         // We always use bit offsets; this doesn't lose any information,
309         // and pixdesc is merely more redundant.
310         offset += shift;
311         if (offset < 0 || offset >= (1 << 6))
312             goto fail;
313         if (offset + d->depth > plane_bits)
314             goto fail;
315         if (d->depth < 0 || d->depth >= (1 << 6))
316             goto fail;
317         desc->comps[c] = (struct mp_imgfmt_comp_desc){
318             .plane = d->plane,
319             .offset = offset,
320             .size = d->depth,
321         };
322     }
323 
324     for (int p = 0; p < desc->num_planes; p++) {
325         if (!desc->bpp[p])
326             goto fail; // plane doesn't exist
327     }
328 
329     // What the fuck: this is probably a pixdesc bug, so fix it.
330     if (fmt == AV_PIX_FMT_RGB8) {
331         desc->comps[2] = (struct mp_imgfmt_comp_desc){0, 0, 2};
332         desc->comps[1] = (struct mp_imgfmt_comp_desc){0, 2, 3};
333         desc->comps[0] = (struct mp_imgfmt_comp_desc){0, 5, 3};
334     }
335 
336     // Overlap test. If any shared bits are happening, this is not a format we
337     // can represent (or it's something like Bayer: components in the same bits,
338     // but different alternating lines).
339     bool any_shared_bits = false;
340     for (int c = 0; c < pd->nb_components; c++) {
341         for (int i = 0; i < c; i++) {
342             struct mp_imgfmt_comp_desc *c1 = &desc->comps[c];
343             struct mp_imgfmt_comp_desc *c2 = &desc->comps[i];
344             if (c1->plane == c2->plane) {
345                 if (c1->offset + c1->size > c2->offset &&
346                     c2->offset + c2->size > c1->offset)
347                     any_shared_bits = true;
348             }
349         }
350     }
351 
352     if (any_shared_bits) {
353         for (int c = 0; c < pd->nb_components; c++)
354             desc->comps[c] = (struct mp_imgfmt_comp_desc){0};
355     }
356 
357     // Many important formats have padding within an access word. For example
358     // yuv420p10 has the upper 6 bit cleared to 0; P010 has the lower 6 bits
359     // cleared to 0. Pixdesc cannot represent that these bits are 0. There are
360     // other formats where padding is not guaranteed to be 0, but they are
361     // described in the same way.
362     // Apply a heuristic that is supposed to identify formats which use
363     // guaranteed 0 padding. This could fail, but nobody said this pixdesc crap
364     // is robust.
365     for (int c = 0; c < pd->nb_components; c++) {
366         struct mp_imgfmt_comp_desc *cd = &desc->comps[c];
367         // Note: rgb444 would defeat our heuristic if we checked only per comp.
368         //       also, exclude "bitstream" formats due to monow/monob
369         int fsize = MP_ALIGN_UP(cd->size, 8);
370         if (!any_shared_bytes && el_bits == 8 && fsize != cd->size &&
371             fsize - cd->size <= (1 << 3))
372         {
373             if (!(cd->offset % 8u)) {
374                 cd->pad = -(fsize - cd->size);
375                 cd->size = fsize;
376             } else if (!((cd->offset + cd->size) % 8u)) {
377                 cd->pad = fsize - cd->size;
378                 cd->size = fsize;
379                 cd->offset = MP_ALIGN_DOWN(cd->offset, 8);
380             }
381         }
382     }
383 
384     // The alpha component always has ID 4 (index 3) in our representation, so
385     // move the alpha component to there.
386     if (has_alpha && pd->nb_components < 4) {
387         desc->comps[3] = desc->comps[pd->nb_components - 1];
388         desc->comps[pd->nb_components - 1] = (struct mp_imgfmt_comp_desc){0};
389     }
390 
391     if (is_packed_ss_yuv) {
392         desc->flags |= MP_IMGFLAG_PACKED_SS_YUV;
393         desc->bpp[0] /= 1 << pd->log2_chroma_w;
394     } else if (!any_shared_bits) {
395         desc->flags |= MP_IMGFLAG_HAS_COMPS;
396     }
397 
398     return;
399 
400 fail:
401     for (int n = 0; n < 4; n++)
402         desc->comps[n] = (struct mp_imgfmt_comp_desc){0};
403     // Average bit size fallback.
404     desc->num_planes = av_pix_fmt_count_planes(fmt);
405     for (int p = 0; p < desc->num_planes; p++) {
406         int ls = av_image_get_linesize(fmt, 256, p);
407         desc->bpp[p] = ls > 0 ? ls * 8 / 256 : 0;
408     }
409 }
410 
mp_imgfmt_get_desc_from_pixdesc(int mpfmt,struct mp_imgfmt_desc * out)411 static bool mp_imgfmt_get_desc_from_pixdesc(int mpfmt, struct mp_imgfmt_desc *out)
412 {
413     enum AVPixelFormat fmt = imgfmt2pixfmt(mpfmt);
414     const AVPixFmtDescriptor *pd = av_pix_fmt_desc_get(fmt);
415     if (!pd || pd->nb_components > 4)
416         return false;
417 
418     struct mp_imgfmt_desc desc = {
419         .id = mpfmt,
420         .chroma_xs = pd->log2_chroma_w,
421         .chroma_ys = pd->log2_chroma_h,
422     };
423 
424     if (pd->flags & AV_PIX_FMT_FLAG_ALPHA)
425         desc.flags |= MP_IMGFLAG_ALPHA;
426 
427     if (pd->flags & AV_PIX_FMT_FLAG_HWACCEL)
428         desc.flags |= MP_IMGFLAG_TYPE_HW;
429 
430     // Pixdesc does not provide a flag for XYZ, so this is the best we can do.
431     if (strncmp(pd->name, "xyz", 3) == 0) {
432         desc.flags |= MP_IMGFLAG_COLOR_XYZ;
433     } else if (pd->flags & AV_PIX_FMT_FLAG_RGB) {
434         desc.flags |= MP_IMGFLAG_COLOR_RGB;
435     } else if (fmt == AV_PIX_FMT_MONOBLACK || fmt == AV_PIX_FMT_MONOWHITE) {
436         desc.flags |= MP_IMGFLAG_COLOR_RGB;
437     } else if (fmt == AV_PIX_FMT_PAL8) {
438         desc.flags |= MP_IMGFLAG_COLOR_RGB | MP_IMGFLAG_TYPE_PAL8;
439     }
440 
441     if (pd->flags & AV_PIX_FMT_FLAG_FLOAT)
442         desc.flags |= MP_IMGFLAG_TYPE_FLOAT;
443 
444     // Educated guess.
445     if (!(desc.flags & MP_IMGFLAG_COLOR_MASK) &&
446         !(desc.flags & MP_IMGFLAG_TYPE_HW))
447         desc.flags |= MP_IMGFLAG_COLOR_YUV;
448 
449     desc.align_x = 1 << desc.chroma_xs;
450     desc.align_y = 1 << desc.chroma_ys;
451 
452     fill_pixdesc_layout(&desc, fmt, pd);
453 
454     if (desc.flags & (MP_IMGFLAG_HAS_COMPS | MP_IMGFLAG_PACKED_SS_YUV)) {
455         if (!(desc.flags & MP_IMGFLAG_TYPE_MASK))
456             desc.flags |= MP_IMGFLAG_TYPE_UINT;
457     }
458 
459     if (desc.bpp[0] % 8u && (pd->flags & AV_PIX_FMT_FLAG_BITSTREAM))
460         desc.align_x = 8 / desc.bpp[0]; // expect power of 2
461 
462     // Very heuristical.
463     bool is_ne = !desc.endian_shift;
464     bool need_endian = (desc.comps[0].size % 8u && desc.bpp[0] > 8) ||
465                        desc.comps[0].size > 8;
466 
467     if (need_endian) {
468         bool is_le = MP_SELECT_LE_BE(is_ne, !is_ne);
469         desc.flags |= is_le ? MP_IMGFLAG_LE : MP_IMGFLAG_BE;
470     } else {
471         desc.flags |= MP_IMGFLAG_LE | MP_IMGFLAG_BE;
472     }
473 
474     *out = desc;
475     return true;
476 }
477 
mp_imgfmt_get_packed_yuv_locations(int imgfmt,uint8_t * luma_offsets)478 bool mp_imgfmt_get_packed_yuv_locations(int imgfmt, uint8_t *luma_offsets)
479 {
480     struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(imgfmt);
481     if (!(desc.flags & MP_IMGFLAG_PACKED_SS_YUV))
482         return false;
483 
484     assert(desc.num_planes == 1);
485 
486     // Guess at which positions the additional luma samples are. We iterate
487     // starting with the first byte, and then put a luma sample at places
488     // not covered by other luma/chroma.
489     // Pixdesc does not and can not provide this information. This heuristic
490     // may fail in certain cases. What a load of bullshit, right?
491     int lsize = desc.comps[0].size;
492     int cur_offset = 0;
493     for (int lsample = 1; lsample < (1 << desc.chroma_xs); lsample++) {
494         while (1) {
495             if (cur_offset + lsize > desc.bpp[0] * desc.align_x)
496                 return false;
497             bool free = true;
498             for (int c = 0; c < 3; c++) {
499                 struct mp_imgfmt_comp_desc *cd = &desc.comps[c];
500                 if (!cd->size)
501                     continue;
502                 if (cd->offset + cd->size > cur_offset &&
503                     cur_offset + lsize > cd->offset)
504                 {
505                     free = false;
506                     break;
507                 }
508             }
509             if (free)
510                 break;
511             cur_offset += lsize;
512         }
513         luma_offsets[lsample] = cur_offset;
514         cur_offset += lsize;
515     }
516 
517     luma_offsets[0] = desc.comps[0].offset;
518     return true;
519 }
520 
get_native_desc(int mpfmt,struct mp_imgfmt_desc * desc)521 static bool get_native_desc(int mpfmt, struct mp_imgfmt_desc *desc)
522 {
523     const struct mp_imgfmt_entry *p = get_mp_desc(mpfmt);
524     if (!p || !p->desc.flags)
525         return false;
526 
527     *desc = p->desc;
528 
529     // Fill in some fields mp_imgfmt_entry.desc is not required to set.
530 
531     desc->id = mpfmt;
532 
533     for (int n = 0; n < MP_NUM_COMPONENTS; n++) {
534         struct mp_imgfmt_comp_desc *cd = &desc->comps[n];
535         if (cd->size)
536             desc->num_planes = MPMAX(desc->num_planes, cd->plane + 1);
537         desc->bpp[cd->plane] =
538             MPMAX(desc->bpp[cd->plane], MP_ALIGN_UP(cd->offset + cd->size, 8));
539     }
540 
541     if (!desc->align_x && !desc->align_y) {
542         desc->align_x = 1 << desc->chroma_xs;
543         desc->align_y = 1 << desc->chroma_ys;
544     }
545 
546     if (desc->num_planes)
547         desc->flags |= MP_IMGFLAG_HAS_COMPS | MP_IMGFLAG_NE;
548 
549     if (!(desc->flags & MP_IMGFLAG_TYPE_MASK))
550         desc->flags |= MP_IMGFLAG_TYPE_UINT;
551 
552     return true;
553 }
554 
mp_imgfmt_desc_get_num_comps(struct mp_imgfmt_desc * desc)555 int mp_imgfmt_desc_get_num_comps(struct mp_imgfmt_desc *desc)
556 {
557     int flags = desc->flags;
558     if (!(flags & MP_IMGFLAG_COLOR_MASK))
559         return 0;
560     return 3 + (flags & MP_IMGFLAG_GRAY ? -2 : 0) + !!(flags & MP_IMGFLAG_ALPHA);
561 }
562 
mp_imgfmt_get_desc(int mpfmt)563 struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
564 {
565     struct mp_imgfmt_desc desc;
566 
567     if (!get_native_desc(mpfmt, &desc) &&
568         !mp_imgfmt_get_desc_from_pixdesc(mpfmt, &desc))
569         return (struct mp_imgfmt_desc){0};
570 
571     for (int p = 0; p < desc.num_planes; p++) {
572         desc.xs[p] = (p == 1 || p == 2) ? desc.chroma_xs : 0;
573         desc.ys[p] = (p == 1 || p == 2) ? desc.chroma_ys : 0;
574     }
575 
576     bool is_ba = desc.num_planes > 0;
577     for (int p = 0; p < desc.num_planes; p++)
578         is_ba = !(desc.bpp[p] % 8u);
579 
580     if (is_ba)
581         desc.flags |= MP_IMGFLAG_BYTE_ALIGNED;
582 
583     if (desc.flags & MP_IMGFLAG_HAS_COMPS) {
584         if (desc.comps[3].size)
585             desc.flags |= MP_IMGFLAG_ALPHA;
586 
587         // Assuming all colors are (CCC+[A]) or (C+[A]), the latter being gray.
588         if (!desc.comps[1].size)
589             desc.flags |= MP_IMGFLAG_GRAY;
590 
591         bool bb = true;
592         for (int n = 0; n < MP_NUM_COMPONENTS; n++) {
593             if (desc.comps[n].offset % 8u || desc.comps[n].size % 8u)
594                 bb = false;
595         }
596         if (bb)
597             desc.flags |= MP_IMGFLAG_BYTES;
598     }
599 
600     if ((desc.flags & (MP_IMGFLAG_YUV | MP_IMGFLAG_RGB))
601         && (desc.flags & MP_IMGFLAG_HAS_COMPS)
602         && (desc.flags & MP_IMGFLAG_BYTES)
603         && ((desc.flags & MP_IMGFLAG_TYPE_MASK) == MP_IMGFLAG_TYPE_UINT))
604     {
605         int cnt = mp_imgfmt_desc_get_num_comps(&desc);
606         bool same_depth = true;
607         for (int p = 0; p < desc.num_planes; p++)
608             same_depth &= desc.bpp[p] == desc.bpp[0];
609         if (same_depth && cnt == desc.num_planes) {
610             if (desc.flags & MP_IMGFLAG_YUV) {
611                 desc.flags |= MP_IMGFLAG_YUV_P;
612             } else {
613                 desc.flags |= MP_IMGFLAG_RGB_P;
614             }
615         }
616         if (cnt == 3 && desc.num_planes == 2 &&
617             desc.bpp[1] == desc.bpp[0] * 2 &&
618             (desc.flags & MP_IMGFLAG_YUV))
619         {
620 
621             desc.flags |= MP_IMGFLAG_YUV_NV;
622         }
623     }
624 
625     return desc;
626 }
627 
validate_regular_imgfmt(const struct mp_regular_imgfmt * fmt)628 static bool validate_regular_imgfmt(const struct mp_regular_imgfmt *fmt)
629 {
630     bool present[MP_NUM_COMPONENTS] = {0};
631     int n_comp = 0;
632 
633     for (int n = 0; n < fmt->num_planes; n++) {
634         const struct mp_regular_imgfmt_plane *plane = &fmt->planes[n];
635         n_comp += plane->num_components;
636         if (n_comp > MP_NUM_COMPONENTS)
637             return false;
638         if (!plane->num_components)
639             return false; // no empty planes in between allowed
640 
641         bool pad_only = true;
642         int chroma_luma = 0; // luma: 1, chroma: 2, both: 3
643         for (int i = 0; i < plane->num_components; i++) {
644             int comp = plane->components[i];
645             if (comp > MP_NUM_COMPONENTS)
646                 return false;
647             if (comp == 0)
648                 continue;
649             pad_only = false;
650             if (present[comp - 1])
651                 return false; // no duplicates
652             present[comp - 1] = true;
653             chroma_luma |= (comp == 2 || comp == 3) ? 2 : 1;
654         }
655         if (pad_only)
656             return false; // no planes with only padding allowed
657         if ((fmt->chroma_xs > 0 || fmt->chroma_ys > 0) && chroma_luma == 3)
658             return false; // separate chroma/luma planes required
659     }
660 
661     if (!(present[0] || present[3]) ||  // at least component 1 or alpha needed
662         (present[1] && !present[0]) ||  // component 2 requires component 1
663         (present[2] && !present[1]))    // component 3 requires component 2
664         return false;
665 
666     return true;
667 }
668 
get_forced_csp_from_flags(int flags)669 static enum mp_csp get_forced_csp_from_flags(int flags)
670 {
671     if (flags & MP_IMGFLAG_COLOR_XYZ)
672         return MP_CSP_XYZ;
673 
674     if (flags & MP_IMGFLAG_COLOR_RGB)
675         return MP_CSP_RGB;
676 
677     return MP_CSP_AUTO;
678 }
679 
mp_imgfmt_get_forced_csp(int imgfmt)680 enum mp_csp mp_imgfmt_get_forced_csp(int imgfmt)
681 {
682     return get_forced_csp_from_flags(mp_imgfmt_get_desc(imgfmt).flags);
683 }
684 
get_component_type_from_flags(int flags)685 static enum mp_component_type get_component_type_from_flags(int flags)
686 {
687     if (flags & MP_IMGFLAG_TYPE_UINT)
688         return MP_COMPONENT_TYPE_UINT;
689 
690     if (flags & MP_IMGFLAG_TYPE_FLOAT)
691         return MP_COMPONENT_TYPE_FLOAT;
692 
693     return MP_COMPONENT_TYPE_UNKNOWN;
694 }
695 
mp_imgfmt_get_component_type(int imgfmt)696 enum mp_component_type mp_imgfmt_get_component_type(int imgfmt)
697 {
698     return get_component_type_from_flags(mp_imgfmt_get_desc(imgfmt).flags);
699 }
700 
mp_find_other_endian(int imgfmt)701 int mp_find_other_endian(int imgfmt)
702 {
703     return pixfmt2imgfmt(av_pix_fmt_swap_endianness(imgfmt2pixfmt(imgfmt)));
704 }
705 
mp_get_regular_imgfmt(struct mp_regular_imgfmt * dst,int imgfmt)706 bool mp_get_regular_imgfmt(struct mp_regular_imgfmt *dst, int imgfmt)
707 {
708     struct mp_regular_imgfmt res = {0};
709 
710     struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(imgfmt);
711     if (!desc.num_planes)
712         return false;
713     res.num_planes = desc.num_planes;
714 
715     if (desc.endian_shift || !(desc.flags & MP_IMGFLAG_HAS_COMPS))
716         return false;
717 
718     res.component_type = get_component_type_from_flags(desc.flags);
719     if (!res.component_type)
720         return false;
721 
722     struct mp_imgfmt_comp_desc *comp0 = &desc.comps[0];
723     if (comp0->size < 1 || comp0->size > 64 || (comp0->size % 8u))
724         return false;
725 
726     res.component_size = comp0->size / 8u;
727     res.component_pad = comp0->pad;
728 
729     for (int n = 0; n < res.num_planes; n++) {
730         if (desc.bpp[n] % comp0->size)
731             return false;
732         res.planes[n].num_components = desc.bpp[n] / comp0->size;
733     }
734 
735     for (int n = 0; n < MP_NUM_COMPONENTS; n++) {
736         struct mp_imgfmt_comp_desc *comp = &desc.comps[n];
737         if (!comp->size)
738             continue;
739 
740         struct mp_regular_imgfmt_plane *plane = &res.planes[comp->plane];
741 
742         res.num_planes = MPMAX(res.num_planes, comp->plane + 1);
743 
744         // We support uniform depth only.
745         if (comp->size != comp0->size || comp->pad != comp0->pad)
746             return false;
747 
748         // Size-aligned only.
749         int pos = comp->offset / comp->size;
750         if (comp->offset != pos * comp->size || pos >= MP_NUM_COMPONENTS)
751             return false;
752 
753         if (plane->components[pos])
754             return false;
755         plane->components[pos] = n + 1;
756     }
757 
758     res.chroma_xs = desc.chroma_xs;
759     res.chroma_ys = desc.chroma_ys;
760 
761     res.forced_csp = get_forced_csp_from_flags(desc.flags);
762 
763     if (!validate_regular_imgfmt(&res))
764         return false;
765 
766     *dst = res;
767     return true;
768 }
769 
regular_imgfmt_equals(struct mp_regular_imgfmt * a,struct mp_regular_imgfmt * b)770 static bool regular_imgfmt_equals(struct mp_regular_imgfmt *a,
771                                   struct mp_regular_imgfmt *b)
772 {
773     if (a->component_type != b->component_type ||
774         a->component_size != b->component_size ||
775         a->num_planes     != b->num_planes ||
776         a->component_pad  != b->component_pad ||
777         a->forced_csp     != b->forced_csp ||
778         a->chroma_xs      != b->chroma_xs ||
779         a->chroma_ys      != b->chroma_ys)
780         return false;
781 
782     for (int n = 0; n < a->num_planes; n++) {
783         int num_comps = a->planes[n].num_components;
784         if (num_comps != b->planes[n].num_components)
785             return false;
786         for (int i = 0; i < num_comps; i++) {
787             if (a->planes[n].components[i] != b->planes[n].components[i])
788                 return false;
789         }
790     }
791 
792     return true;
793 }
794 
795 // Find a format that matches this one exactly.
mp_find_regular_imgfmt(struct mp_regular_imgfmt * src)796 int mp_find_regular_imgfmt(struct mp_regular_imgfmt *src)
797 {
798     for (int n = IMGFMT_START + 1; n < IMGFMT_END; n++) {
799         struct mp_regular_imgfmt f;
800         if (mp_get_regular_imgfmt(&f, n) && regular_imgfmt_equals(src, &f))
801             return n;
802     }
803     return 0;
804 }
805 
806 // Compare the dst image formats, and return the one which can carry more data
807 // (e.g. higher depth, more color components, lower chroma subsampling, etc.),
808 // with respect to what is required to keep most of the src format.
809 // Returns the imgfmt, or 0 on error.
mp_imgfmt_select_best(int dst1,int dst2,int src)810 int mp_imgfmt_select_best(int dst1, int dst2, int src)
811 {
812     enum AVPixelFormat dst1pxf = imgfmt2pixfmt(dst1);
813     enum AVPixelFormat dst2pxf = imgfmt2pixfmt(dst2);
814     enum AVPixelFormat srcpxf = imgfmt2pixfmt(src);
815     enum AVPixelFormat dstlist[] = {dst1pxf, dst2pxf, AV_PIX_FMT_NONE};
816     return pixfmt2imgfmt(avcodec_find_best_pix_fmt_of_list(dstlist, srcpxf, 1, 0));
817 }
818 
819 // Same as mp_imgfmt_select_best(), but with a list of dst formats.
mp_imgfmt_select_best_list(int * dst,int num_dst,int src)820 int mp_imgfmt_select_best_list(int *dst, int num_dst, int src)
821 {
822     int best = 0;
823     for (int n = 0; n < num_dst; n++)
824         best = best ? mp_imgfmt_select_best(best, dst[n], src) : dst[n];
825     return best;
826 }
827