diff options
-rw-r--r-- | test/img_format.c | 31 | ||||
-rw-r--r-- | test/ref/img_formats.txt | 158 | ||||
-rw-r--r-- | video/img_format.c | 224 | ||||
-rw-r--r-- | video/img_format.h | 108 | ||||
-rw-r--r-- | video/repack.c | 22 |
5 files changed, 265 insertions, 278 deletions
diff --git a/test/img_format.c b/test/img_format.c index 02bda18bd4..f7a7354d1a 100644 --- a/test/img_format.c +++ b/test/img_format.c @@ -110,17 +110,12 @@ static void run(struct test_ctx *ctx) fprintf(f, " [NODESC]\n"); } - struct mp_imgfmt_layout pd; - mp_imgfmt_get_layout(mpfmt, &pd); - for (int n = 0; n < d.num_planes; n++) { - fprintf(f, " %d: %dbits", n, pd.bits[n]); - if (pd.extra_w) - fprintf(f, " w=%d", pd.extra_w + 1); - if (pd.endian_bytes) - fprintf(f, " endian_bytes=%d", pd.endian_bytes); + fprintf(f, " %d: %dbits", n, d.bpp[n]); + if (d.endian_shift) + fprintf(f, " endian_bytes=%d", 1 << d.endian_shift); for (int x = 0; x < MP_NUM_COMPONENTS; x++) { - struct mp_imgfmt_comp_desc cm = pd.comps[x]; + struct mp_imgfmt_comp_desc cm = d.comps[x]; fprintf(f, " {"); if (cm.plane == n) { if (cm.size) { @@ -133,12 +128,22 @@ static void run(struct test_ctx *ctx) } } fprintf(f, "}"); + if (!(d.flags & (MP_IMGFLAG_PACKED_SS_YUV | MP_IMGFLAG_HAS_COMPS))) + { + assert(cm.size == 0); + assert(cm.offset == 0); + assert(cm.pad == 0); + } } fprintf(f, "\n"); - if (pd.extra_w) { - fprintf(f, " extra_luma_offsets=["); - for (int x = 0; x < pd.extra_w; x++) - fprintf(f, " %d", pd.extra_luma_offsets[x]); + if (d.flags & MP_IMGFLAG_PACKED_SS_YUV) { + assert(!(d.flags & MP_IMGFLAG_HAS_COMPS)); + uint8_t offsets[10]; + bool r = mp_imgfmt_get_packed_yuv_locations(mpfmt, offsets); + assert(r); + fprintf(f, " luma_offsets=["); + for (int x = 0; x < d.align_x; x++) + fprintf(f, " %d", offsets[x]); fprintf(f, "]\n"); } } diff --git a/test/ref/img_formats.txt b/test/ref/img_formats.txt index 0a4c24eba6..71bbb288ca 100644 --- a/test/ref/img_formats.txt +++ b/test/ref/img_formats.txt @@ -517,9 +517,9 @@ gbrp1: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-7 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -632,9 +632,9 @@ gbrp2: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-6 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -643,9 +643,9 @@ gbrp3: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-5 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -654,9 +654,9 @@ gbrp4: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-4 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -665,9 +665,9 @@ gbrp5: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-3 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -676,9 +676,9 @@ gbrp6: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=3, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} + 2: 8bits {} {} {} {} Regular: planes=3 compbytes=1 bitpad=-2 chroma=1x1 ctype=uint 0: {2} 1: {3} @@ -828,8 +828,8 @@ grayaf32: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=2, chroma=0:0 align=1:1 {32/[0:0] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} Regular: planes=2 compbytes=4 bitpad=0 chroma=1x1 ctype=float 0: {1} 1: {4} @@ -1190,8 +1190,8 @@ uyvy422: ctype=uint Basic desc: [ba][yuv][le][be] planes=1, chroma=1:0 align=2:1 {16/[0:0] } - 0: 32bits w=2 {8:8} {0:8} {16:8} {} - extra_luma_offsets=[ 24] + 0: 16bits {8:8} {0:8} {16:8} {} + luma_offsets=[ 8 24] AVD: name=uyvy422 chroma=1:0 flags=0x0 0: p=0 st=2 o=1 sh=0 d=8 1: p=0 st=4 o=0 sh=0 d=8 @@ -1200,8 +1200,8 @@ uyyvyy411: [GENERIC] ctype=uint Basic desc: [yuv][le][be] planes=1, chroma=2:0 align=4:1 {12/[0:0] } - 0: 48bits w=4 {8:8} {0:8} {24:8} {} - extra_luma_offsets=[ 16 32 40] + 0: 12bits {8:8} {0:8} {24:8} {} + luma_offsets=[ 8 16 32 40] AVD: name=uyyvyy411 chroma=2:0 flags=0x0 0: p=0 st=4 o=1 sh=0 d=8 1: p=0 st=6 o=0 sh=0 d=8 @@ -1269,15 +1269,15 @@ y1: fcsp=rgb ctype=uint Basic desc: [ba][rgb][le] planes=1, chroma=0:0 align=1:1 {8/[0:0] } - 0: 0bits {} {} {} {} + 0: 8bits {} {} {} {} Regular: planes=1 compbytes=1 bitpad=-7 chroma=1x1 ctype=uint 0: {1} y210: [GENERIC] ctype=uint Basic desc: [ba][yuv][le] planes=1, chroma=1:0 align=2:1 {32/[0:0] } - 0: 64bits w=2 {0:16/6} {16:16/6} {48:16/6} {} - extra_luma_offsets=[ 32] + 0: 32bits {0:16/6} {16:16/6} {48:16/6} {} + luma_offsets=[ 0 32] AVD: name=y210le chroma=1:0 flags=0x0 0: p=0 st=4 o=0 sh=6 d=10 1: p=0 st=8 o=2 sh=6 d=10 @@ -1286,8 +1286,8 @@ y210be: [GENERIC] ctype=uint Basic desc: [ba][yuv][be] planes=1, chroma=1:0 align=2:1 {32/[0:0] } - 0: 64bits w=2 endian_bytes=2 {0:16/6} {16:16/6} {48:16/6} {} - extra_luma_offsets=[ 32] + 0: 32bits endian_bytes=2 {0:16/6} {16:16/6} {48:16/6} {} + luma_offsets=[ 0 32] AVD: name=y210be chroma=1:0 flags=0x1 [be] 0: p=0 st=4 o=0 sh=6 d=10 1: p=0 st=8 o=2 sh=6 d=10 @@ -1324,8 +1324,8 @@ yap16: ctype=uint Basic desc: [ba][a][yuvp][yuv][le] planes=2, chroma=0:0 align=1:1 {16/[0:0] 16/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} + 0: 16bits {} {} {} {} + 1: 16bits {} {} {} {} Regular: planes=2 compbytes=2 bitpad=0 chroma=1x1 ctype=uint 0: {1} 1: {4} @@ -1333,8 +1333,8 @@ yap8: ctype=uint Basic desc: [ba][a][yuvp][yuv][le] planes=2, chroma=0:0 align=1:1 {8/[0:0] 8/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} + 0: 8bits {} {} {} {} + 1: 8bits {} {} {} {} Regular: planes=2 compbytes=1 bitpad=0 chroma=1x1 ctype=uint 0: {1} 1: {4} @@ -1357,9 +1357,9 @@ yuv410pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=2:2 align=4:4 {32/[0:0] 32/[2:2] 32/[2:2] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=4x4 ctype=float 0: {1} 1: {2} @@ -1383,9 +1383,9 @@ yuv411pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=2:0 align=4:1 {32/[0:0] 32/[2:0] 32/[2:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=4x1 ctype=float 0: {1} 1: {2} @@ -1540,9 +1540,9 @@ yuv420pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=1:1 align=2:2 {32/[0:0] 32/[1:1] 32/[1:1] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=2x2 ctype=float 0: {1} 1: {2} @@ -1696,9 +1696,9 @@ yuv422pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=1:0 align=2:1 {32/[0:0] 32/[1:0] 32/[1:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=2x1 ctype=float 0: {1} 1: {2} @@ -1774,9 +1774,9 @@ yuv440pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=0:1 align=1:2 {32/[0:0] 32/[0:1] 32/[0:1] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=1x2 ctype=float 0: {1} 1: {2} @@ -1931,9 +1931,9 @@ yuv444pf: ctype=float Basic desc: [ba][yuvp][yuv][le] planes=3, chroma=0:0 align=1:1 {32/[0:0] 32/[0:0] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} Regular: planes=3 compbytes=4 bitpad=0 chroma=1x1 ctype=float 0: {1} 1: {2} @@ -1942,10 +1942,10 @@ yuva410pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=2:2 align=4:4 {32/[0:0] 32/[2:2] 32/[2:2] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=4x4 ctype=float 0: {1} 1: {2} @@ -1955,10 +1955,10 @@ yuva411pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=2:0 align=4:1 {32/[0:0] 32/[2:0] 32/[2:0] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=4x1 ctype=float 0: {1} 1: {2} @@ -2079,10 +2079,10 @@ yuva420pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=1:1 align=2:2 {32/[0:0] 32/[1:1] 32/[1:1] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=2x2 ctype=float 0: {1} 1: {2} @@ -2234,10 +2234,10 @@ yuva422pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=1:0 align=2:1 {32/[0:0] 32/[1:0] 32/[1:0] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=2x1 ctype=float 0: {1} 1: {2} @@ -2247,10 +2247,10 @@ yuva440pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=0:1 align=1:2 {32/[0:0] 32/[0:1] 32/[0:1] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=1x2 ctype=float 0: {1} 1: {2} @@ -2402,10 +2402,10 @@ yuva444pf: ctype=float Basic desc: [ba][a][yuvp][yuv][le] planes=4, chroma=0:0 align=1:1 {32/[0:0] 32/[0:0] 32/[0:0] 32/[0:0] } - 0: 0bits {} {} {} {} - 1: 0bits {} {} {} {} - 2: 0bits {} {} {} {} - 3: 0bits {} {} {} {} + 0: 32bits {} {} {} {} + 1: 32bits {} {} {} {} + 2: 32bits {} {} {} {} + 3: 32bits {} {} {} {} Regular: planes=4 compbytes=4 bitpad=0 chroma=1x1 ctype=float 0: {1} 1: {2} @@ -2460,8 +2460,8 @@ yuyv422: [GENERIC] ctype=uint Basic desc: [ba][yuv][le][be] planes=1, chroma=1:0 align=2:1 {16/[0:0] } - 0: 32bits w=2 {0:8} {8:8} {24:8} {} - extra_luma_offsets=[ 16] + 0: 16bits {0:8} {8:8} {24:8} {} + luma_offsets=[ 0 16] AVD: name=yuyv422 chroma=1:0 flags=0x0 0: p=0 st=2 o=0 sh=0 d=8 1: p=0 st=4 o=1 sh=0 d=8 @@ -2470,8 +2470,8 @@ yvyu422: [GENERIC] ctype=uint Basic desc: [ba][yuv][le][be] planes=1, chroma=1:0 align=2:1 {16/[0:0] } - 0: 32bits w=2 {0:8} {24:8} {8:8} {} - extra_luma_offsets=[ 16] + 0: 16bits {0:8} {24:8} {8:8} {} + luma_offsets=[ 0 16] AVD: name=yvyu422 chroma=1:0 flags=0x0 0: p=0 st=2 o=0 sh=0 d=8 1: p=0 st=4 o=3 sh=0 d=8 diff --git a/video/img_format.c b/video/img_format.c index 6e3a78a2c6..81286796d6 100644 --- a/video/img_format.c +++ b/video/img_format.c @@ -35,8 +35,6 @@ struct mp_imgfmt_entry { struct mp_imgfmt_desc desc; // valid if reg_desc.component_size is set struct mp_regular_imgfmt reg_desc; - // valid if bits!=0 - struct mp_imgfmt_layout layout; // valid if non-0 and no reg_desc enum mp_csp forced_csp; enum mp_component_type ctype; @@ -74,13 +72,14 @@ static const struct mp_imgfmt_entry mp_imgfmt_list[] = { .desc = { .id = IMGFMT_RGB30, .avformat = AV_PIX_FMT_NONE, - .flags = MP_IMGFLAG_BYTE_ALIGNED | MP_IMGFLAG_NE | MP_IMGFLAG_RGB, + .flags = MP_IMGFLAG_BYTE_ALIGNED | MP_IMGFLAG_NE | MP_IMGFLAG_RGB | + MP_IMGFLAG_HAS_COMPS, .num_planes = 1, .align_x = 1, .align_y = 1, .bpp = {32}, + .comps = { {0, 20, 10}, {0, 10, 10}, {0, 0, 10} }, }, - .layout = { {32}, { {0, 20, 10}, {0, 10, 10}, {0, 0, 10} } }, .forced_csp = MP_CSP_RGB, .ctype = MP_COMPONENT_TYPE_UINT, }, @@ -229,23 +228,12 @@ static struct mp_imgfmt_desc to_legacy_desc(int fmt, struct mp_regular_imgfmt re return desc; } -void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) +static void fill_pixdesc_layout(struct mp_imgfmt_desc *desc, + enum AVPixelFormat fmt, + const AVPixFmtDescriptor *pd) { - const struct mp_imgfmt_entry *mpdesc = get_mp_desc(mpfmt); - if (mpdesc && mpdesc->reg_desc.component_size) { - *p_desc = (struct mp_imgfmt_layout){{0}}; - return; - } - if (mpdesc && mpdesc->layout.bits) { - *p_desc = mpdesc->layout; - return; - } - - enum AVPixelFormat fmt = imgfmt2pixfmt(mpfmt); - const AVPixFmtDescriptor *pd = av_pix_fmt_desc_get(fmt); - if (!pd || - (pd->flags & AV_PIX_FMT_FLAG_PAL) || - (pd->flags & AV_PIX_FMT_FLAG_HWACCEL)) + if (pd->flags & AV_PIX_FMT_FLAG_PAL || + pd->flags & AV_PIX_FMT_FLAG_HWACCEL) goto fail; bool has_alpha = pd->flags & AV_PIX_FMT_FLAG_ALPHA; @@ -253,8 +241,6 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) pd->nb_components != 3 + has_alpha) goto fail; - struct mp_imgfmt_layout desc = {0}; - // Very convenient: we assume we're always on little endian, and FFmpeg // explicitly marks big endian formats => don't need to guess whether a // format is little endian, or not affected by byte order. @@ -262,14 +248,11 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) // Packed sub-sampled YUV is very... special. bool is_packed_ss_yuv = pd->log2_chroma_w && !pd->log2_chroma_h && - (1 << pd->log2_chroma_w) <= MP_ARRAY_SIZE(desc.extra_luma_offsets) + 1 && pd->comp[1].plane == 0 && pd->comp[2].plane == 0 && pd->nb_components == 3; - if (is_packed_ss_yuv) { - desc.extra_w = (1 << pd->log2_chroma_w) - 1; - desc.bits[0] = pd->comp[1].step * 8; - } + if (is_packed_ss_yuv) + desc->bpp[0] = pd->comp[1].step * 8; int num_planes = 0; int el_bits = (pd->flags & AV_PIX_FMT_FLAG_BITSTREAM) ? 1 : 8; @@ -280,7 +263,7 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) num_planes = MPMAX(num_planes, d->plane + 1); - int plane_bits = desc.bits[d->plane]; + int plane_bits = desc->bpp[d->plane]; int c_bits = d->step * el_bits; // The first component wins, because either all components result in @@ -289,7 +272,7 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) if (c_bits > plane_bits) goto fail; // inconsistent } else { - desc.bits[d->plane] = plane_bits = c_bits; + desc->bpp[d->plane] = plane_bits = c_bits; } int shift = d->shift; @@ -323,21 +306,24 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) if (is_be && word == 1) { // Probably packed RGB formats with varying word sizes. Assume // the word access size is the entire pixel. - if (plane_bits % 8 || plane_bits >= 64) + int logend = mp_log2(plane_bits) - 3; + if (!MP_IS_POWER_OF_2(plane_bits) || logend < 0 || logend > 3) goto fail; - if (!desc.endian_bytes) - desc.endian_bytes = plane_bits / 8; - if (desc.endian_bytes != plane_bits / 8) + if (!desc->endian_shift) + desc->endian_shift = logend; + if (desc->endian_shift != logend) goto fail; - offset = desc.endian_bytes * 8 - 8 - offset; + offset = (1 << desc->endian_shift) * 8 - 8 - offset; } if (is_be && word > 1) { - if (desc.endian_bytes && desc.endian_bytes != word) + int logend = mp_log2(word); + if (desc->endian_shift && desc->endian_shift != logend) goto fail; // fortunately not needed/never happens - if (word >= 64) + if (logend > 3) goto fail; - desc.endian_bytes = word; + desc->endian_shift = logend; } + // We always use bit offsets; this doesn't lose any information, // and pixdesc is merely more redundant. offset += shift; @@ -347,7 +333,7 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) goto fail; if (d->depth < 0 || d->depth >= (1 << 6)) goto fail; - desc.comps[c] = (struct mp_imgfmt_comp_desc){ + desc->comps[c] = (struct mp_imgfmt_comp_desc){ .plane = d->plane, .offset = offset, .size = d->depth, @@ -355,15 +341,15 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) } for (int p = 0; p < num_planes; p++) { - if (!desc.bits[p]) + if (!desc->bpp[p]) goto fail; // plane doesn't exist } // What the fuck: this is probably a pixdesc bug, so fix it. if (fmt == AV_PIX_FMT_RGB8) { - desc.comps[2] = (struct mp_imgfmt_comp_desc){0, 0, 2}; - desc.comps[1] = (struct mp_imgfmt_comp_desc){0, 2, 3}; - desc.comps[0] = (struct mp_imgfmt_comp_desc){0, 5, 3}; + desc->comps[2] = (struct mp_imgfmt_comp_desc){0, 0, 2}; + desc->comps[1] = (struct mp_imgfmt_comp_desc){0, 2, 3}; + desc->comps[0] = (struct mp_imgfmt_comp_desc){0, 5, 3}; } // Overlap test. If any shared bits are happening, this is not a format we @@ -373,8 +359,8 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) bool any_shared_bytes = false; for (int c = 0; c < pd->nb_components; c++) { for (int i = 0; i < c; i++) { - struct mp_imgfmt_comp_desc *c1 = &desc.comps[c]; - struct mp_imgfmt_comp_desc *c2 = &desc.comps[i]; + struct mp_imgfmt_comp_desc *c1 = &desc->comps[c]; + struct mp_imgfmt_comp_desc *c2 = &desc->comps[i]; if (c1->plane == c2->plane) { if (c1->offset + c1->size > c2->offset && c2->offset + c2->size > c1->offset) @@ -388,7 +374,7 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) if (any_shared_bits) { for (int c = 0; c < pd->nb_components; c++) - desc.comps[c] = (struct mp_imgfmt_comp_desc){0}; + desc->comps[c] = (struct mp_imgfmt_comp_desc){0}; } // Many important formats have padding within an access word. For example @@ -400,7 +386,7 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) // guaranteed 0 padding. This could fail, but nobody said this pixdesc crap // is robust. for (int c = 0; c < pd->nb_components; c++) { - struct mp_imgfmt_comp_desc *cd = &desc.comps[c]; + struct mp_imgfmt_comp_desc *cd = &desc->comps[c]; // Note: rgb444 would defeat our heuristic if we checked only per comp. // also, exclude "bitstream" formats due to monow/monob int fsize = MP_ALIGN_UP(cd->size, 8); @@ -418,59 +404,30 @@ void mp_imgfmt_get_layout(int mpfmt, struct mp_imgfmt_layout *p_desc) } } - if (is_packed_ss_yuv) { - if (num_planes > 1) - goto fail; - // Guess at which positions the additional luma samples are. We iterate - // starting with the first byte, and then put a luma sample at places - // not covered by other luma/chroma. - // Pixdesc does not and can not provide this information. This heuristic - // may fail in certain cases. What a load of bullshit, right? - int lsize = desc.comps[0].size; - int cur_offset = 0; - for (int lsample = 1; lsample < (1 << pd->log2_chroma_w); lsample++) { - while (1) { - if (cur_offset + lsize > desc.bits[0]) - goto fail; - bool free = true; - for (int c = 0; c < pd->nb_components; c++) { - struct mp_imgfmt_comp_desc *cd = &desc.comps[c]; - if (!cd->size) - continue; - if (cd->offset + cd->size > cur_offset && - cur_offset + lsize > cd->offset) - { - free = false; - break; - } - } - if (free) - break; - cur_offset += lsize; - } - desc.extra_luma_offsets[lsample - 1] = cur_offset; - cur_offset += lsize; - } - } - // The alpha component always has ID 4 (index 3) in our representation, so // move the alpha component to there. if (has_alpha && pd->nb_components < 4) { - desc.comps[3] = desc.comps[pd->nb_components - 1]; - desc.comps[pd->nb_components - 1] = (struct mp_imgfmt_comp_desc){0}; + desc->comps[3] = desc->comps[pd->nb_components - 1]; + desc->comps[pd->nb_components - 1] = (struct mp_imgfmt_comp_desc){0}; + } + + if (is_packed_ss_yuv) { + desc->flags |= MP_IMGFLAG_PACKED_SS_YUV; + desc->bpp[0] /= 1 << pd->log2_chroma_w; + } else { + desc->flags |= MP_IMGFLAG_HAS_COMPS; } - *p_desc = desc; return; fail: - *p_desc = (struct mp_imgfmt_layout){{0}}; + for (int n = 0; n < 4; n++) + desc->comps[n] = (struct mp_imgfmt_comp_desc){0}; // Average bit size fallback. int num_av_planes = av_pix_fmt_count_planes(fmt); for (int p = 0; p < num_av_planes; p++) { int ls = av_image_get_linesize(fmt, 256, p); - if (ls > 0) - p_desc->bits[p] = ls * 8 / 256; + desc->bpp[p] = ls > 0 ? ls * 8 / 256 : 0; } } @@ -498,22 +455,30 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) for (int c = 0; c < pd->nb_components; c++) desc.num_planes = MPMAX(desc.num_planes, pd->comp[c].plane + 1); - struct mp_imgfmt_layout layout; - mp_imgfmt_get_layout(mpfmt, &layout); + for (int p = 0; p < desc.num_planes; p++) { + desc.xs[p] = (p == 1 || p == 2) ? desc.chroma_xs : 0; + desc.ys[p] = (p == 1 || p == 2) ? desc.chroma_ys : 0; + } + + desc.align_x = 1 << desc.chroma_xs; + desc.align_y = 1 << desc.chroma_ys; + + fill_pixdesc_layout(&desc, fmt, pd); + + if (desc.bpp[0] % 8u && (pd->flags & AV_PIX_FMT_FLAG_BITSTREAM)) + desc.align_x = 8 / desc.bpp[0]; // expect power of 2 bool is_ba = desc.num_planes > 0; - for (int p = 0; p < desc.num_planes; p++) { - desc.bpp[p] = layout.bits[p] / (layout.extra_w + 1); + for (int p = 0; p < desc.num_planes; p++) is_ba = !(desc.bpp[p] % 8u); - } if (is_ba) desc.flags |= MP_IMGFLAG_BYTE_ALIGNED; // Very heuristical. - bool is_be = layout.endian_bytes > 0; - bool need_endian = (layout.comps[0].size % 8u && layout.bits[0] > 8) || - layout.comps[0].size > 8; + bool is_be = desc.endian_shift > 0; + bool need_endian = (desc.comps[0].size % 8u && desc.bpp[0] > 8) || + desc.comps[0].size > 8; if (need_endian) { desc.flags |= is_be ? MP_IMGFLAG_BE : MP_IMGFLAG_LE; @@ -545,10 +510,8 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) && is_uint) { bool same_depth = true; - for (int p = 0; p < desc.num_planes; p++) { - same_depth &= layout.bits[p] == layout.bits[0] && - desc.bpp[p] == desc.bpp[0]; - } + for (int p = 0; p < desc.num_planes; p++) + same_depth &= desc.bpp[p] == desc.bpp[0]; if (same_depth && pd->nb_components == desc.num_planes) { if (desc.flags & MP_IMGFLAG_YUV) { desc.flags |= MP_IMGFLAG_YUV_P; @@ -565,18 +528,50 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) } } - for (int p = 0; p < desc.num_planes; p++) { - desc.xs[p] = (p == 1 || p == 2) ? desc.chroma_xs : 0; - desc.ys[p] = (p == 1 || p == 2) ? desc.chroma_ys : 0; - } + return desc; +} - desc.align_x = 1 << desc.chroma_xs; - desc.align_y = 1 << desc.chroma_ys; +bool mp_imgfmt_get_packed_yuv_locations(int imgfmt, uint8_t *luma_offsets) +{ + struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(imgfmt); + if (!(desc.flags & MP_IMGFLAG_PACKED_SS_YUV)) + return false; - if ((desc.bpp[0] * (layout.extra_w + 1) % 8) != 0) - desc.align_x = 8 / desc.bpp[0]; // expect power of 2 + assert(desc.num_planes == 1); + + // Guess at which positions the additional luma samples are. We iterate + // starting with the first byte, and then put a luma sample at places + // not covered by other luma/chroma. + // Pixdesc does not and can not provide this information. This heuristic + // may fail in certain cases. What a load of bullshit, right? + int lsize = desc.comps[0].size; + int cur_offset = 0; + for (int lsample = 1; lsample < (1 << desc.chroma_xs); lsample++) { + while (1) { + if (cur_offset + lsize > desc.bpp[0] * desc.align_x) + return false; + bool free = true; + for (int c = 0; c < 3; c++) { + struct mp_imgfmt_comp_desc *cd = &desc.comps[c]; + if (!cd->size) + continue; + if (cd->offset + cd->size > cur_offset && + cur_offset + lsize > cd->offset) + { + free = false; + break; + } + } + if (free) + break; + cur_offset += lsize; + } + luma_offsets[lsample] = cur_offset; + cur_offset += lsize; + } - return desc; + luma_offsets[0] = desc.comps[0].offset; + return true; } static bool validate_regular_imgfmt(const struct mp_regular_imgfmt *fmt) @@ -689,17 +684,14 @@ bool mp_get_regular_imgfmt(struct mp_regular_imgfmt *dst, int imgfmt) return false; res.num_planes = desc.num_planes; - struct mp_imgfmt_layout layout; - mp_imgfmt_get_layout(imgfmt, &layout); - - if (layout.endian_bytes || layout.extra_w) + if (desc.endian_shift || !(desc.flags & MP_IMGFLAG_HAS_COMPS)) return false; res.component_type = mp_imgfmt_get_component_type(imgfmt); if (!res.component_type) return false; - struct mp_imgfmt_comp_desc *comp0 = &layout.comps[0]; + struct mp_imgfmt_comp_desc *comp0 = &desc.comps[0]; if (comp0->size < 1 || comp0->size > 64 || (comp0->size % 8u)) return false; @@ -707,13 +699,13 @@ bool mp_get_regular_imgfmt(struct mp_regular_imgfmt *dst, int imgfmt) res.component_pad = comp0->pad; for (int n = 0; n < res.num_planes; n++) { - if (layout.bits[n] % comp0->size) + if (desc.bpp[n] % comp0->size) return false; - res.planes[n].num_components = layout.bits[n] / comp0->size; + res.planes[n].num_components = desc.bpp[n] / comp0->size; } for (int n = 0; n < MP_NUM_COMPONENTS; n++) { - struct mp_imgfmt_comp_desc *comp = &layout.comps[n]; + struct mp_imgfmt_comp_desc *comp = &desc.comps[n]; if (!comp->size) continue; diff --git a/video/img_format.h b/video/img_format.h index 712937292e..92e1716ca9 100644 --- a/video/img_format.h +++ b/video/img_format.h @@ -34,6 +34,10 @@ // All pixels start in byte boundaries #define MP_IMGFLAG_BYTE_ALIGNED 0x1 +// mp_imgfmt_desc.comps[] is set to useful values. Some types of formats will +// use comps[], but not set this flag, because it doesn't cover all requirements +// (for example MP_IMGFLAG_PACKED_SS_YUV). +#define MP_IMGFLAG_HAS_COMPS (1 << 1) // set if (possibly) alpha is included (might be not definitive for packed RGB) #define MP_IMGFLAG_ALPHA 0x80 // set if it's YUV colorspace @@ -63,6 +67,30 @@ // Semi-planar YUV formats, like AV_PIX_FMT_NV12. #define MP_IMGFLAG_YUV_NV 0x80000 +// Packed, sub-sampled YUV format. Does not apply to packed non-subsampled YUV. +// These formats pack multiple pixels into one sample with strange organization. +// In this specific case, mp_imgfmt_desc.align_x gives the size of a "full" +// pixel, which has align_x luma samples, and 1 chroma sample of each Cb and Cr. +// mp_imgfmt_desc.comps describes the chroma samples, and the first luma sample. +// All luma samples have the same configuration as the first one, and you can +// get their offsets with mp_imgfmt_get_packed_yuv_locations(). Note that the +// component offsets can be >= bpp[0]; the actual range is bpp[0]*align_x. +// These formats have no alpha. +#define MP_IMGFLAG_PACKED_SS_YUV (1 << 20) + +#define MP_NUM_COMPONENTS 4 + +struct mp_imgfmt_comp_desc { + // Plane on which this component is. + uint8_t plane; + // Bit offset of first sample, from start of the pixel group (little endian). + uint8_t offset : 6; + // Number of bits used by each sample. + uint8_t size : 6; + // Internal padding. See mp_regular_imgfmt.component_pad. + int8_t pad : 4; +}; + struct mp_imgfmt_desc { int id; // IMGFMT_* int avformat; // AV_PIX_FMT_* (or AV_PIX_FMT_NONE) @@ -80,10 +108,31 @@ struct mp_imgfmt_desc { // addition to chroma, and thus is not sub-sampled (uses align_x=2 instead). int8_t xs[MP_MAX_PLANES]; int8_t ys[MP_MAX_PLANES]; + + // Description for each component. Generally valid only if flags has + // MP_IMGFLAG_HAS_COMPS set. + // This is indexed by component_type-1 (so 0=R, 1=G, etc.), see + // mp_regular_imgfmt_plane.components[x] for component_type. Components not + // present, or which have an unknown layout, use size=0. Bits not covered by + // any component are random and not interpreted by any software. + // In particular, don't make the mistake to index this by plane. + struct mp_imgfmt_comp_desc comps[MP_NUM_COMPONENTS]; + + // log(2) of the word size in bytes for endian swapping that needs to be + // performed for converting to native endian. This is performed before any + // other unpacking steps, and for all data covered by bits. + // Always 0 if IMGFLAG_NE is set. + uint8_t endian_shift : 2; }; struct mp_imgfmt_desc mp_imgfmt_get_desc(int imgfmt); +// For MP_IMGFLAG_PACKED_SS_YUV formats (packed sub-sampled YUV): positions of +// further luma samples. luma_offsets must be an array of align_x size, and the +// function will return the offset (like in mp_imgfmt_comp_desc.offset) of each +// luma pixel. luma_offsets[0] == mp_imgfmt_desc.comps[0].offset. +bool mp_imgfmt_get_packed_yuv_locations(int imgfmt, uint8_t *luma_offsets); + // MP_CSP_AUTO for YUV, MP_CSP_RGB or MP_CSP_XYZ otherwise. // (Because IMGFMT/AV_PIX_FMT conflate format and csp for RGB and XYZ.) enum mp_csp mp_imgfmt_get_forced_csp(int imgfmt); @@ -96,8 +145,6 @@ enum mp_component_type { enum mp_component_type mp_imgfmt_get_component_type(int imgfmt); -#define MP_NUM_COMPONENTS 4 - struct mp_regular_imgfmt_plane { uint8_t num_components; // 1 is red/luminance/gray, 2 is green/Cb, 3 is blue/Cr, 4 is alpha. @@ -141,63 +188,6 @@ struct mp_regular_imgfmt { bool mp_get_regular_imgfmt(struct mp_regular_imgfmt *dst, int imgfmt); int mp_find_regular_imgfmt(struct mp_regular_imgfmt *src); -struct mp_imgfmt_comp_desc { - // Plane on which this component is. - uint8_t plane; - // Bit offset of first sample, from start of the pixel group (little endian). - uint8_t offset : 6; - // Number of bits used by each sample. - uint8_t size : 6; - // Internal padding. See mp_regular_imgfmt.component_pad. - int8_t pad |