📄 matroskadec.c
字号:
idx.time != (uint64_t) -1 &&
idx.track != (uint16_t) -1) {
if (matroska->num_indexes % 32 == 0) {
/* re-allocate bigger index */
matroska->index =
av_realloc(matroska->index,
(matroska->num_indexes + 32) *
sizeof(MatroskaDemuxIndex));
}
matroska->index[matroska->num_indexes] = idx;
matroska->num_indexes++;
}
break;
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown entry 0x%x in cues header\n", id);
/* fall-through */
case EBML_ID_VOID:
res = ebml_read_skip(matroska);
break;
}
if (matroska->level_up) {
matroska->level_up--;
break;
}
}
return res;
}
static int
matroska_parse_metadata (MatroskaDemuxContext *matroska)
{
int res = 0;
uint32_t id;
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) {
/* Hm, this is unsupported... */
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown entry 0x%x in metadata header\n", id);
/* fall-through */
case EBML_ID_VOID:
res = ebml_read_skip(matroska);
break;
}
if (matroska->level_up) {
matroska->level_up--;
break;
}
}
return res;
}
static int
matroska_parse_seekhead (MatroskaDemuxContext *matroska)
{
int res = 0;
uint32_t id;
av_log(matroska->ctx, AV_LOG_DEBUG, "parsing seekhead...\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) {
case MATROSKA_ID_SEEKENTRY: {
uint32_t seek_id = 0, peek_id_cache = 0;
uint64_t seek_pos = (uint64_t) -1, t;
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
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) {
case MATROSKA_ID_SEEKID:
res = ebml_read_uint(matroska, &id, &t);
seek_id = t;
break;
case MATROSKA_ID_SEEKPOSITION:
res = ebml_read_uint(matroska, &id, &seek_pos);
break;
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown seekhead 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 (!seek_id || seek_pos == (uint64_t) -1) {
av_log(matroska->ctx, AV_LOG_INFO,
"Incomplete seekhead entry (0x%x/%"PRIu64")\n",
seek_id, seek_pos);
break;
}
switch (seek_id) {
case MATROSKA_ID_CUES:
case MATROSKA_ID_TAGS: {
uint32_t level_up = matroska->level_up;
offset_t before_pos;
uint64_t length;
MatroskaLevel level;
/* remember the peeked ID and the current position */
peek_id_cache = matroska->peek_id;
before_pos = url_ftell(&matroska->ctx->pb);
/* seek */
if ((res = ebml_read_seek(matroska, seek_pos +
matroska->segment_start)) < 0)
return res;
/* we don't want to lose our seekhead level, so we add
* a dummy. This is a crude hack. */
if (matroska->num_levels == EBML_MAX_DEPTH) {
av_log(matroska->ctx, AV_LOG_INFO,
"Max EBML element depth (%d) reached, "
"cannot parse further.\n", EBML_MAX_DEPTH);
return AVERROR_UNKNOWN;
}
level.start = 0;
level.length = (uint64_t)-1;
matroska->levels[matroska->num_levels] = level;
matroska->num_levels++;
/* check ID */
if (!(id = ebml_peek_id (matroska,
&matroska->level_up)))
goto finish;
if (id != seek_id) {
av_log(matroska->ctx, AV_LOG_INFO,
"We looked for ID=0x%x but got "
"ID=0x%x (pos=%"PRIu64")",
seek_id, id, seek_pos +
matroska->segment_start);
goto finish;
}
/* read master + parse */
if ((res = ebml_read_master(matroska, &id)) < 0)
goto finish;
switch (id) {
case MATROSKA_ID_CUES:
if (!(res = matroska_parse_index(matroska)) ||
url_feof(&matroska->ctx->pb)) {
matroska->index_parsed = 1;
res = 0;
}
break;
case MATROSKA_ID_TAGS:
if (!(res = matroska_parse_metadata(matroska)) ||
url_feof(&matroska->ctx->pb)) {
matroska->metadata_parsed = 1;
res = 0;
}
break;
}
finish:
/* remove dummy level */
while (matroska->num_levels) {
matroska->num_levels--;
length =
matroska->levels[matroska->num_levels].length;
if (length == (uint64_t)-1)
break;
}
/* seek back */
if ((res = ebml_read_seek(matroska, before_pos)) < 0)
return res;
matroska->peek_id = peek_id_cache;
matroska->level_up = level_up;
break;
}
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Ignoring seekhead entry for ID=0x%x\n",
seek_id);
break;
}
break;
}
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown seekhead 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;
}
}
return res;
}
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
static int
matroska_aac_profile (char *codec_id)
{
static const char *aac_profiles[] = {
"MAIN", "LC", "SSR"
};
int profile;
for (profile=0; profile<ARRAY_SIZE(aac_profiles); profile++)
if (strstr(codec_id, aac_profiles[profile]))
break;
return profile + 1;
}
static int
matroska_aac_sri (int samplerate)
{
static const int aac_sample_rates[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000,
};
int sri;
for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++)
if (aac_sample_rates[sri] == samplerate)
break;
return sri;
}
static int
matroska_read_header (AVFormatContext *s,
AVFormatParameters *ap)
{
MatroskaDemuxContext *matroska = s->priv_data;
char *doctype;
int version, last_level, res = 0;
uint32_t id;
matroska->ctx = s;
/* First read the EBML header. */
doctype = NULL;
if ((res = ebml_read_header(matroska, &doctype, &version)) < 0)
return res;
if ((doctype == NULL) || strcmp(doctype, "matroska")) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Wrong EBML doctype ('%s' != 'matroska').\n",
doctype ? doctype : "(none)");
if (doctype)
av_free(doctype);
return AVERROR_NOFMT;
}
av_free(doctype);
if (version > 2) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Matroska demuxer version 2 too old for file version %d\n",
version);
return AVERROR_NOFMT;
}
/* 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: {
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
res = matroska_parse_info(matroska);
break;
}
/* track info headers */
case MATROSKA_ID_TRACKS: {
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
res = matroska_parse_tracks(matroska);
break;
}
/* stream index */
case MATROSKA_ID_CUES: {
if (!matroska->index_parsed) {
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
res = matroska_parse_index(matroska);
} else
res = ebml_read_skip(matroska);
break;
}
/* metadata */
case MATROSKA_ID_TAGS: {
if (!matroska->metadata_parsed) {
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
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: {
if ((res = ebml_read_master(matroska, &id)) < 0)
break;
res = matroska_parse_seekhead(matroska);
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;
}
default:
av_log(matroska->ctx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -