|
|
|
@ -209,6 +209,7 @@ typedef struct MatroskaDemuxContext { |
|
|
|
|
int metadata_parsed; |
|
|
|
|
int index_parsed; |
|
|
|
|
int done; |
|
|
|
|
int has_cluster_id; |
|
|
|
|
|
|
|
|
|
/* What to skip before effectively reading a packet. */ |
|
|
|
|
int skip_to_keyframe; |
|
|
|
@ -407,6 +408,24 @@ static EbmlSyntax matroska_seekhead[] = { |
|
|
|
|
{ 0 } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static EbmlSyntax matroska_segment[] = { |
|
|
|
|
{ MATROSKA_ID_INFO, EBML_NEST, 0, 0, {.n=matroska_info } }, |
|
|
|
|
{ MATROSKA_ID_TRACKS, EBML_NEST, 0, 0, {.n=matroska_tracks } }, |
|
|
|
|
{ MATROSKA_ID_ATTACHMENTS, EBML_NEST, 0, 0, {.n=matroska_attachments} }, |
|
|
|
|
{ MATROSKA_ID_CHAPTERS, EBML_NEST, 0, 0, {.n=matroska_chapters } }, |
|
|
|
|
{ MATROSKA_ID_CUES, EBML_NEST, 0, 0, {.n=matroska_index } }, |
|
|
|
|
{ MATROSKA_ID_TAGS, EBML_NEST, 0, 0, {.n=matroska_tags } }, |
|
|
|
|
{ MATROSKA_ID_SEEKHEAD, EBML_NEST, 0, 0, {.n=matroska_seekhead } }, |
|
|
|
|
{ MATROSKA_ID_CLUSTER, EBML_STOP, 0, offsetof(MatroskaDemuxContext,has_cluster_id) }, |
|
|
|
|
{ EBML_ID_VOID, EBML_NONE }, |
|
|
|
|
{ 0 } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static EbmlSyntax matroska_segments[] = { |
|
|
|
|
{ MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, {.n=matroska_segment } }, |
|
|
|
|
{ 0 } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The first few functions handle EBML file parsing. The rest |
|
|
|
|
* is the document interpretation. Matroska really just is a |
|
|
|
@ -1151,14 +1170,6 @@ static void ebml_free(EbmlSyntax *syntax, void *data) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_info (MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
|
int res = ebml_parse(matroska, matroska_info, matroska, MATROSKA_ID_INFO, 0); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_decode_buffer(uint8_t** buf, int* buf_size, MatroskaTrack *track) |
|
|
|
|
{ |
|
|
|
@ -1236,16 +1247,6 @@ matroska_decode_buffer(uint8_t** buf, int* buf_size, MatroskaTrack *track) |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_tracks (MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
|
int i, res; |
|
|
|
|
|
|
|
|
|
res = ebml_parse(matroska, matroska_tracks, matroska, MATROSKA_ID_TRACKS, 0); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_index (MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
@ -1258,12 +1259,6 @@ matroska_parse_metadata (MatroskaDemuxContext *matroska) |
|
|
|
|
return ebml_parse(matroska, matroska_tags, matroska, MATROSKA_ID_TAGS, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_seekhead (MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
|
return ebml_parse(matroska, matroska_seekhead, matroska, MATROSKA_ID_SEEKHEAD, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
matroska_execute_seekhead(MatroskaDemuxContext *matroska) |
|
|
|
|
{ |
|
|
|
@ -1347,28 +1342,6 @@ matroska_execute_seekhead(MatroskaDemuxContext *matroska) |
|
|
|
|
matroska->level_up = level_up; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_attachments(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
MatroskaDemuxContext *matroska = s->priv_data; |
|
|
|
|
int i, j, res; |
|
|
|
|
|
|
|
|
|
res = ebml_parse(matroska, matroska_attachments, matroska, MATROSKA_ID_ATTACHMENTS, 0); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_parse_chapters(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
MatroskaDemuxContext *matroska = s->priv_data; |
|
|
|
|
int i, res; |
|
|
|
|
|
|
|
|
|
res = ebml_parse(matroska, matroska_chapters, matroska, MATROSKA_ID_CHAPTERS, 0); |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
matroska_aac_profile (char *codec_id) |
|
|
|
|
{ |
|
|
|
@ -1406,10 +1379,9 @@ matroska_read_header (AVFormatContext *s, |
|
|
|
|
MatroskaTrack *tracks; |
|
|
|
|
EbmlList *index_list; |
|
|
|
|
MatroskaIndex *index; |
|
|
|
|
int i, j, last_level, res = 0; |
|
|
|
|
Ebml ebml = { 0 }; |
|
|
|
|
AVStream *st; |
|
|
|
|
uint32_t id; |
|
|
|
|
int i, j; |
|
|
|
|
|
|
|
|
|
matroska->ctx = s; |
|
|
|
|
|
|
|
|
@ -1427,107 +1399,8 @@ matroska_read_header (AVFormatContext *s, |
|
|
|
|
ebml_free(ebml_syntax, &ebml); |
|
|
|
|
|
|
|
|
|
/* The next thing is a segment. */ |
|
|
|
|
while (1) { |
|
|
|
|
if (!(id = ebml_peek_id(matroska, &last_level))) |
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
if (id == MATROSKA_ID_SEGMENT) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
/* oi! */ |
|
|
|
|
av_log(matroska->ctx, AV_LOG_INFO, |
|
|
|
|
"Expected a Segment ID (0x%x), but received 0x%x!\n", |
|
|
|
|
MATROSKA_ID_SEGMENT, id); |
|
|
|
|
if ((res = ebml_read_skip(matroska)) < 0) |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* We now have a Matroska segment.
|
|
|
|
|
* Seeks are from the beginning of the segment, |
|
|
|
|
* after the segment ID/length. */ |
|
|
|
|
if ((res = ebml_read_master(matroska, &id)) < 0) |
|
|
|
|
return res; |
|
|
|
|
matroska->segment_start = url_ftell(s->pb); |
|
|
|
|
|
|
|
|
|
matroska->time_scale = 1000000; |
|
|
|
|
/* we've found our segment, start reading the different contents in here */ |
|
|
|
|
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) { |
|
|
|
|
/* stream info */ |
|
|
|
|
case MATROSKA_ID_INFO: { |
|
|
|
|
res = matroska_parse_info(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* track info headers */ |
|
|
|
|
case MATROSKA_ID_TRACKS: { |
|
|
|
|
res = matroska_parse_tracks(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* stream index */ |
|
|
|
|
case MATROSKA_ID_CUES: { |
|
|
|
|
if (!matroska->index_parsed) { |
|
|
|
|
res = matroska_parse_index(matroska); |
|
|
|
|
} else |
|
|
|
|
res = ebml_read_skip(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* metadata */ |
|
|
|
|
case MATROSKA_ID_TAGS: { |
|
|
|
|
if (!matroska->metadata_parsed) { |
|
|
|
|
res = matroska_parse_metadata(matroska); |
|
|
|
|
} else |
|
|
|
|
res = ebml_read_skip(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* file index (if seekable, seek to Cues/Tags to parse it) */ |
|
|
|
|
case MATROSKA_ID_SEEKHEAD: { |
|
|
|
|
res = matroska_parse_seekhead(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case MATROSKA_ID_ATTACHMENTS: { |
|
|
|
|
res = matroska_parse_attachments(s); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case MATROSKA_ID_CLUSTER: { |
|
|
|
|
/* Do not read the master - this will be done in the next
|
|
|
|
|
* call to matroska_read_packet. */ |
|
|
|
|
res = 1; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case MATROSKA_ID_CHAPTERS: { |
|
|
|
|
res = matroska_parse_chapters(s); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
av_log(matroska->ctx, AV_LOG_INFO, |
|
|
|
|
"Unknown matroska file header ID 0x%x\n", id); |
|
|
|
|
/* fall-through */ |
|
|
|
|
|
|
|
|
|
case EBML_ID_VOID: |
|
|
|
|
res = ebml_read_skip(matroska); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (matroska->level_up) { |
|
|
|
|
matroska->level_up--; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (ebml_parse(matroska, matroska_segments, matroska, 0, 1) < 0) |
|
|
|
|
return -1; |
|
|
|
|
matroska_execute_seekhead(matroska); |
|
|
|
|
|
|
|
|
|
/* Have we found a cluster? */ |
|
|
|
@ -1781,7 +1654,6 @@ matroska_read_header (AVFormatContext *s, |
|
|
|
|
|
|
|
|
|
/* What do we do with private data? E.g. for Vorbis. */ |
|
|
|
|
} |
|
|
|
|
res = 0; |
|
|
|
|
|
|
|
|
|
attachements = attachements_list->elem; |
|
|
|
|
for (j=0; j<attachements_list->nb_elem; j++) { |
|
|
|
@ -1834,7 +1706,7 @@ matroska_read_header (AVFormatContext *s, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
@ -2291,8 +2163,7 @@ matroska_read_close (AVFormatContext *s) |
|
|
|
|
for (n=0; n < matroska->tracks.nb_elem; n++) |
|
|
|
|
if (tracks[n].type == MATROSKA_TRACK_TYPE_AUDIO) |
|
|
|
|
av_free(tracks[n].audio.buf); |
|
|
|
|
ebml_free(matroska_tracks, matroska); |
|
|
|
|
ebml_free(matroska_index, matroska); |
|
|
|
|
ebml_free(matroska_segment, matroska); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|