[FFmpeg-devel] [PATCH v12 5/9] libavcodec/dnxucdec: DNxUncompressed decoder

James Almer jamrial at gmail.com
Mon Oct 21 23:44:49 EEST 2024


On 10/21/2024 4:57 PM, Martin Schitter wrote:
> ---
>   libavcodec/Makefile    |   1 +
>   libavcodec/allcodecs.c |   1 +
>   libavcodec/dnxucdec.c  | 338 +++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 340 insertions(+)
>   create mode 100644 libavcodec/dnxucdec.c
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index dd5d0de..e13b127 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -328,6 +328,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 c7e5f99..ccca2ad 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/dnxucdec.c b/libavcodec/dnxucdec.c
> new file mode 100644
> index 0000000..9d5847d
> --- /dev/null
> +++ b/libavcodec/dnxucdec.c
> @@ -0,0 +1,338 @@
> +/*
> + * Avid DNxUncomressed / SMPTE RDD 50 decoder
> + * 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 decoder 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.
> +
> + Not all DNxUncompressed pixel format variants are supported,
> + but at least an elementary base set is already usable:
> +
> +  - YUV 4:2:2 8/10/12/16bit/half/float   (16bit untested)
> +    YUV 4:4:4 8/16bit/half/float         (all untested!)
> +  - RGB 8/10/12/16bit/half/float         (16bit untested)
> +    Alpha/Y 8/16bit                      (all untested!)

That's not good...

[...]

> +static int dnxuc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
> +                             int *got_frame, AVPacket *avpkt)
> +{
> +    char fourcc_buf[AV_FOURCC_MAX_STRING_SIZE];
> +    int ret;
> +
> +    av_fourcc_make_string(fourcc_buf, avctx->codec_tag);
> +    if ((avctx->width % 2) && ((fourcc_buf[0] == 'y' && fourcc_buf[1] == '2')
> +                             ||(fourcc_buf[1] == 'y' && fourcc_buf[2] == '2'))){
> +        av_log(avctx, AV_LOG_ERROR,
> +        "Image width must be a multiple of 2 for YUV 4:2:2 DNxUncompressed!\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    switch (avctx->codec_tag) {
> +        case MKTAG('y','2','0','8'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_UYVY422, 16, pass_through);


> +            break;
> +        case MKTAG('y','4','0','8'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444, 24, pass_through);

Y408 is mapped to AV_PIX_FMT_AYUV.

> +            break;
> +        case MKTAG('y','2','1','0'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV422P10LE, 20, unpack_y210);

Y210 has no pixel format, and it's packed, not planar, so definitely not 
AV_PIX_FMT_YUV422P10LE.

> +            break;
> +        case MKTAG('y','4','1','0'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444P10LE, 20, unpack_y410);

Y410 is mapped to AV_PIX_FMT_XV30LE.

> +            break;
> +        case MKTAG('y','2','1','2'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV422P12LE, 24, unpack_y212);

AV_PIX_FMT_Y212?

> +            break;
> +        case MKTAG('y','4','1','2'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444P12LE, 24, unpack_y412);

This one is probably AV_PIX_FMT_XV36, and definitely not planar.

> +            break;
> +        case MKTAG('y','2','1','6'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_UYVY422_16LE, 32, pass_through);

The order of y216 appears to be YUYV, not UYVY. 
https://learn.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats

> +            break;
> +        case MKTAG('y','4','1','6'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444_16LE, 48, pass_through);

This one is probably AV_PIX_FMT_AYUV64.

> +            break;
> +        case MKTAG(' ','y','2','h'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_UYVY422F16LE, 32, pass_through);
> +            break;
> +        case MKTAG(' ','y','4','h'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444F16LE, 48, pass_through);
> +            break;
> +        case MKTAG(' ','y','2','f'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_UYVY422F32LE, 64, pass_through);
> +            break;
> +        case MKTAG(' ','y','4','f'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_YUV444F32LE, 96, pass_through);
> +            break;
> +
> +        case MKTAG('r','g','0','8'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_RGB24, 24, pass_through);
> +            break;
> +        case MKTAG('r','g','1','0'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_GBRP10LE, 30, unpack_rg10);
> +            break;
> +        case MKTAG('r','g','1','2'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_GBRP12LE, 36, unpack_rg12);
> +            break;
> +        case MKTAG('r','g','1','6'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_RGB48LE, 48, pass_through);
> +            break;
> +        case MKTAG(' ','r','g','h'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_RGBF16LE, 48, pass_through);
> +            break;
> +        case MKTAG(' ','r','g','f'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_RGBF32LE, 96, pass_through);
> +            break;
> +
> +        case MKTAG(' ','a','0','8'):
> +        case MKTAG(' ','y','0','8'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_GRAY8, 8, pass_through);
> +            break;
> +        case MKTAG(' ','a','1','6'):
> +        case MKTAG(' ','y','1','6'):
> +            ret = fmt_frame(avctx, frame, avpkt, AV_PIX_FMT_GRAY16LE, 16, pass_through);
> +            break;
> +
> +        // case MKTAG('r','l','0','8'): TODO: RLE encoded 8bit alpha
> +        // case MKTAG('r','l','1','6'): TODO: RLE encoded 16bit alpha
> +
> +        default:
> +            av_log(avctx, AV_LOG_ERROR,
> +            "Unsupported DNxUncompressed pixel format variant: '%s'\n",
> +            fourcc_buf);
> +            return AVERROR_PATCHWELCOME;
> +    }
> +
> +    if (ret < 0) {
> +        av_buffer_unref(&frame->buf[0]);
> +        return ret;
> +    }
> +
> +    *got_frame = 1;
> +
> +    return avpkt->size;
> +}
> +
> +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,
> +    FF_CODEC_DECODE_CB(dnxuc_decode_frame),
> +    .p.capabilities = AV_CODEC_CAP_FRAME_THREADS,
> +};

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 495 bytes
Desc: OpenPGP digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20241021/7c65f811/attachment.sig>


More information about the ffmpeg-devel mailing list