[FFmpeg-devel] [PATCH 1/2] Implementation of DNxUncompressed decoder

Martin Schitter ms+git at mur.at
Mon Aug 26 22:07:33 EEST 2024


This version doesn't only fix the trivial platform specific _Float16 issue and some
cosmetic cleanup but also corrects a few bitpack alignment issues affecting the
10 and 12bit decoders of my first patch...

---
 Changelog                 |   1 +
 doc/general_contents.texi |   1 +
 libavcodec/Makefile       |   1 +
 libavcodec/allcodecs.c    |   1 +
 libavcodec/codec_desc.c   |   7 +
 libavcodec/codec_id.h     |   1 +
 libavcodec/dnxucdec.c     | 470 ++++++++++++++++++++++++++++++++++++++
 libavcodec/parsers.c      |   1 +
 libavcodec/version.c      |   2 +-
 libavcodec/version.h      |   2 +-
 libavformat/mxf.c         |   1 +
 libavformat/mxfdec.c      |  21 ++
 12 files changed, 507 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/dnxucdec.c

diff --git a/Changelog b/Changelog
index 571b27a..8f2e418 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,7 @@ version <next>:
 - D3D12VA HEVC encoder
 - Cropping metadata parsing and writing in Matroska and MP4/MOV de/muxers
 - Intel QSV-accelerated VVC decoding
+- DNxUncompressed (SMPTE RDD 50) decoder
 
 
 version 7.0:
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index e7cf4f8..1bd696b 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -619,6 +619,7 @@ library:
 @item raw DFPWM                 @tab X @tab X
 @item raw Dirac                 @tab X @tab X
 @item raw DNxHD                 @tab X @tab X
+ at itme raw DNxUncompressed       @rab   @tab X
 @item raw DTS                   @tab X @tab X
 @item raw DTS-HD                @tab   @tab X
 @item raw E-AC-3                @tab X @tab X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 262d0a3..917ce35 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -321,6 +321,7 @@ OBJS-$(CONFIG_DFPWM_DECODER)           += dfpwmdec.o
 OBJS-$(CONFIG_DFPWM_ENCODER)           += dfpwmenc.o
 OBJS-$(CONFIG_DNXHD_DECODER)           += dnxhddec.o dnxhddata.o
 OBJS-$(CONFIG_DNXHD_ENCODER)           += dnxhdenc.o dnxhddata.o
+OBJS-$(CONFIG_DNXUC_DECODER)           += dnxucdec.o
 OBJS-$(CONFIG_DOLBY_E_DECODER)         += dolby_e.o dolby_e_parse.o kbdwin.o
 OBJS-$(CONFIG_DPX_DECODER)             += dpx.o
 OBJS-$(CONFIG_DPX_ENCODER)             += dpxenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 09385be..ce95835 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -93,6 +93,7 @@ extern const FFCodec ff_dfa_decoder;
 extern const FFCodec ff_dirac_decoder;
 extern const FFCodec ff_dnxhd_encoder;
 extern const FFCodec ff_dnxhd_decoder;
