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.cdiff --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,
+};
OpenPGP_signature.asc
Description: OpenPGP digital signature
_______________________________________________ ffmpeg-devel mailing list [email protected] https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email [email protected] with subject "unsubscribe".
