mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-04-11 03:32:39 +00:00
matroskadec: use generic parser to parse clusters
Originally committed as revision 14573 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
f06a488647
commit
209472b45d
@ -216,6 +216,17 @@ typedef struct MatroskaDemuxContext {
|
|||||||
AVStream *skip_to_stream;
|
AVStream *skip_to_stream;
|
||||||
} MatroskaDemuxContext;
|
} MatroskaDemuxContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t duration;
|
||||||
|
int64_t reference;
|
||||||
|
EbmlBin bin;
|
||||||
|
} MatroskaBlock;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t timecode;
|
||||||
|
EbmlList blocks;
|
||||||
|
} MatroskaCluster;
|
||||||
|
|
||||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
|
||||||
|
|
||||||
static EbmlSyntax ebml_header[] = {
|
static EbmlSyntax ebml_header[] = {
|
||||||
@ -426,6 +437,28 @@ static EbmlSyntax matroska_segments[] = {
|
|||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static EbmlSyntax matroska_blockgroup[] = {
|
||||||
|
{ MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) },
|
||||||
|
{ MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) },
|
||||||
|
{ MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} },
|
||||||
|
{ MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
|
||||||
|
{ EBML_ID_VOID, EBML_NONE },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static EbmlSyntax matroska_cluster[] = {
|
||||||
|
{ MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) },
|
||||||
|
{ MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} },
|
||||||
|
{ MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} },
|
||||||
|
{ EBML_ID_VOID, EBML_NONE },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static EbmlSyntax matroska_clusters[] = {
|
||||||
|
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, {.n=matroska_cluster} },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first few functions handle EBML file parsing. The rest
|
* The first few functions handle EBML file parsing. The rest
|
||||||
* is the document interpretation. Matroska really just is a
|
* is the document interpretation. Matroska really just is a
|
||||||
@ -1675,7 +1708,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
AVPacket *pkt;
|
AVPacket *pkt;
|
||||||
uint8_t *origdata = data;
|
|
||||||
int16_t block_time;
|
int16_t block_time;
|
||||||
uint32_t *lace_size = NULL;
|
uint32_t *lace_size = NULL;
|
||||||
int n, flags, laces = 0;
|
int n, flags, laces = 0;
|
||||||
@ -1684,7 +1716,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
|||||||
/* first byte(s): tracknum */
|
/* first byte(s): tracknum */
|
||||||
if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
|
if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
|
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
|
||||||
av_free(origdata);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
data += n;
|
data += n;
|
||||||
@ -1695,12 +1726,10 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
|||||||
if (size <= 3 || !track || !track->stream) {
|
if (size <= 3 || !track || !track->stream) {
|
||||||
av_log(matroska->ctx, AV_LOG_INFO,
|
av_log(matroska->ctx, AV_LOG_INFO,
|
||||||
"Invalid stream %"PRIu64" or size %u\n", num, size);
|
"Invalid stream %"PRIu64" or size %u\n", num, size);
|
||||||
av_free(origdata);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
st = track->stream;
|
st = track->stream;
|
||||||
if (st->discard >= AVDISCARD_ALL) {
|
if (st->discard >= AVDISCARD_ALL) {
|
||||||
av_free(origdata);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (duration == AV_NOPTS_VALUE)
|
if (duration == AV_NOPTS_VALUE)
|
||||||
@ -1716,7 +1745,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
|||||||
|
|
||||||
if (matroska->skip_to_keyframe) {
|
if (matroska->skip_to_keyframe) {
|
||||||
if (!is_keyframe || st != matroska->skip_to_stream) {
|
if (!is_keyframe || st != matroska->skip_to_stream) {
|
||||||
av_free(origdata);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
matroska->skip_to_keyframe = 0;
|
matroska->skip_to_keyframe = 0;
|
||||||
@ -1885,151 +1913,25 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
av_free(lace_size);
|
av_free(lace_size);
|
||||||
av_free(origdata);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
|
|
||||||
uint64_t cluster_time)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
uint32_t id;
|
|
||||||
int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets;
|
|
||||||
uint64_t duration = AV_NOPTS_VALUE;
|
|
||||||
uint8_t *data;
|
|
||||||
int size = 0;
|
|
||||||
int64_t pos = 0;
|
|
||||||
|
|
||||||
av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n");
|
|
||||||
|
|
||||||
while (res == 0) {
|
|
||||||
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
|
|
||||||
res = AVERROR(EIO);
|
|
||||||
break;
|
|
||||||
} else if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
/* one block inside the group. Note, block parsing is one
|
|
||||||
* of the harder things, so this code is a bit complicated.
|
|
||||||
* See http://www.matroska.org/ for documentation. */
|
|
||||||
case MATROSKA_ID_BLOCK: {
|
|
||||||
pos = url_ftell(matroska->ctx->pb);
|
|
||||||
res = ebml_read_binary(matroska, &id, &data, &size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MATROSKA_ID_BLOCKDURATION: {
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &duration)) < 0)
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MATROSKA_ID_BLOCKREFERENCE: {
|
|
||||||
int64_t num;
|
|
||||||
/* We've found a reference, so not even the first frame in
|
|
||||||
* the lace is a key frame. */
|
|
||||||
is_keyframe = 0;
|
|
||||||
if (last_num_packets != matroska->num_packets)
|
|
||||||
matroska->packets[last_num_packets]->flags = 0;
|
|
||||||
if ((res = ebml_read_sint(matroska, &id, &num)) < 0)
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
av_log(matroska->ctx, AV_LOG_INFO,
|
|
||||||
"Unknown entry 0x%x in blockgroup data\n", id);
|
|
||||||
/* fall-through */
|
|
||||||
|
|
||||||
case EBML_ID_VOID:
|
|
||||||
res = ebml_read_skip(matroska);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if (size > 0)
|
|
||||||
res = matroska_parse_block(matroska, data, size, pos, cluster_time,
|
|
||||||
duration, is_keyframe);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
matroska_parse_cluster (MatroskaDemuxContext *matroska)
|
matroska_parse_cluster (MatroskaDemuxContext *matroska)
|
||||||
{
|
{
|
||||||
int res = 0;
|
MatroskaCluster cluster = { 0 };
|
||||||
uint32_t id;
|
EbmlList *blocks_list;
|
||||||
uint64_t cluster_time = 0;
|
MatroskaBlock *blocks;
|
||||||
uint8_t *data;
|
int i, res = ebml_parse(matroska, matroska_clusters, &cluster, 0, 1);
|
||||||
int64_t pos;
|
blocks_list = &cluster.blocks;
|
||||||
int size;
|
blocks = blocks_list->elem;
|
||||||
|
for (i=0; !res && i<blocks_list->nb_elem; i++)
|
||||||
av_log(matroska->ctx, AV_LOG_DEBUG,
|
if (blocks[i].bin.size > 0)
|
||||||
"parsing cluster at %"PRId64"\n", url_ftell(matroska->ctx->pb));
|
res=matroska_parse_block(matroska,
|
||||||
|
blocks[i].bin.data, blocks[i].bin.size,
|
||||||
while (res == 0) {
|
blocks[i].bin.pos, cluster.timecode,
|
||||||
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
|
blocks[i].duration, !blocks[i].reference);
|
||||||
res = AVERROR(EIO);
|
ebml_free(matroska_cluster, &cluster);
|
||||||
break;
|
|
||||||
} else if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
/* cluster timecode */
|
|
||||||
case MATROSKA_ID_CLUSTERTIMECODE: {
|
|
||||||
uint64_t num;
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
|
|
||||||
break;
|
|
||||||
cluster_time = num;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a group of blocks inside a cluster */
|
|
||||||
case MATROSKA_ID_BLOCKGROUP:
|
|
||||||
if ((res = ebml_read_master(matroska, &id)) < 0)
|
|
||||||
break;
|
|
||||||
res = matroska_parse_blockgroup(matroska, cluster_time);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MATROSKA_ID_SIMPLEBLOCK:
|
|
||||||
pos = url_ftell(matroska->ctx->pb);
|
|
||||||
res = ebml_read_binary(matroska, &id, &data, &size);
|
|
||||||
if (res == 0)
|
|
||||||
res = matroska_parse_block(matroska, data, size, pos,
|
|
||||||
cluster_time, AV_NOPTS_VALUE,
|
|
||||||
-1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
av_log(matroska->ctx, AV_LOG_INFO,
|
|
||||||
"Unknown entry 0x%x in cluster data\n", id);
|
|
||||||
/* fall-through */
|
|
||||||
|
|
||||||
case EBML_ID_VOID:
|
|
||||||
res = ebml_read_skip(matroska);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2038,8 +1940,6 @@ matroska_read_packet (AVFormatContext *s,
|
|||||||
AVPacket *pkt)
|
AVPacket *pkt)
|
||||||
{
|
{
|
||||||
MatroskaDemuxContext *matroska = s->priv_data;
|
MatroskaDemuxContext *matroska = s->priv_data;
|
||||||
int res;
|
|
||||||
uint32_t id;
|
|
||||||
|
|
||||||
/* Read stream until we have a packet queued. */
|
/* Read stream until we have a packet queued. */
|
||||||
while (matroska_deliver_packet(matroska, pkt)) {
|
while (matroska_deliver_packet(matroska, pkt)) {
|
||||||
@ -2048,36 +1948,7 @@ matroska_read_packet (AVFormatContext *s,
|
|||||||
if (matroska->done)
|
if (matroska->done)
|
||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
|
|
||||||
res = 0;
|
if (matroska_parse_cluster(matroska) < 0)
|
||||||
while (res == 0) {
|
|
||||||
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
|
|
||||||
return AVERROR(EIO);
|
|
||||||
} else if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case MATROSKA_ID_CLUSTER:
|
|
||||||
if ((res = ebml_read_master(matroska, &id)) < 0)
|
|
||||||
break;
|
|
||||||
if ((res = matroska_parse_cluster(matroska)) == 0)
|
|
||||||
res = 1; /* Parsed one cluster, let's get out. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
case EBML_ID_VOID:
|
|
||||||
res = ebml_read_skip(matroska);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matroska->level_up) {
|
|
||||||
matroska->level_up--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == -1)
|
|
||||||
matroska->done = 1;
|
matroska->done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user