+extern const FFCodec ff_dnxuc_decoder;
 extern const FFCodec ff_dpx_encoder;
 extern const FFCodec ff_dpx_decoder;
 extern const FFCodec ff_dsicinvideo_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index a28ef68..2b83ea2 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1952,6 +1952,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("vMix Video"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_DNXUC,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "dnxuc",
+        .long_name = NULL_IF_CONFIG_SMALL("DNxUncompressed / SMPTE RDD 50"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+    },
     {
         .id        = AV_CODEC_ID_LEAD,
         .type      = AVMEDIA_TYPE_VIDEO,
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 0ab1e34..27b229b 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -321,6 +321,7 @@ enum AVCodecID {
     AV_CODEC_ID_EVC,
     AV_CODEC_ID_RTV1,
     AV_CODEC_ID_VMIX,
+    AV_CODEC_ID_DNXUC,
     AV_CODEC_ID_LEAD,
 
     /* various PCM "codecs" */
diff --git a/libavcodec/dnxucdec.c b/libavcodec/dnxucdec.c
new file mode 100644
index 0000000..de9e06f
--- /dev/null
+++ b/libavcodec/dnxucdec.c
@@ -0,0 +1,470 @@
+/*
+ * Avid DNxUncomressed / SMPTE RDD 50 demuxer
+ * Copyright (c) 2024 Martin Schitter
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ This partial implementation of a decoder for DNxUncompressed video data
+ is based on reverse engineering of output generated by DaVinci Resolve 19
+ because the SMPTE RDD 50 specification is unfortunately not freely accessible.
+
+ It's therefor limited by the present export capabilities of Resolve (YUV444
+ variants, YUV422 16bit, and alpha support is missing). But also some ffmpeg
+ shortcomings are affecting the range of available formats (no YUV half and
+ float pixel formats and filters are provided by ffmpeg until now and RGB half
+ content always requires an alpha plane).
+ 
+ A wide range of DNxUncompressed formats are nevertheless already supported:
+
+  - YUV 4:2:2 8-/10-/12-bit
+  - RGB 8-/10-/12-bit/half/float
+
+*/
+
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "libavutil/imgutils.h"
+#include "thread.h"
+
+
+typedef struct DNxUcParseContext {
+    uint32_t fourcc_tag;
+    uint32_t width;
+    uint32_t height;
+    uint32_t nr_bytes;
+} DNxUcParseContext;
+
+/* 
+DNxUncompressed frame data comes wrapped in simple metadata
+and fourcc markers:
+
+[0-4]   number of raw data (37 bytes header + frame data)
+[4-7]   fourcc 'pack'
+[8-11]  unknown value (allways: 0x15)
+[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]    unknown value (alpha?)
+[29-32] nr of bytes in frame data + 8
+[33-36] fourcc 'sdat'
+[37-..] frame data
+ */
+
+static int dnxuc_parse(AVCodecParserContext *s,
+                    AVCodecContext *avctx,
+                    const uint8_t **poutbuf, int *poutbuf_size,
+                    const uint8_t *buf, int buf_size){
+
+    char fourcc_buf[5];
+    const int HEADER_SIZE = 37;
+
+    DNxUcParseContext *pc;
+    pc = (DNxUcParseContext *) s->priv_data;
+
+    if (!buf_size) {
+        return 0;
+    } else if ( buf_size < 37 /* check metadata structure expectations */
+        || MKTAG('p','a','c','k') != *(uint32_t*) (buf+4)
+        || MKTAG('s','i','n','f') != *(uint32_t*) (buf+12)
+        || MKTAG('s','d','a','t') != *(uint32_t*) (buf+33)){
+            av_log(0, AV_LOG_ERROR, "can't read DNxUncompressed metadata.\n");
+            *poutbuf_size = 0;
+            return buf_size;
+    }
+
+    pc->fourcc_tag = *(uint32_t*)(buf+24);
+    pc->width =  *(uint32_t*)(buf+16);
+    pc->height =  *(uint32_t*)(buf+20);
+    pc->nr_bytes = *(uint32_t*)(buf+29) - 8;
+
+    if (!avctx->codec_tag) {
+        av_fourcc_make_string(fourcc_buf, pc->fourcc_tag);
+        av_log(0, AV_LOG_INFO, "dnxuc_parser: '%s' %dx%d %dbpp %d\n", 
+            fourcc_buf, 
+            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){
+        av_log(avctx, AV_LOG_ERROR, "Insufficient size of data.\n");
+        *poutbuf_size = 0;
+        return buf_size;
+    }
+
+    *poutbuf = buf + HEADER_SIZE;
+    *poutbuf_size = pc->nr_bytes;
+
+    return buf_size;
+}
+
+static av_cold int dnxuc_decode_init(AVCodecContext *avctx){
+    return 0;
+}
+
+
+static int pass_though(AVCodecContext *avctx, AVFrame *frame, const AVPacket *avpkt){
+
+    /* there is no need to copy as the data already match
+     * a known pixel format */
+
+    frame->buf[0] = av_buffer_ref(avpkt->buf);
+
+    if (!frame->buf[0]) {
+        return AVERROR(ENOMEM);
+    }
+
+    return av_image_fill_arrays(frame->data, frame->linesize, avpkt->data,
+                               avctx->pix_fmt, avctx->width, avctx->height, 1);
+}
+
+static int float2planes(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    int ret, x, y, lw;
+    const size_t sof = 4;
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x++){
+            memcpy(&frame->data[2][sof*(lw*y + x)], &pkt->data[sof* 3*(lw*y + x)], sof);
+            memcpy(&frame->data[0][sof*(lw*y + x)], &pkt->data[sof*(3*(lw*y + x) + 1)], sof);
+            memcpy(&frame->data[1][sof*(lw*y + x)], &pkt->data[sof*(3*(lw*y + x) + 2)], sof);
+        }
+    }
+    return pkt->size;
+}
+
+static int half_add_alpha(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    /* ffmpeg doesn't provide RGB half bit depth without alpha channel right now
+     * we simply add an opaque alpha layer as workaround */
+
+    int ret, x, y, lw;
+    const size_t soh = 2;
+    const _Float16 opaque = 1.0;
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x++){
+            memcpy(&frame->data[0][soh*4*(lw*y + x)], &pkt->data[soh*3*(lw*y + x)], soh*3);
+            memcpy(&frame->data[0][soh*(4*(lw*y + x) + 3)], &opaque, soh);
+        }
+    }
+    return pkt->size;
+}
+
+/* DNxUncompressed utilizes a very dense bitpack representation of 10bit and 12bit pixel data.
+
+Lines of Image data, which look like in their ordinary 8bit counterpart, contain the most 
+significant upper bits of the pixel data. These sections alternate with shorter segments in 
+which the complementary least significant bits of information get packed in a gapless sequence.
+
++----------------------+ +----------------------+ +------------------------+ +----------~
+|  8 m.s.bits of R[1]  | |  8 m.s.bits of G[1]  | |  8 m.s.bits of B[1]    | | msb R[2]    ... one line
++----------------------+ +----------------------+ +------------------------+ +----------~
+
++---------------------------------------------------------------+  +-----------~
+| +------------+ +------------+ +------------+ +--------------+ |  | +--------~
+| | 2 lsb R[1] | | 2 lsb G[1] | | 2 lsb B[1] | | 2 lsb R[2]   | |  | | G[2]lsb    ... LSB bits for line
+| +------------+ +------------+ +------------+ +--------------+ |  | +--------~
++---------------------------- one byte ------------------------ +  +-----------~
+
+next line of MSB bytes...   */
+
+static int unpack_rg10(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    int ret, x, y, lw, msp, pack, lsp;
+    uint16_t r,g,b;
+
+    if (avctx->width % 4){
+        av_log(0, AV_LOG_ERROR, 
+        "Image width has to be dividable by 4 for 10bit RGB DNxUncompressed!\n");
+        return AVERROR_EXIT;
+    }
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x++){
+            msp = pkt->data[y*3*(lw + lw/4) + 3*x];
+            pack = pkt->data[y*(3*(lw + lw/4)) + 3*lw + 3*x/4];
+            lsp = (pack >> (x%4)*2) & 0x3;
+            r = (msp << 2) + lsp;
+
+            msp = pkt->data[y*3*(lw + lw/4) + 3*x + 1];
+            pack = pkt->data[y*(3*(lw + lw/4)) + 3*lw + 3*(x+1)/4];
+            lsp = (pack >> ((x+1)%4)*2) & 0x3;
+            g = (msp << 2) + lsp;            
+            
+            msp = pkt->data[y*3*(lw + lw/4) + 3*x + 2];
+            pack = pkt->data[y*(3*(lw + lw/4)) + 3*lw + 3*(x+2)/4];
+            lsp = (pack >> ((x+2)%4)*2) & 0x3;
+            b = (msp << 2) + lsp;
+
+            memcpy(&frame->data[2][2*(y*lw + x)], &r, 2);
+            memcpy(&frame->data[0][2*(y*lw + x)], &g, 2);
+            memcpy(&frame->data[1][2*(y*lw + x)], &b, 2);
+        }
+    }
+    return pkt->size;
+}
+
+static int unpack_rg12(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    int ret, x, y, lw, msp, pack, lsp;
+    uint16_t r,g,b;
+
+    if (avctx->width % 2){
+        av_log(0, AV_LOG_ERROR, 
+        "Image width has to be dividable by 2 for 12bit RGB DNxUncompressed!\n");
+        return AVERROR_EXIT;
+    }
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x++){
+            msp = pkt->data[y*3*(lw + lw/2) + 3*x];
+            pack = pkt->data[y*(3*(lw + lw/2)) + 3*lw + 3*x/2];
+            lsp = (pack >> (x%2)*4) & 0xf;
+            r = (msp << 4) + lsp;
+
+            msp = pkt->data[y*3*(lw + lw/2) + 3*x + 1];
+            pack = pkt->data[y*(3*(lw + lw/2)) + 3*lw + 3*(x+1)/2];
+            lsp = (pack >> ((x+1)%2)*4) & 0xf;
+            g = (msp << 4) + lsp;            
+            
+            msp = pkt->data[y*3*(lw + lw/2) + 3*x + 2];
+            pack = pkt->data[y*(3*(lw + lw/2)) + 3*lw + 3*(x+2)/2];
+            lsp = (pack >> ((x+2)%2)*4) & 0xf;
+            b = (msp << 4) + lsp;
+
+            memcpy(&frame->data[2][2*(y*lw + x)], &r, 2);
+            memcpy(&frame->data[0][2*(y*lw + x)], &g, 2);
+            memcpy(&frame->data[1][2*(y*lw + x)], &b, 2);
+        }
+    }
+    return pkt->size;
+}
+
+
+static int unpack_y210(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    int ret, x, y, lw, msp, pack, lsp;
+    uint16_t y1, y2, u, v;
+
+    if (avctx->width % 2){
+        av_log(0, AV_LOG_ERROR, 
+        "Image width has to be dividable by 2 for 10bit YUV 4:2:2 DNxUncompressed!\n");
+        return AVERROR_EXIT;
+    }
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x += 2){
+            msp = pkt->data[y*2*(lw + lw/4) + 2*x];
+            pack = pkt->data[y*(2*(lw + lw/4)) + 2*lw + 2*x/4];
+            lsp = (pack >> (x%4)*2) & 0x3;
+            u = (msp << 2) + lsp;
+
+            msp = pkt->data[y*2*(lw + lw/4) + 2*x + 1];
+            pack = pkt->data[y*(2*(lw + lw/4)) + 2*lw + 2*x/4];
+            lsp = (pack >> ((x+1)%4)*2) & 0x3;
+            y1 = (msp << 2) + lsp;            
+            
+            msp = pkt->data[y*2*(lw + lw/4) + 2*x + 2];
+            pack = pkt->data[y*(2*(lw + lw/4)) + 2*lw + 2*x/4];
+            lsp = (pack >> ((x+2)%4)*2) & 0x3;
+            v = (msp << 2) + lsp;
+
+            msp = pkt->data[y*2*(lw + lw/4) + 2*x + 3];
+            pack = pkt->data[y*(2*(lw + lw/4)) + 2*lw + 2*(x+2)/4];
+            lsp = (pack >> ((x+3)%4)*2) & 0x3;
+            y2 = (msp << 2) + lsp;
+
+            memcpy(&frame->data[0][2*(y*lw + x)], &y1, 2);
+            memcpy(&frame->data[0][2*(y*lw + x+1)], &y2, 2);
+            memcpy(&frame->data[1][2*(y*lw/2 + x/2)], &u, 2);
+            memcpy(&frame->data[2][2*(y*lw/2 + x/2)], &v, 2);
+        }
+    }
+    return pkt->size;
+}
+
+
+static int unpack_y212(AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt){
+
+    int ret, x, y, lw, msp, pack, lsp;
+    uint16_t y1, y2, u, v;
+
+    if (avctx->width % 2){
+        av_log(0, AV_LOG_ERROR, 
+        "Image width has to be dividable by 2 for 12bit YUV 4:2:2 DNxUncompressed!\n");
+        return AVERROR_EXIT;
+    }
+
+    ret = ff_thread_get_buffer(avctx, frame, 0);
+    if (ret < 0)
+        return ret;
+
+    lw = frame->width;
+
+    for(y = 0; y < frame->height; y++){ 
+        for(x = 0; x < frame->width; x += 2){
+            msp = pkt->data[y*2*(lw + lw/2) + 2*x];
+            pack = pkt->data[y*(2*(lw + lw/2)) + 2*lw + 2*x/2];
+            lsp = (pack >> (x%2)*4) & 0xf;
+            u = (msp << 4) + lsp;
+
+            msp = pkt->data[y*2*(lw + lw/2) + 2*x + 1];
+            pack = pkt->data[y*(2*(lw + lw/2)) + 2*lw + 2*x/2];
+            lsp = (pack >> ((x+1)%2)*4) & 0xf;
+            y1 = (msp << 4) + lsp;            
+            
+            msp = pkt->data[y*2*(lw + lw/2) + 2*x + 2];
+            pack = pkt->data[y*(2*(lw + lw/2)) + 2*lw + 2*x/2];
+            lsp = (pack >> ((x+2)%2)*4) & 0xf;
+            v = (msp << 4) + lsp;
+
+            msp = pkt->data[y*2*(lw + lw/2) + 2*x + 3];
+            pack = pkt->data[y*(2*(lw + lw/2)) + 2*lw + 2*(x+2)/2];
+            lsp = (pack >> ((x+3)%3)*4) & 0xf;
+            y2 = (msp << 4) + lsp;
+
+            memcpy(&frame->data[0][2*(y*lw + x)], &y1, 2);
+            memcpy(&frame->data[0][2*(y*lw + x+1)], &y2, 2);
+            memcpy(&frame->data[1][2*(y*lw/2 + x/2)], &u, 2);
+            memcpy(&frame->data[2][2*(y*lw/2 + x/2)], &v, 2);
+        }
+    }
+    return pkt->size;
+}
+
+
+static int dnxuc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+                             int *got_frame, AVPacket *avpkt) {
+
+    char fourcc_buf[5];
+    int i, ret;
+    
+    switch (avctx->codec_tag) {
+        case MKTAG('r','g','0','8'):
+            avctx->pix_fmt = AV_PIX_FMT_RGB24;
+            ret = pass_though(avctx, frame, avpkt);
+            break;
+        case MKTAG('r','g','1','0'):
+            avctx->pix_fmt = AV_PIX_FMT_GBRP10LE;
+            ret = unpack_rg10(avctx, frame, avpkt);
+            break;
+        case MKTAG('r','g','1','2'):
+            avctx->pix_fmt = AV_PIX_FMT_GBRP12LE;
+            ret = unpack_rg12(avctx, frame, avpkt);
+            break;
+        case MKTAG(' ','r','g','h'):
+            avctx->pix_fmt = AV_PIX_FMT_RGBAF16LE;
+            ret = half_add_alpha(avctx, frame, avpkt);
+            break;
+        case MKTAG(' ','r','g','f'):
+            avctx->pix_fmt = AV_PIX_FMT_GBRPF32LE;
+            ret = float2planes(avctx, frame, avpkt);
+            break;
+
+        case MKTAG('y','2','0','8'):
+            avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+            ret = pass_though(avctx, frame, avpkt);
+            break;
+        case MKTAG('y','2','1','0'):
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
+            ret = unpack_y210(avctx, frame, avpkt);
+            break;
+        case MKTAG('y','2','1','2'):
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P12LE;
+            ret = unpack_y212(avctx, frame, avpkt);
+            break;
+
+        default:
+            av_fourcc_make_string(fourcc_buf, avctx->codec_tag);
+            av_log(0, AV_LOG_ERROR, 
+            "Unsupported DNxUncompressed pixel format variant: '%s'\n", 
+            fourcc_buf);
+            return AVERROR(ENOSYS);
+    }
+
+    if (ret < 0) {
+        av_buffer_unref(&frame->buf[0]);
+        return ret;
+    }
+
+    for (i = 0; frame->data[i]; i++){
+    av_log(0, AV_LOG_DEBUG, 
+        "frame(%ld) data[%d] dump: %02x %02x %02x %02x %02x %02x %02x %02x ...\n",
+        avctx->frame_num, i, 
+        frame->data[i][0], frame->data[i][1], frame->data[i][2], frame->data[i][3],
+        frame->data[i][4], frame->data[i][5], frame->data[i][6], frame->data[i][7]);
+    }
+
+    *got_frame = 1;
+
+    return avpkt->size;
+}
+
+const AVCodecParser ff_dnxuc_parser = {
+    .codec_ids      = { AV_CODEC_ID_DNXUC },
+    .priv_data_size = sizeof(DNxUcParseContext),
+    //.parser_init    = dnxuc_parser_init,
+    .parser_parse   = dnxuc_parse,
+    //.parser_close   = dnxuc_parser_close,
+};
+
+const FFCodec ff_dnxuc_decoder = {
+    .p.name         = "dnxuc",
+    CODEC_LONG_NAME()"DNxUncompressed (SMPTE RDD 50)",
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id             = AV_CODEC_ID_DNXUC,
+    .init           = dnxuc_decode_init,
+    FF_CODEC_DECODE_CB(dnxuc_decode_frame),
+    .p.capabilities = AV_CODEC_CAP_FRAME_THREADS,
+};
\ No newline at end of file
diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
index 5128009..8bfd2db 100644
--- a/libavcodec/parsers.c
+++ b/libavcodec/parsers.c
@@ -35,6 +35,7 @@ extern const AVCodecParser ff_cri_parser;
 extern const AVCodecParser ff_dca_parser;
 extern const AVCodecParser ff_dirac_parser;
 extern const AVCodecParser ff_dnxhd_parser;
