mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-29 22:00:58 +02:00
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@passwd.hu>
This commit is contained in:
parent
aea63ea7f5
commit
1402a2ac3b
@ -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.
|
||||
* This parser for DNxUncompressed video data is mostly based on the public
|
||||
* SMPTE RDD 50:2019 specification.
|
||||
*/
|
||||
|
||||
Limitations: Multiple image planes are not supported.
|
||||
*/
|
||||
|
||||
#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 *ipc = s->priv_data;
|
||||
int next = END_NOT_FOUND;
|
||||
|
||||
DNxUcParseContext *pc;
|
||||
pc = (DNxUcParseContext *) s->priv_data;
|
||||
s->pict_type = AV_PICTURE_TYPE_NONE;
|
||||
|
||||
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");
|
||||
*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;
|
||||
*poutbuf = buf;
|
||||
*poutbuf_size = buf_size;
|
||||
|
||||
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;
|
||||
|
||||
return buf_size;
|
||||
return next;
|
||||
}
|
||||
|
||||
const AVCodecParser ff_dnxuc_parser = {
|
||||
|
@ -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, \
|
||||
|
Loading…
x
Reference in New Issue
Block a user