avformat/matroskadec: support parsing more than one BlockMore element

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer 2023-03-12 15:02:06 -03:00
parent 2244722f1f
commit 44513156e3
1 changed files with 41 additions and 21 deletions

View File

@ -349,13 +349,17 @@ typedef struct MatroskaLevel {
uint64_t length;
} MatroskaLevel;
typedef struct MatroskaBlockMore {
uint64_t additional_id;
EbmlBin additional;
} MatroskaBlockMore;
typedef struct MatroskaBlock {
uint64_t duration;
CountedElement reference;
uint64_t non_simple;
EbmlBin bin;
uint64_t additional_id;
EbmlBin additional;
EbmlList blockmore;
int64_t discard_padding;
} MatroskaBlock;
@ -759,13 +763,13 @@ static EbmlSyntax matroska_segments[] = {
};
static EbmlSyntax matroska_blockmore[] = {
{ MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, 0, offsetof(MatroskaBlock,additional_id), { .u = 1 } },
{ MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, 0, offsetof(MatroskaBlock,additional) },
{ MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, 0, offsetof(MatroskaBlockMore,additional_id), { .u = 1 } },
{ MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, 0, offsetof(MatroskaBlockMore,additional) },
CHILD_OF(matroska_blockadditions)
};
static EbmlSyntax matroska_blockadditions[] = {
{ MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, 0, {.n = matroska_blockmore} },
{ MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, sizeof(MatroskaBlockMore), offsetof(MatroskaBlock, blockmore), { .n = matroska_blockmore } },
CHILD_OF(matroska_blockgroup)
};
@ -3610,12 +3614,28 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
return 0;
}
static int matroska_parse_block_additional(MatroskaDemuxContext *matroska,
AVPacket *pkt,
const uint8_t *data, int size, uint64_t id)
{
uint8_t *side_data = av_packet_new_side_data(pkt,
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
size + (size_t)8);
if (!side_data)
return AVERROR(ENOMEM);
AV_WB64(side_data, id);
memcpy(side_data + 8, data, size);
return 0;
}
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track, AVStream *st,
AVBufferRef *buf, uint8_t *data, int pkt_size,
uint64_t timecode, uint64_t lace_duration,
int64_t pos, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
MatroskaBlockMore *blockmore, int nb_blockmore,
int64_t discard_padding)
{
uint8_t *pkt_data = data;
@ -3647,7 +3667,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
buf = NULL;
}
if (!pkt_size && !additional_size)
if (!pkt_size && !nb_blockmore)
goto no_output;
if (!buf)
@ -3666,16 +3686,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
pkt->flags = is_keyframe;
pkt->stream_index = st->index;
if (additional_size > 0) {
uint8_t *side_data = av_packet_new_side_data(pkt,
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
additional_size + 8);
if (!side_data) {
for (int i = 0; i < nb_blockmore; i++) {
MatroskaBlockMore *more = &blockmore[i];
if (!more->additional.size)
continue;
res = matroska_parse_block_additional(matroska, pkt, more->additional.data,
more->additional.size, more->additional_id);
if (res < 0) {
av_packet_unref(pkt);
return AVERROR(ENOMEM);
return res;
}
AV_WB64(side_data, additional_id);
memcpy(side_data + 8, additional, additional_size);
}
if (discard_padding) {
@ -3721,7 +3743,7 @@ fail:
static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t block_duration, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
MatroskaBlockMore *blockmore, int nb_blockmore,
int64_t cluster_pos, int64_t discard_padding)
{
uint64_t timecode = AV_NOPTS_VALUE;
@ -3856,7 +3878,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
res = matroska_parse_frame(matroska, track, st, buf, out_data,
out_size, timecode, lace_duration,
pos, !n ? is_keyframe : 0,
additional, additional_id, additional_size,
blockmore, nb_blockmore,
discard_padding);
if (res)
return res;
@ -3897,14 +3919,12 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
if (res >= 0 && block->bin.size > 0) {
int is_keyframe = block->non_simple ? block->reference.count == 0 : -1;
uint8_t* additional = block->additional.size > 0 ?
block->additional.data : NULL;
res = matroska_parse_block(matroska, block->bin.buf, block->bin.data,
block->bin.size, block->bin.pos,
cluster->timecode, block->duration,
is_keyframe, additional, block->additional_id,
block->additional.size, cluster->pos,
is_keyframe, block->blockmore.elem,
block->blockmore.nb_elem, cluster->pos,
block->discard_padding);
}