+extern const AVCodecParser ff_dnxuc_parser;
 extern const AVCodecParser ff_dolby_e_parser;
 extern const AVCodecParser ff_dpx_parser;
 extern const AVCodecParser ff_dvaudio_parser;
diff --git a/libavcodec/version.c b/libavcodec/version.c
index 27f9432..c3b576a 100644
--- a/libavcodec/version.c
+++ b/libavcodec/version.c
@@ -31,7 +31,7 @@ const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
 
 unsigned avcodec_version(void)
 {
-    static_assert(AV_CODEC_ID_LEAD         ==   269 &&
+    static_assert(AV_CODEC_ID_LEAD         ==   270 &&
                   AV_CODEC_ID_PCM_SGA      == 65572 &&
                   AV_CODEC_ID_ADPCM_XMD    == 69683 &&
                   AV_CODEC_ID_CBD2_DPCM    == 81928 &&
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 8b53586..da2264a 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR  11
+#define LIBAVCODEC_VERSION_MINOR  12
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavformat/mxf.c b/libavformat/mxf.c
index a73e40e..35fb73e 100644
--- a/libavformat/mxf.c
+++ b/libavformat/mxf.c
@@ -61,6 +61,7 @@ const MXFCodecUL ff_mxf_codec_uls[] = {
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x71,0x00,0x00,0x00 }, 13,      AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x03,0x02,0x00,0x00 }, 14,      AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x02,0x01,0x02,0x04,0x01,0x00 }, 16,      AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD Legacy Avid Media Composer MXF */
+    { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x02,0x01,0x02,0x1E,0x01,0x00 }, 16,      AV_CODEC_ID_DNXUC }, /* DNxUncompressed/SMPTE RDD 50 */
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14,       AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra */
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 14,       AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC SPS/PPS in-band */
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x01 }, 16,       AV_CODEC_ID_V210 }, /* V210 */
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index af0c8a3..8f81fd8 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -208,13 +208,18 @@ typedef struct MXFDescriptor {
     int field_dominance;
     int channels;
     int bits_per_sample;
+    int padding_bits;
     int64_t duration; /* ContainerDuration optional property */
     unsigned int component_depth;
+    unsigned int color_siting;
     unsigned int black_ref_level;
     unsigned int white_ref_level;
     unsigned int color_range;
     unsigned int horiz_subsampling;
     unsigned int vert_subsampling;
+    unsigned int reversed_byte_order;
+    unsigned int image_start_offset;
+    unsigned int image_end_offset;
     UID *file_descriptors_refs;
     int file_descriptors_count;
     UID *sub_descriptors_refs;
@@ -1364,6 +1369,12 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
     case 0x3212:
         descriptor->field_dominance = avio_r8(pb);
         break;
+    case 0x3213:
+        descriptor->image_start_offset = avio_rb32(pb);
+        break;
+    case 0x3214:
+        descriptor->image_end_offset = avio_rb32(pb);
+        break;
     case 0x3219:
         avio_read(pb, descriptor->color_primaries_ul, 16);
         break;
@@ -1376,6 +1387,9 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
     case 0x3302:
         descriptor->horiz_subsampling = avio_rb32(pb);
         break;
+    case 0x3303:
+        descriptor->color_siting = avio_r8(pb);
+        break;
     case 0x3304:
         descriptor->black_ref_level = avio_rb32(pb);
         break;
@@ -1385,9 +1399,15 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
     case 0x3306:
         descriptor->color_range = avio_rb32(pb);
         break;
+    case 0x3307:
+        descriptor->padding_bits = avio_rb16(pb);
+        break;
     case 0x3308:
         descriptor->vert_subsampling = avio_rb32(pb);
         break;
+    case 0x330B:
+        descriptor->reversed_byte_order = avio_r8(pb);
+        break;
     case 0x3D03:
         descriptor->sample_rate.num = avio_rb32(pb);
         descriptor->sample_rate.den = avio_rb32(pb);
@@ -1597,6 +1617,7 @@ static const MXFCodecUL mxf_picture_essence_container_uls[] = {
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 }, 14,   AV_CODEC_ID_JPEG2000, NULL, 14, J2KWrap },
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, 14,       AV_CODEC_ID_H264, NULL, 15 }, /* H.264 */
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, 14,      AV_CODEC_ID_DNXHD, NULL, 14 }, /* VC-3 */
+    { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x1e,0x01,0x00 }, 14,      AV_CODEC_ID_DNXUC, NULL, 14 }, /* DNxUncompressed / SMPTE RDD 50 */
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x12,0x01,0x00 }, 14,        AV_CODEC_ID_VC1, NULL, 14 }, /* VC-1 */
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x14,0x01,0x00 }, 14,       AV_CODEC_ID_TIFF, NULL, 14 }, /* TIFF */
     { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x15,0x01,0x00 }, 14,      AV_CODEC_ID_DIRAC, NULL, 14 }, /* VC-2 */
-- 
2.45.2



More information about the ffmpeg-devel mailing list