diff mbox series

[FFmpeg-devel,1/4] lav/dnxhd: better support 4:2:0 in DNXHR profiles

Message ID 20210130091906.312-2-christophe.gisquet@gmail.com
State New
Headers show
Series Better colorspace support in dnxhddec
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Christophe Gisquet Jan. 30, 2021, 9:19 a.m. UTC
From: Christophe Gisquet <c.gisquet@ateme.com>

Where they are allowed. No validation of profile + colorformat is performed,
however.
---
 libavcodec/dnxhddec.c | 55 +++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c
index c78d55aee5..359588f963 100644
--- a/libavcodec/dnxhddec.c
+++ b/libavcodec/dnxhddec.c
@@ -49,6 +49,13 @@  typedef struct RowContext {
     int format;
 } RowContext;
 
+typedef enum {
+    DNX_CHROMAFORMAT_422 = 0,
+    DNX_CHROMAFORMAT_420 = 1,
+    DNX_CHROMAFORMAT_444 = 2,
+    DNX_CHROMAFORMAT_UNKNOWN = 3,
+} DNXChromaFormat;
+
 typedef struct DNXHDContext {
     AVCodecContext *avctx;
     RowContext *rows;
@@ -67,7 +74,7 @@  typedef struct DNXHDContext {
     ScanTable scantable;
     const CIDEntry *cid_table;
     int bit_depth; // 8, 10, 12 or 0 if not initialized at all.
-    int is_444;
+    int chromafmt;
     int alpha;
     int lla;
     int mbaff;
@@ -168,6 +175,7 @@  static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
                                const uint8_t *buf, int buf_size,
                                int first_field)
 {
+    static const char* cfname[4] = { "4:2:2", "4:2:0", "4:4:4", "Unknown" };
     int i, cid, ret;
     int old_bit_depth = ctx->bit_depth, bitdepth;
     uint64_t header_prefix;
@@ -234,8 +242,8 @@  static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
         av_log(ctx->avctx, AV_LOG_WARNING,
                "Adaptive color transform in an unsupported profile.\n");
 
-    ctx->is_444 = (buf[0x2C] >> 6) & 1;
-    if (ctx->is_444) {
+    ctx->chromafmt = (buf[0x2C] >> 5) & 3;
+    if (ctx->chromafmt == DNX_CHROMAFORMAT_444) {
         if (bitdepth == 8) {
             avpriv_request_sample(ctx->avctx, "4:4:4 8 bits");
             return AVERROR_INVALIDDATA;
@@ -250,16 +258,16 @@  static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
         }
     } else if (bitdepth == 12) {
         ctx->decode_dct_block = dnxhd_decode_dct_block_12;
-        ctx->pix_fmt = AV_PIX_FMT_YUV422P12;
+        ctx->pix_fmt = ctx->chromafmt == DNX_CHROMAFORMAT_420 ? AV_PIX_FMT_YUV420P12 : AV_PIX_FMT_YUV422P12;
     } else if (bitdepth == 10) {
         if (ctx->avctx->profile == FF_PROFILE_DNXHR_HQX)
             ctx->decode_dct_block = dnxhd_decode_dct_block_10_444;
         else
             ctx->decode_dct_block = dnxhd_decode_dct_block_10;
-        ctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+        ctx->pix_fmt = ctx->chromafmt == DNX_CHROMAFORMAT_420 ? AV_PIX_FMT_YUV420P10 : AV_PIX_FMT_YUV422P10;
     } else {
         ctx->decode_dct_block = dnxhd_decode_dct_block_8;
-        ctx->pix_fmt = AV_PIX_FMT_YUV422P;
+        ctx->pix_fmt = ctx->chromafmt == DNX_CHROMAFORMAT_420 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV422P;
     }
 
     ctx->avctx->bits_per_raw_sample = ctx->bit_depth = bitdepth;
@@ -292,8 +300,8 @@  static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
     if ((ctx->height + 15) >> 4 == ctx->mb_height && frame->interlaced_frame)
         ctx->height <<= 1;
 
-    av_log(ctx->avctx, AV_LOG_VERBOSE, "%dx%d, 4:%s %d bits, MBAFF=%d ACT=%d\n",
-           ctx->width, ctx->height, ctx->is_444 ? "4:4" : "2:2",
+    av_log(ctx->avctx, AV_LOG_VERBOSE, "%dx%d, %s %d bits, MBAFF=%d ACT=%d\n",
+           ctx->width, ctx->height, cfname[ctx->chromafmt],
            ctx->bit_depth, ctx->mbaff, ctx->act);
 
     // Newer format supports variable mb_scan_index sizes
@@ -360,7 +368,7 @@  static av_always_inline int dnxhd_decode_dct_block(const DNXHDContext *ctx,
 
     ctx->bdsp.clear_block(block);
 
-    if (!ctx->is_444) {
+    if (ctx->chromafmt != DNX_CHROMAFORMAT_444) {
         if (n & 2) {
             component     = 1 + (n & 1);
             scale = row->chroma_scale;
@@ -478,6 +486,9 @@  static int dnxhd_decode_dct_block_12_444(const DNXHDContext *ctx,
 static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
                                    AVFrame *frame, int x, int y)
 {
+    static const char yoff[4] = { 1, 0, 1, 0 };
+    static const char xoff[4] = { 0, 0, 1, 0 };
+    static const uint8_t num_blocks[4] = { 8, 6, 12, 0 };
     int shift1 = ctx->bit_depth >= 10;
     int dct_linesize_luma   = frame->linesize[0];
     int dct_linesize_chroma = frame->linesize[1];
@@ -516,7 +527,7 @@  static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
         row->last_qscale = qscale;
     }
 
-    for (i = 0; i < 8 + 4 * ctx->is_444; i++) {
+    for (i = 0; i < num_blocks[ctx->chromafmt]; i++) {
         if (ctx->decode_dct_block(ctx, row, i) < 0)
             return AVERROR_INVALIDDATA;
     }
@@ -526,9 +537,9 @@  static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
         dct_linesize_chroma <<= 1;
     }
 
-    dest_y = frame->data[0] + ((y * dct_linesize_luma)   << 4) + (x << (4 + shift1));
-    dest_u = frame->data[1] + ((y * dct_linesize_chroma) << 4) + (x << (3 + shift1 + ctx->is_444));
-    dest_v = frame->data[2] + ((y * dct_linesize_chroma) << 4) + (x << (3 + shift1 + ctx->is_444));
+    dest_y = frame->data[0] + ((y * dct_linesize_luma)   <<  4) + (x << (4 + shift1));
+    dest_u = frame->data[1] + ((y * dct_linesize_chroma) << (3 + yoff[ctx->chromafmt])) + (x << (3 + shift1 + xoff[ctx->chromafmt]));
+    dest_v = frame->data[2] + ((y * dct_linesize_chroma) << (3 + yoff[ctx->chromafmt])) + (x << (3 + shift1 + xoff[ctx->chromafmt]));
 
     if (frame->interlaced_frame && ctx->cur_field) {
         dest_y += frame->linesize[0];
@@ -542,7 +553,8 @@  static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
 
     dct_y_offset = interlaced_mb ? frame->linesize[0] : (dct_linesize_luma << 3);
     dct_x_offset = 8 << shift1;
-    if (!ctx->is_444) {
+    switch (ctx->chromafmt) {
+    case DNX_CHROMAFORMAT_422:
         ctx->idsp.idct_put(dest_y,                               dct_linesize_luma, row->blocks[0]);
         ctx->idsp.idct_put(dest_y + dct_x_offset,                dct_linesize_luma, row->blocks[1]);
         ctx->idsp.idct_put(dest_y + dct_y_offset,                dct_linesize_luma, row->blocks[4]);
@@ -555,7 +567,8 @@  static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
             ctx->idsp.idct_put(dest_u + dct_y_offset, dct_linesize_chroma, row->blocks[6]);
             ctx->idsp.idct_put(dest_v + dct_y_offset, dct_linesize_chroma, row->blocks[7]);
         }
-    } else {
+        break;
+    case DNX_CHROMAFORMAT_444:
         ctx->idsp.idct_put(dest_y,                               dct_linesize_luma, row->blocks[0]);
         ctx->idsp.idct_put(dest_y + dct_x_offset,                dct_linesize_luma, row->blocks[1]);
         ctx->idsp.idct_put(dest_y + dct_y_offset,                dct_linesize_luma, row->blocks[6]);
@@ -572,6 +585,18 @@  static int dnxhd_decode_macroblock(const DNXHDContext *ctx, RowContext *row,
             ctx->idsp.idct_put(dest_v + dct_y_offset,                dct_linesize_chroma, row->blocks[10]);
             ctx->idsp.idct_put(dest_v + dct_y_offset + dct_x_offset, dct_linesize_chroma, row->blocks[11]);
         }
+        break;
+    case DNX_CHROMAFORMAT_420:
+        ctx->idsp.idct_put(dest_y,                               dct_linesize_luma, row->blocks[0]);
+        ctx->idsp.idct_put(dest_y + dct_x_offset,                dct_linesize_luma, row->blocks[1]);
+        ctx->idsp.idct_put(dest_y + dct_y_offset,                dct_linesize_luma, row->blocks[4]);
+        ctx->idsp.idct_put(dest_y + dct_y_offset + dct_x_offset, dct_linesize_luma, row->blocks[5]);
+
+        if (!(ctx->avctx->flags & AV_CODEC_FLAG_GRAY)) {
+            ctx->idsp.idct_put(dest_u,                               dct_linesize_chroma, row->blocks[2]);
+            ctx->idsp.idct_put(dest_v,                               dct_linesize_chroma, row->blocks[3]);
+        }
+        break;
     }
 
     return 0;