mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2024-11-25 12:40:01 +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;
|
||||
} 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))
|
||||
|
||||
static EbmlSyntax ebml_header[] = {
|
||||
@ -426,6 +437,28 @@ static EbmlSyntax matroska_segments[] = {
|
||||
{ 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
|
||||
* 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;
|
||||
AVStream *st;
|
||||
AVPacket *pkt;
|
||||
uint8_t *origdata = data;
|
||||
int16_t block_time;
|
||||
uint32_t *lace_size = NULL;
|
||||
int n, flags, laces = 0;
|
||||
@ -1684,7 +1716,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
||||
/* first byte(s): tracknum */
|
||||
if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
|
||||
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
|
||||
av_free(origdata);
|
||||
return res;
|
||||
}
|
||||
data += n;
|
||||
@ -1695,12 +1726,10 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
|
||||
if (size <= 3 || !track || !track->stream) {
|
||||
av_log(matroska->ctx, AV_LOG_INFO,
|
||||
"Invalid stream %"PRIu64" or size %u\n", num, size);
|
||||
av_free(origdata);
|
||||
return res;
|
||||
}
|
||||
st = track->stream;
|
||||
if (st->discard >= AVDISCARD_ALL) {
|
||||
av_free(origdata);
|
||||
return res;
|
||||
}
|
||||
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 (!is_keyframe || st != matroska->skip_to_stream) {
|
||||
av_free(origdata);
|
||||
return res;
|
||||
}
|
||||
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(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;
|
||||
}
|
||||
|
||||
static int
|
||||
matroska_parse_cluster (MatroskaDemuxContext *matroska)
|
||||
{
|
||||
int res = 0;
|
||||
uint32_t id;
|
||||
uint64_t cluster_time = 0;
|
||||
uint8_t *data;
|
||||
int64_t pos;
|
||||
int size;
|
||||
|
||||
av_log(matroska->ctx, AV_LOG_DEBUG,
|
||||
"parsing cluster at %"PRId64"\n", url_ftell(matroska->ctx->pb));
|
||||
|
||||
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) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
MatroskaCluster cluster = { 0 };
|
||||
EbmlList *blocks_list;
|
||||
MatroskaBlock *blocks;
|
||||
int i, res = ebml_parse(matroska, matroska_clusters, &cluster, 0, 1);
|
||||
blocks_list = &cluster.blocks;
|
||||
blocks = blocks_list->elem;
|
||||
for (i=0; !res && i<blocks_list->nb_elem; i++)
|
||||
if (blocks[i].bin.size > 0)
|
||||
res=matroska_parse_block(matroska,
|
||||
blocks[i].bin.data, blocks[i].bin.size,
|
||||
blocks[i].bin.pos, cluster.timecode,
|
||||
blocks[i].duration, !blocks[i].reference);
|
||||
ebml_free(matroska_cluster, &cluster);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -2038,8 +1940,6 @@ matroska_read_packet (AVFormatContext *s,
|
||||
AVPacket *pkt)
|
||||
{
|
||||
MatroskaDemuxContext *matroska = s->priv_data;
|
||||
int res;
|
||||
uint32_t id;
|
||||
|
||||
/* Read stream until we have a packet queued. */
|
||||
while (matroska_deliver_packet(matroska, pkt)) {
|
||||
@ -2048,36 +1948,7 @@ matroska_read_packet (AVFormatContext *s,
|
||||
if (matroska->done)
|
||||
return AVERROR(EIO);
|
||||
|
||||
res = 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)
|
||||
if (matroska_parse_cluster(matroska) < 0)
|
||||
matroska->done = 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user