mirror of https://git.ffmpeg.org/ffmpeg.git
avformat/matroskadec: Make cluster parsing level compatible
Before this commit, the parsing of clusters mixed EBML levels by allowing elements from different levels in a EbmlSyntax (namely matroska_cluster_parsing). This has been changed. And the level is now explicitly used to determine how to parse. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
This commit is contained in:
parent
b31c9b72e5
commit
865c537007
|
@ -722,15 +722,10 @@ static const EbmlSyntax matroska_cluster_parsing[] = {
|
||||||
{ MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) },
|
{ MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) },
|
||||||
{ MATROSKA_ID_CLUSTERPOSITION, EBML_NONE },
|
{ MATROSKA_ID_CLUSTERPOSITION, EBML_NONE },
|
||||||
{ MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE },
|
{ MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE },
|
||||||
{ MATROSKA_ID_INFO, EBML_NONE },
|
CHILD_OF(matroska_segment)
|
||||||
{ MATROSKA_ID_CUES, EBML_NONE },
|
|
||||||
{ MATROSKA_ID_TAGS, EBML_NONE },
|
|
||||||
{ MATROSKA_ID_SEEKHEAD, EBML_NONE },
|
|
||||||
{ MATROSKA_ID_CLUSTER, EBML_STOP },
|
|
||||||
{ 0 } /* We don't want to go back to level 0, so don't add the parent. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const EbmlSyntax matroska_cluster[] = {
|
static const EbmlSyntax matroska_cluster_initial[] = {
|
||||||
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) },
|
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) },
|
||||||
{ MATROSKA_ID_BLOCKGROUP, EBML_STOP },
|
{ MATROSKA_ID_BLOCKGROUP, EBML_STOP },
|
||||||
{ MATROSKA_ID_SIMPLEBLOCK, EBML_STOP },
|
{ MATROSKA_ID_SIMPLEBLOCK, EBML_STOP },
|
||||||
|
@ -739,11 +734,19 @@ static const EbmlSyntax matroska_cluster[] = {
|
||||||
CHILD_OF(matroska_segment)
|
CHILD_OF(matroska_segment)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const EbmlSyntax matroska_cluster_enter[] = {
|
||||||
|
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster_initial } },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
static const EbmlSyntax matroska_clusters[] = {
|
static const EbmlSyntax matroska_clusters[] = {
|
||||||
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster } },
|
{ MATROSKA_ID_CLUSTER, EBML_STOP },
|
||||||
{ MATROSKA_ID_INFO, EBML_NONE },
|
|
||||||
{ MATROSKA_ID_CUES, EBML_NONE },
|
{ MATROSKA_ID_CUES, EBML_NONE },
|
||||||
{ MATROSKA_ID_TAGS, EBML_NONE },
|
{ MATROSKA_ID_TAGS, EBML_NONE },
|
||||||
|
{ MATROSKA_ID_INFO, EBML_NONE },
|
||||||
|
{ MATROSKA_ID_TRACKS, EBML_NONE },
|
||||||
|
{ MATROSKA_ID_ATTACHMENTS, EBML_NONE },
|
||||||
|
{ MATROSKA_ID_CHAPTERS, EBML_NONE },
|
||||||
{ MATROSKA_ID_SEEKHEAD, EBML_NONE },
|
{ MATROSKA_ID_SEEKHEAD, EBML_NONE },
|
||||||
{ 0 } /* We don't want to go back to level 0, so don't add the parent. */
|
{ 0 } /* We don't want to go back to level 0, so don't add the parent. */
|
||||||
};
|
};
|
||||||
|
@ -814,24 +817,6 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
|
||||||
return pb->error ? pb->error : AVERROR_EOF;
|
return pb->error ? pb->error : AVERROR_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return: Whether we reached the end of a level in the hierarchy or not.
|
|
||||||
*/
|
|
||||||
static int ebml_level_end(MatroskaDemuxContext *matroska)
|
|
||||||
{
|
|
||||||
AVIOContext *pb = matroska->ctx->pb;
|
|
||||||
int64_t pos = avio_tell(pb);
|
|
||||||
|
|
||||||
if (matroska->num_levels > 0) {
|
|
||||||
MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1];
|
|
||||||
if (pos - level->start >= level->length || matroska->current_id) {
|
|
||||||
matroska->num_levels--;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (matroska->is_live && matroska->ctx->pb->eof_reached) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read: an "EBML number", which is defined as a variable-length
|
* Read: an "EBML number", which is defined as a variable-length
|
||||||
* array of bytes. The first byte indicates the length by giving a
|
* array of bytes. The first byte indicates the length by giving a
|
||||||
|
@ -3604,41 +3589,37 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
|
||||||
MatroskaCluster *cluster = &matroska->current_cluster;
|
MatroskaCluster *cluster = &matroska->current_cluster;
|
||||||
MatroskaBlock *block = &cluster->block;
|
MatroskaBlock *block = &cluster->block;
|
||||||
int res;
|
int res;
|
||||||
res = ebml_parse(matroska,
|
|
||||||
matroska_cluster_parsing,
|
av_assert0(matroska->num_levels <= 2);
|
||||||
cluster);
|
|
||||||
|
if (matroska->num_levels == 1) {
|
||||||
|
res = ebml_parse(matroska, matroska_clusters, NULL);
|
||||||
|
|
||||||
if (res == 1) {
|
if (res == 1) {
|
||||||
/* New Cluster */
|
/* Found a cluster: subtract the size of the ID already read. */
|
||||||
if (cluster->pos)
|
cluster->pos = avio_tell(matroska->ctx->pb) - 4;
|
||||||
ebml_level_end(matroska);
|
|
||||||
cluster->pos = avio_tell(matroska->ctx->pb);
|
res = ebml_parse(matroska, matroska_cluster_enter, cluster);
|
||||||
/* sizeof the ID which was already read */
|
if (res < 0)
|
||||||
if (matroska->current_id)
|
return res;
|
||||||
cluster->pos -= 4;
|
|
||||||
res = ebml_parse(matroska,
|
|
||||||
matroska_clusters,
|
|
||||||
cluster);
|
|
||||||
/* Try parsing the block again. */
|
|
||||||
if (res == 1)
|
|
||||||
res = ebml_parse(matroska,
|
|
||||||
matroska_cluster_parsing,
|
|
||||||
cluster);
|
|
||||||
else
|
|
||||||
cluster->pos = 0;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matroska->num_levels == 2) {
|
||||||
|
int err = 0;
|
||||||
|
/* We are inside a cluster. */
|
||||||
|
res = ebml_parse(matroska, matroska_cluster_parsing, cluster);
|
||||||
|
|
||||||
if (res >= 0 && block->bin.size > 0) {
|
if (res >= 0 && block->bin.size > 0) {
|
||||||
int is_keyframe = block->non_simple ? block->reference == INT64_MIN : -1;
|
int is_keyframe = block->non_simple ? block->reference == INT64_MIN : -1;
|
||||||
uint8_t* additional = block->additional.size > 0 ?
|
uint8_t* additional = block->additional.size > 0 ?
|
||||||
block->additional.data : NULL;
|
block->additional.data : NULL;
|
||||||
|
|
||||||
res = matroska_parse_block(matroska, block->bin.buf, block->bin.data,
|
err = matroska_parse_block(matroska, block->bin.buf, block->bin.data,
|
||||||
block->bin.size, block->bin.pos,
|
block->bin.size, block->bin.pos,
|
||||||
matroska->current_cluster.timecode,
|
cluster->timecode, block->duration,
|
||||||
block->duration, is_keyframe,
|
is_keyframe, additional, block->additional_id,
|
||||||
additional, block->additional_id,
|
block->additional.size, cluster->pos,
|
||||||
block->additional.size,
|
|
||||||
cluster->pos,
|
|
||||||
block->discard_padding);
|
block->discard_padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3648,6 +3629,13 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
|
||||||
ebml_free(matroska_blockgroup, block);
|
ebml_free(matroska_blockgroup, block);
|
||||||
memset(block, 0, sizeof(*block));
|
memset(block, 0, sizeof(*block));
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
} else if (!matroska->num_levels) {
|
||||||
|
matroska->done = 1;
|
||||||
|
return AVERROR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue