matroskadec: split laces parsing

release/1.0
Luca Barbato 13 years ago
parent 117d8c6d1f
commit 2d0e7713f9
  1. 181
      libavformat/matroskadec.c

@ -1749,89 +1749,40 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska)
}
}
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t duration, int is_keyframe,
int64_t cluster_pos)
static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
int size, int type,
uint32_t **lace_buf, int *laces)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
int res = 0;
AVStream *st;
AVPacket *pkt;
int16_t block_time;
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
uint64_t num;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
return n;
}
data += n;
size -= n;
int res = 0, n;
uint8_t *data = *buf;
uint32_t *lace_size;
if (!type) {
*laces = 1;
*lace_buf = av_mallocz(sizeof(int));
if (!*lace_buf)
return AVERROR(ENOMEM);
track = matroska_find_track_by_num(matroska, num);
if (!track || !track->stream) {
av_log(matroska->ctx, AV_LOG_INFO,
"Invalid stream %"PRIu64" or size %u\n", num, size);
return AVERROR_INVALIDDATA;
} else if (size <= 3)
*lace_buf[0] = size;
return 0;
st = track->stream;
if (st->discard >= AVDISCARD_ALL)
return res;
if (duration == AV_NOPTS_VALUE)
duration = track->default_duration / matroska->time_scale;
block_time = AV_RB16(data);
data += 2;
flags = *data++;
size -= 3;
if (is_keyframe == -1)
is_keyframe = flags & 0x80 ? AV_PKT_FLAG_KEY : 0;
if (cluster_time != (uint64_t)-1
&& (block_time >= 0 || cluster_time >= -block_time)) {
timecode = cluster_time + block_time;
if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE
&& timecode < track->end_timecode)
is_keyframe = 0; /* overlapping subtitles are not key frame */
if (is_keyframe)
av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME);
track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
}
if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
if (!is_keyframe || timecode < matroska->skip_to_timecode)
return res;
matroska->skip_to_keyframe = 0;
}
switch ((flags & 0x06) >> 1) {
case 0x0: /* no lacing */
laces = 1;
lace_size = av_mallocz(sizeof(int));
lace_size[0] = size;
break;
case 0x1: /* Xiph lacing */
case 0x2: /* fixed-size lacing */
case 0x3: /* EBML lacing */
assert(size>0); // size <=3 is checked before size-=3 above
laces = (*data) + 1;
assert(size > 0);
*laces = *data + 1;
data += 1;
size -= 1;
lace_size = av_mallocz(laces * sizeof(int));
lace_size = av_mallocz(*laces * sizeof(int));
if (!lace_size)
return AVERROR(ENOMEM);
switch ((flags & 0x06) >> 1) {
switch (type) {
case 0x1: /* Xiph lacing */ {
uint8_t temp;
uint32_t total = 0;
for (n = 0; res == 0 && n < laces - 1; n++) {
for (n = 0; res == 0 && n < *laces - 1; n++) {
while (1) {
if (size == 0) {
res = -1;
res = AVERROR_EOF;
break;
}
temp = *data;
@ -1845,34 +1796,36 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
}
if (size <= total) {
res = AVERROR_INVALIDDATA;
goto end;
break;
}
lace_size[n] = size - total;
break;
}
case 0x2: /* fixed-size lacing */
if (size != (size / laces) * size) {
if (size != (size / *laces) * size) {
res = AVERROR_INVALIDDATA;
goto end;
break;
}
for (n = 0; n < laces; n++)
lace_size[n] = size / laces;
for (n = 0; n < *laces; n++)
lace_size[n] = size / *laces;
break;
case 0x3: /* EBML lacing */ {
uint64_t num;
uint32_t total;
n = matroska_ebmlnum_uint(matroska, data, size, &num);
if (n < 0) {
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
res = n;
goto end;
break;
}
data += n;
size -= n;
total = lace_size[0] = num;
for (n = 1; res == 0 && n < laces - 1; n++) {
for (n = 1; res == 0 && n < *laces - 1; n++) {
int64_t snum;
int r;
r = matroska_ebmlnum_sint(matroska, data, size, &snum);
@ -1880,7 +1833,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
res = r;
goto end;
break;
}
data += r;
size -= r;
@ -1889,14 +1842,80 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
}
if (size <= total) {
res = AVERROR_INVALIDDATA;
goto end;
break;
}
lace_size[laces - 1] = size - total;
lace_size[*laces - 1] = size - total;
break;
}
}
break;
*buf = data;
*lace_buf = lace_size;
return res;
}
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t duration, int is_keyframe,
int64_t cluster_pos)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
int res = 0;
AVStream *st;
AVPacket *pkt;
int16_t block_time;
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
uint64_t num;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
return n;
}
data += n;
size -= n;
track = matroska_find_track_by_num(matroska, num);
if (!track || !track->stream) {
av_log(matroska->ctx, AV_LOG_INFO,
"Invalid stream %"PRIu64" or size %u\n", num, size);
return AVERROR_INVALIDDATA;
} else if (size <= 3)
return 0;
st = track->stream;
if (st->discard >= AVDISCARD_ALL)
return res;
if (duration == AV_NOPTS_VALUE)
duration = track->default_duration / matroska->time_scale;
block_time = AV_RB16(data);
data += 2;
flags = *data++;
size -= 3;
if (is_keyframe == -1)
is_keyframe = flags & 0x80 ? AV_PKT_FLAG_KEY : 0;
if (cluster_time != (uint64_t)-1
&& (block_time >= 0 || cluster_time >= -block_time)) {
timecode = cluster_time + block_time;
if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE
&& timecode < track->end_timecode)
is_keyframe = 0; /* overlapping subtitles are not key frame */
if (is_keyframe)
av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME);
track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
}
if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
if (!is_keyframe || timecode < matroska->skip_to_timecode)
return res;
matroska->skip_to_keyframe = 0;
}
res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1,
&lace_size, &laces);
if (res == 0) {
for (n = 0; n < laces; n++) {

Loading…
Cancel
Save