[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