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 ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".