[FFmpeg-devel] [PATCH 2/2] avcodec/dnxuc_parser: rework DNXUC parser

Marton Balint cus at passwd.hu
Tue Nov 19 23:47:31 EET 2024


The current parser does things which a parser should not, like skipping parts
of the packet header, but it does not actually able to packetize a raw DNXUC
bitstream.

Rework the parser logic to work similar to other parsers and be able to
correctly packetize raw DNXUC bitstreams.

Signed-off-by: Marton Balint <cus at passwd.hu>
---
 libavcodec/dnxuc_parser.c | 122 ++++++++++++++------------------------
 1 file changed, 44 insertions(+), 78 deletions(-)

diff --git a/libavcodec/dnxuc_parser.c b/libavcodec/dnxuc_parser.c
index 12472c7a2d..14f19efe67 100644
--- a/libavcodec/dnxuc_parser.c
+++ b/libavcodec/dnxuc_parser.c
@@ -20,99 +20,65 @@
  */
 
 /*
- This parser for DNxUncompressed video data is mostly based on
- reverse engineering of output generated by DaVinci Resolve 19
- but was later also checked against the SMPTE RDD 50 specification.
-
- Limitations: Multiple image planes are not supported.
-*/
+ * This parser for DNxUncompressed video data is mostly based on the public
+ * SMPTE RDD 50:2019 specification.
+ */
 
-#include "avcodec.h"
-#include "libavutil/intreadwrite.h"
+#include "parser.h"
+#include "libavutil/bswap.h"
 
 typedef struct DNxUcParseContext {
-    uint32_t fourcc_tag;
-    uint32_t width;
-    uint32_t height;
-    uint32_t nr_bytes;
+    ParseContext pc;
+    uint32_t remaining;
 } DNxUcParseContext;
 
-/*
-DNxUncompressed frame data comes wrapped in nested boxes of metadata
-(box structure: len + fourcc marker + data):
-
-[0-4]   len of outer essence unit box (typically 37 bytes of header + frame data)
-[4-7]   fourcc 'pack'
-
-[8-11]  len of "signal info box" (always 21)
-[12-15] fourcc 'sinf'
-[16-19] frame width / line packing size
-[20-23] frame hight / nr of lines
-[24-27] fourcc pixel format indicator
-[28]    frame_layout (0: progressive, 1: interlaced)
-
-[29-32] len of "signal data box" (nr of frame data bytes + 8)
-[33-36] fourcc 'sdat'
-[37-..] frame data
-
-A sequence of 'signal info'+'signal data' box pairs wrapped in
-'icmp'(=image component) boxes can be utilized to compose more
-complex multi plane images.
-This feature is only partially supported in the present implementation.
-We never pick more than the first pair of info and image data enclosed
-in this way.
-*/
-
 static int dnxuc_parse(AVCodecParserContext *s,
                     AVCodecContext *avctx,
                     const uint8_t **poutbuf, int *poutbuf_size,
                     const uint8_t *buf, int buf_size)
 {
-    const int HEADER_SIZE = 37;
-    int icmp_offset = 0;
-
-    DNxUcParseContext *pc;
-    pc = (DNxUcParseContext *) s->priv_data;
-
-    if (!buf_size) {
-        return 0;
-    }
-    if (buf_size > 16 && MKTAG('i','c','m','p') == AV_RL32(buf+12)){
-        icmp_offset += 8;
-    }
-    if ( buf_size < 37 + icmp_offset /* check metadata structure expectations */
-        || MKTAG('p','a','c','k') != AV_RL32(buf+4+icmp_offset)
-        || MKTAG('s','i','n','f') != AV_RL32(buf+12+icmp_offset)
-        || MKTAG('s','d','a','t') != AV_RL32(buf+33+icmp_offset)){
-            av_log(avctx, AV_LOG_ERROR, "can't read DNxUncompressed metadata.\n");
+    DNxUcParseContext *ipc = s->priv_data;
+    int next = END_NOT_FOUND;
+
+    s->pict_type = AV_PICTURE_TYPE_NONE;
+
+    *poutbuf_size = 0;
+    *poutbuf = NULL;
+
+    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+        next = buf_size;
+    } else {
+        if (ipc->remaining == 0) {
+            uint64_t state = ipc->pc.state64;
+            for (int i = 0; i < buf_size; i++) {
+                state = (state << 8) | buf[i];
+                if (ipc->pc.index + i >= 7 && (uint32_t)state == MKBETAG('p','a','c','k')) {
+                    uint32_t size = av_bswap32(state >> 32);
+                    if (size >= 8) {
+                         next = i - 7;
+                         ipc->remaining = size + FFMIN(next, 0);
+                         break;
+                    }
+                }
+            }
+            ipc->pc.state64 = state;
+        } else if (ipc->remaining <= buf_size) {
+            next = ipc->remaining;
+            ipc->remaining = 0;
+        } else {
+            ipc->remaining -= buf_size;
+        }
+        if (ff_combine_frame(&ipc->pc, next, &buf, &buf_size) < 0) {
+            *poutbuf = NULL;
             *poutbuf_size = 0;
             return buf_size;
+        }
     }
 
-    pc->fourcc_tag = AV_RL32(buf+24+icmp_offset);
-    pc->width = AV_RL32(buf+16+icmp_offset);
-    pc->height = AV_RL32(buf+20+icmp_offset);
-    pc->nr_bytes = AV_RL32(buf+29+icmp_offset) - 8;
-
-    if (!avctx->codec_tag) {
-        av_log(avctx, AV_LOG_INFO, "dnxuc_parser: '%s' %dx%d %dbpp %d\n",
-            av_fourcc2str(pc->fourcc_tag),
-            pc->width, pc->height,
-            (pc->nr_bytes*8)/(pc->width*pc->height),
-            pc->nr_bytes);
-        avctx->codec_tag = pc->fourcc_tag;
-    }
-
-    if (pc->nr_bytes > buf_size - HEADER_SIZE + icmp_offset){
-        av_log(avctx, AV_LOG_ERROR, "Insufficient size of image essence data.\n");
-        *poutbuf_size = 0;
-        return buf_size;
-    }
-
-    *poutbuf = buf + HEADER_SIZE + icmp_offset;
-    *poutbuf_size = pc->nr_bytes;
+    *poutbuf      = buf;
+    *poutbuf_size = buf_size;
 
-    return buf_size;
+    return next;
 }
 
 const AVCodecParser ff_dnxuc_parser = {
-- 
2.43.0



More information about the ffmpeg-devel mailing list