[FFmpeg-cvslog] avcodec/dnxuc_parser: rework DNXUC parser
Marton Balint
git at videolan.org
Mon Nov 25 23:46:27 EET 2024
ffmpeg | branch: master | Marton Balint <cus at passwd.hu> | Tue Nov 19 10:51:16 2024 +0100| [1402a2ac3ba59dfa0b5a1e82c180694104e9d677] | committer: Marton Balint
avcodec/dnxuc_parser: rework DNXUC parser
The current parser does things which a parser should not, like skipping parts
of the packet header, but it does not actually able to packetize a raw DNXUC
bitstream.
Rework the parser logic to work similar to other parsers and be able to
correctly packetize raw DNXUC bitstreams.
Bump minor version because the DNXUC codec packet format changes with this.
Normally this would be a breaking change, but in this particular case it should
not cause any issues in practice because the DNXUC codec is relatively new and
we never added a decoder for it.
Signed-off-by: Marton Balint <cus at passwd.hu>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=1402a2ac3ba59dfa0b5a1e82c180694104e9d677
---
libavcodec/dnxuc_parser.c | 122 +++++++++++++++++-----------------------------
libavcodec/version.h | 4 +-
2 files changed, 46 insertions(+), 80 deletions(-)
diff --git a/libavcodec/dnxuc_parser.c b/libavcodec/dnxuc_parser.c
index 12472c7a2d..14f19efe67 100644
--- a/libavcodec/dnxuc_parser.c
+++ b/libavcodec/dnxuc_parser.c
@@ -20,99 +20,65 @@
*/
/*
- This parser 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.
-
- Limitations: Multiple image planes are not supported.
-*/
+ * This parser for DNxUncompressed video data is mostly based on the public
+ * SMPTE RDD 50:2019 specification.
+ */
-#include "avcodec.h"
-#include "libavutil/intreadwrite.h"
+#include "parser.h"
+#include "libavutil/bswap.h"
typedef struct DNxUcParseContext {
- uint32_t fourcc_tag;
- uint32_t width;
- uint32_t height;
- uint32_t nr_bytes;
+ ParseContext pc;
+ uint32_t remaining;
} DNxUcParseContext;
-/*
-DNxUncompressed frame data comes wrapped in nested boxes of metadata
-(box structure: len + fourcc marker + data):
-
-[0-4] len of outer essence unit box (typically 37 bytes of header + frame data)
-[4-7] fourcc 'pack'
-
-[8-11] len of "signal info box" (always 21)
-[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] frame_layout (0: progressive, 1: interlaced)
-
-[29-32] len of "signal data box" (nr of frame data bytes + 8)
-[33-36] fourcc 'sdat'
-[37-..] frame data
-
-A sequence of 'signal info'+'signal data' box pairs wrapped in
-'icmp'(=image component) boxes can be utilized to compose more
-complex multi plane images.
-This feature is only partially supported in the present implementation.
-We never pick more than the first pair of info and image data enclosed
-in this way.
-*/
-
static int dnxuc_parse(AVCodecParserContext *s,
AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
- const int HEADER_SIZE = 37;
- int icmp_offset = 0;
-
- DNxUcParseContext *pc;
- pc = (DNxUcParseContext *) s->priv_data;
-
- if (!buf_size) {
- return 0;
- }
- if (buf_size > 16 && MKTAG('i','c','m','p') == AV_RL32(buf+12)){
- icmp_offset += 8;
- }
- if ( buf_size < 37 + icmp_offset /* check metadata structure expectations */
- || MKTAG('p','a','c','k') != AV_RL32(buf+4+icmp_offset)
- || MKTAG('s','i','n','f') != AV_RL32(buf+12+icmp_offset)
- || MKTAG('s','d','a','t') != AV_RL32(buf+33+icmp_offset)){
- av_log(avctx, AV_LOG_ERROR, "can't read DNxUncompressed metadata.\n");
+ DNxUcParseContext *ipc = s->priv_data;
+ int next = END_NOT_FOUND;
+
+ s->pict_type = AV_PICTURE_TYPE_NONE;
+
+ *poutbuf_size = 0;
+ *poutbuf = NULL;
+
+ if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+ next = buf_size;
+ } else {
+ if (ipc->remaining == 0) {
+ uint64_t state = ipc->pc.state64;
+ for (int i = 0; i < buf_size; i++) {
+ state = (state << 8) | buf[i];
+ if (ipc->pc.index + i >= 7 && (uint32_t)state == MKBETAG('p','a','c','k')) {
+ uint32_t size = av_bswap32(state >> 32);
+ if (size >= 8) {
+ next = i - 7;
+ ipc->remaining = size + FFMIN(next, 0);
+ break;
+ }
+ }
+ }
+ ipc->pc.state64 = state;
+ } else if (ipc->remaining <= buf_size) {
+ next = ipc->remaining;
+ ipc->remaining = 0;
+ } else {
+ ipc->remaining -= buf_size;
+ }
+ if (ff_combine_frame(&ipc->pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
*poutbuf_size = 0;
return buf_size;
+ }
}
- pc->fourcc_tag = AV_RL32(buf+24+icmp_offset);
- pc->width = AV_RL32(buf+16+icmp_offset);
- pc->height = AV_RL32(buf+20+icmp_offset);
- pc->nr_bytes = AV_RL32(buf+29+icmp_offset) - 8;
-
- if (!avctx->codec_tag) {
- av_log(avctx, AV_LOG_INFO, "dnxuc_parser: '%s' %dx%d %dbpp %d\n",
- av_fourcc2str(pc->fourcc_tag),
- 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 + icmp_offset){
- av_log(avctx, AV_LOG_ERROR, "Insufficient size of image essence data.\n");
- *poutbuf_size = 0;
- return buf_size;
- }
-
- *poutbuf = buf + HEADER_SIZE + icmp_offset;
- *poutbuf_size = pc->nr_bytes;
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
- return buf_size;
+ return next;
}
const AVCodecParser ff_dnxuc_parser = {
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 8eaabc20ca..26ee41eb1f 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,8 +29,8 @@
#include "version_major.h"
-#define LIBAVCODEC_VERSION_MINOR 25
-#define LIBAVCODEC_VERSION_MICRO 103
+#define LIBAVCODEC_VERSION_MINOR 26
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
More information about the ffmpeg-cvslog
mailing list