mirror of
https://github.com/mpv-player/mpv
synced 2024-12-24 07:33:46 +01:00
demux_mkv: use a bounded buffer for block data
Should help avoiding out-of-bounds reads.
This commit is contained in:
parent
c951010a26
commit
9f21c81633
@ -249,27 +249,27 @@ static int aac_get_sample_rate_index(uint32_t sample_rate)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
|
static bstr demux_mkv_decode(mkv_track_t *track, bstr data, uint32_t type)
|
||||||
uint8_t **dest, uint32_t *size, uint32_t type)
|
|
||||||
{
|
{
|
||||||
|
uint8_t *src = data.start;
|
||||||
uint8_t *orig_src = src;
|
uint8_t *orig_src = src;
|
||||||
|
uint8_t *dest = src;
|
||||||
*dest = src;
|
uint32_t size = data.len;
|
||||||
|
|
||||||
for (int i = 0; i < track->num_encodings; i++) {
|
for (int i = 0; i < track->num_encodings; i++) {
|
||||||
struct mkv_content_encoding *enc = track->encodings + i;
|
struct mkv_content_encoding *enc = track->encodings + i;
|
||||||
if (!(enc->scope & type))
|
if (!(enc->scope & type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (src != *dest && src != orig_src)
|
if (src != dest && src != orig_src)
|
||||||
talloc_free(src);
|
talloc_free(src);
|
||||||
src = *dest; // output from last iteration is new source
|
src = dest; // output from last iteration is new source
|
||||||
|
|
||||||
if (enc->comp_algo == 0) {
|
if (enc->comp_algo == 0) {
|
||||||
#if CONFIG_ZLIB
|
#if CONFIG_ZLIB
|
||||||
/* zlib encoded track */
|
/* zlib encoded track */
|
||||||
|
|
||||||
if (*size == 0)
|
if (size == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
z_stream zstream;
|
z_stream zstream;
|
||||||
@ -283,21 +283,21 @@ static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
zstream.next_in = (Bytef *) src;
|
zstream.next_in = (Bytef *) src;
|
||||||
zstream.avail_in = *size;
|
zstream.avail_in = size;
|
||||||
|
|
||||||
*dest = NULL;
|
dest = NULL;
|
||||||
zstream.avail_out = *size;
|
zstream.avail_out = size;
|
||||||
int result;
|
int result;
|
||||||
do {
|
do {
|
||||||
*size += 4000;
|
size += 4000;
|
||||||
*dest = talloc_realloc_size(NULL, *dest, *size);
|
dest = talloc_realloc_size(NULL, dest, size);
|
||||||
zstream.next_out = (Bytef *) (*dest + zstream.total_out);
|
zstream.next_out = (Bytef *) (dest + zstream.total_out);
|
||||||
result = inflate(&zstream, Z_NO_FLUSH);
|
result = inflate(&zstream, Z_NO_FLUSH);
|
||||||
if (result != Z_OK && result != Z_STREAM_END) {
|
if (result != Z_OK && result != Z_STREAM_END) {
|
||||||
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
||||||
"[mkv] zlib decompression failed.\n");
|
"[mkv] zlib decompression failed.\n");
|
||||||
talloc_free(*dest);
|
talloc_free(dest);
|
||||||
*dest = NULL;
|
dest = NULL;
|
||||||
inflateEnd(&zstream);
|
inflateEnd(&zstream);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -305,46 +305,47 @@ static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
|
|||||||
} while (zstream.avail_out == 4000 && zstream.avail_in != 0
|
} while (zstream.avail_out == 4000 && zstream.avail_in != 0
|
||||||
&& result != Z_STREAM_END);
|
&& result != Z_STREAM_END);
|
||||||
|
|
||||||
*size = zstream.total_out;
|
size = zstream.total_out;
|
||||||
inflateEnd(&zstream);
|
inflateEnd(&zstream);
|
||||||
#endif
|
#endif
|
||||||
} else if (enc->comp_algo == 2) {
|
} else if (enc->comp_algo == 2) {
|
||||||
/* lzo encoded track */
|
/* lzo encoded track */
|
||||||
int out_avail;
|
int out_avail;
|
||||||
int dstlen = *size * 3;
|
int dstlen = size * 3;
|
||||||
|
|
||||||
*dest = NULL;
|
dest = NULL;
|
||||||
while (1) {
|
while (1) {
|
||||||
int srclen = *size;
|
int srclen = size;
|
||||||
*dest = talloc_realloc_size(NULL, *dest,
|
dest = talloc_realloc_size(NULL, dest,
|
||||||
dstlen + AV_LZO_OUTPUT_PADDING);
|
dstlen + AV_LZO_OUTPUT_PADDING);
|
||||||
out_avail = dstlen;
|
out_avail = dstlen;
|
||||||
int result = av_lzo1x_decode(*dest, &out_avail, src, &srclen);
|
int result = av_lzo1x_decode(dest, &out_avail, src, &srclen);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
break;
|
break;
|
||||||
if (!(result & AV_LZO_OUTPUT_FULL)) {
|
if (!(result & AV_LZO_OUTPUT_FULL)) {
|
||||||
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
||||||
"[mkv] lzo decompression failed.\n");
|
"[mkv] lzo decompression failed.\n");
|
||||||
talloc_free(*dest);
|
talloc_free(dest);
|
||||||
*dest = NULL;
|
dest = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
mp_msg(MSGT_DEMUX, MSGL_DBG2,
|
mp_msg(MSGT_DEMUX, MSGL_DBG2,
|
||||||
"[mkv] lzo decompression buffer too small.\n");
|
"[mkv] lzo decompression buffer too small.\n");
|
||||||
dstlen *= 2;
|
dstlen *= 2;
|
||||||
}
|
}
|
||||||
*size = dstlen - out_avail;
|
size = dstlen - out_avail;
|
||||||
} else if (enc->comp_algo == 3) {
|
} else if (enc->comp_algo == 3) {
|
||||||
*dest = talloc_size(NULL, *size + enc->comp_settings_len);
|
dest = talloc_size(NULL, size + enc->comp_settings_len);
|
||||||
memcpy(*dest, enc->comp_settings, enc->comp_settings_len);
|
memcpy(dest, enc->comp_settings, enc->comp_settings_len);
|
||||||
memcpy(*dest + enc->comp_settings_len, src, *size);
|
memcpy(dest + enc->comp_settings_len, src, size);
|
||||||
*size += enc->comp_settings_len;
|
size += enc->comp_settings_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (src != *dest && src != orig_src)
|
if (src != dest && src != orig_src)
|
||||||
talloc_free(src);
|
talloc_free(src);
|
||||||
|
return (bstr){dest, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1616,19 +1617,17 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
|
|||||||
int sid)
|
int sid)
|
||||||
{
|
{
|
||||||
if (track->subtitle_type) {
|
if (track->subtitle_type) {
|
||||||
int size;
|
bstr in = (bstr){track->private_data, track->private_size};
|
||||||
uint8_t *buffer;
|
|
||||||
sh_sub_t *sh = new_sh_sub(demuxer, sid);
|
sh_sub_t *sh = new_sh_sub(demuxer, sid);
|
||||||
sh->gsh->demuxer_id = track->tnum;
|
sh->gsh->demuxer_id = track->tnum;
|
||||||
track->sh_sub = sh;
|
track->sh_sub = sh;
|
||||||
sh->type = track->subtitle_type;
|
sh->type = track->subtitle_type;
|
||||||
size = track->private_size;
|
bstr buffer = demux_mkv_decode(track, in, 2);
|
||||||
demux_mkv_decode(track, track->private_data, &buffer, &size, 2);
|
if (buffer.start && buffer.start != track->private_data) {
|
||||||
if (buffer && buffer != track->private_data) {
|
|
||||||
talloc_free(track->private_data);
|
talloc_free(track->private_data);
|
||||||
talloc_steal(track, buffer);
|
talloc_steal(track, buffer.start);
|
||||||
track->private_data = buffer;
|
track->private_data = buffer.start;
|
||||||
track->private_size = size;
|
track->private_size = buffer.len;
|
||||||
}
|
}
|
||||||
sh->extradata = malloc(track->private_size);
|
sh->extradata = malloc(track->private_size);
|
||||||
memcpy(sh->extradata, track->private_data, track->private_size);
|
memcpy(sh->extradata, track->private_data, track->private_size);
|
||||||
@ -1784,8 +1783,19 @@ static int demux_mkv_open(demuxer_t *demuxer)
|
|||||||
return DEMUXER_TYPE_MATROSKA;
|
return DEMUXER_TYPE_MATROSKA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
|
static bool bstr_read_u8(bstr *buffer, uint8_t *out_u8)
|
||||||
uint8_t *laces,
|
{
|
||||||
|
if (buffer->len > 0) {
|
||||||
|
*out_u8 = buffer->start[0];
|
||||||
|
buffer->len -= 1;
|
||||||
|
buffer->start += 1;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int demux_mkv_read_block_lacing(bstr *buffer, uint8_t *laces,
|
||||||
uint32_t lace_size[MAX_NUM_LACES])
|
uint32_t lace_size[MAX_NUM_LACES])
|
||||||
{
|
{
|
||||||
uint32_t total = 0;
|
uint32_t total = 0;
|
||||||
@ -1793,75 +1803,62 @@ static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* lacing flags */
|
/* lacing flags */
|
||||||
if (*size < 1)
|
if (!bstr_read_u8(buffer, &flags))
|
||||||
goto error;
|
goto error;
|
||||||
flags = *buffer++;
|
|
||||||
(*size)--;
|
|
||||||
|
|
||||||
switch ((flags & 0x06) >> 1) {
|
switch ((flags & 0x06) >> 1) {
|
||||||
case 0: /* no lacing */
|
case 0: /* no lacing */
|
||||||
*laces = 1;
|
*laces = 1;
|
||||||
lace_size[0] = *size;
|
lace_size[0] = buffer->len;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* xiph lacing */
|
case 1: /* xiph lacing */
|
||||||
case 2: /* fixed-size lacing */
|
case 2: /* fixed-size lacing */
|
||||||
case 3: /* EBML lacing */
|
case 3: /* EBML lacing */
|
||||||
if (*size < 1)
|
if (!bstr_read_u8(buffer, laces))
|
||||||
goto error;
|
goto error;
|
||||||
*laces = *buffer++;
|
|
||||||
(*size)--;
|
|
||||||
(*laces)++;
|
(*laces)++;
|
||||||
|
|
||||||
switch ((flags & 0x06) >> 1) {
|
switch ((flags & 0x06) >> 1) {
|
||||||
case 1: /* xiph lacing */
|
case 1: /* xiph lacing */
|
||||||
for (i = 0; i < *laces - 1; i++) {
|
for (i = 0; i < *laces - 1; i++) {
|
||||||
|
uint8_t t;
|
||||||
lace_size[i] = 0;
|
lace_size[i] = 0;
|
||||||
do {
|
do {
|
||||||
if (!*size)
|
if (!bstr_read_u8(buffer, &t))
|
||||||
goto error;
|
goto error;
|
||||||
lace_size[i] += *buffer;
|
lace_size[i] += t;
|
||||||
(*size)--;
|
} while (t == 0xFF);
|
||||||
} while (*buffer++ == 0xFF);
|
if (lace_size[i] > buffer->len - total || total > buffer->len)
|
||||||
if (lace_size[i] > *size - total || total > *size)
|
|
||||||
goto error;
|
goto error;
|
||||||
total += lace_size[i];
|
total += lace_size[i];
|
||||||
}
|
}
|
||||||
lace_size[i] = *size - total;
|
lace_size[i] = buffer->len - total;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* fixed-size lacing */
|
case 2: /* fixed-size lacing */
|
||||||
for (i = 0; i < *laces; i++)
|
for (i = 0; i < *laces; i++)
|
||||||
lace_size[i] = *size / *laces;
|
lace_size[i] = buffer->len / *laces;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:; /* EBML lacing */
|
case 3:; /* EBML lacing */
|
||||||
int l;
|
uint64_t num = ebml_read_vlen_uint(buffer);
|
||||||
uint64_t num = ebml_read_vlen_uint(buffer, &l);
|
|
||||||
if (num == EBML_UINT_INVALID)
|
if (num == EBML_UINT_INVALID)
|
||||||
goto error;
|
goto error;
|
||||||
buffer += l;
|
if (num > buffer->len)
|
||||||
if (*size < l)
|
|
||||||
goto error;
|
|
||||||
*size -= l;
|
|
||||||
if (num > *size)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
total = lace_size[0] = num;
|
total = lace_size[0] = num;
|
||||||
for (i = 1; i < *laces - 1; i++) {
|
for (i = 1; i < *laces - 1; i++) {
|
||||||
int64_t snum = ebml_read_vlen_int(buffer, &l);
|
int64_t snum = ebml_read_vlen_int(buffer);
|
||||||
if (snum == EBML_INT_INVALID)
|
if (snum == EBML_INT_INVALID)
|
||||||
goto error;
|
goto error;
|
||||||
buffer += l;
|
|
||||||
if (*size < l)
|
|
||||||
goto error;
|
|
||||||
*size -= l;
|
|
||||||
lace_size[i] = lace_size[i - 1] + snum;
|
lace_size[i] = lace_size[i - 1] + snum;
|
||||||
if (lace_size[i] > *size - total || total > *size)
|
if (lace_size[i] > buffer->len - total || total > buffer->len)
|
||||||
goto error;
|
goto error;
|
||||||
total += lace_size[i];
|
total += lace_size[i];
|
||||||
}
|
}
|
||||||
lace_size[i] = *size - total;
|
lace_size[i] = buffer->len - total;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1922,14 +1919,14 @@ static double real_fix_timestamp(unsigned char *buf, unsigned int timestamp, uns
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
|
static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
|
||||||
uint8_t *buffer, uint32_t size, bool keyframe)
|
bstr data, bool keyframe)
|
||||||
{
|
{
|
||||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||||
demux_packet_t *dp;
|
demux_packet_t *dp;
|
||||||
uint32_t timestamp = mkv_d->last_pts * 1000;
|
uint32_t timestamp = mkv_d->last_pts * 1000;
|
||||||
|
|
||||||
dp = new_demux_packet(size);
|
dp = new_demux_packet(data.len);
|
||||||
memcpy(dp->buffer, buffer, size);
|
memcpy(dp->buffer, data.start, data.len);
|
||||||
|
|
||||||
if (mkv_d->v_skip_to_keyframe) {
|
if (mkv_d->v_skip_to_keyframe) {
|
||||||
dp->pts = mkv_d->last_pts;
|
dp->pts = mkv_d->last_pts;
|
||||||
@ -1948,7 +1945,7 @@ static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
||||||
uint8_t *buffer, uint32_t size, bool keyframe)
|
bstr data, bool keyframe)
|
||||||
{
|
{
|
||||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||||
int sps = track->sub_packet_size;
|
int sps = track->sub_packet_size;
|
||||||
@ -1956,6 +1953,8 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|||||||
int cfs = track->coded_framesize;
|
int cfs = track->coded_framesize;
|
||||||
int w = track->audiopk_size;
|
int w = track->audiopk_size;
|
||||||
int spc = track->sub_packet_cnt;
|
int spc = track->sub_packet_cnt;
|
||||||
|
uint8_t *buffer = data.start;
|
||||||
|
uint32_t size = data.len;
|
||||||
demux_packet_t *dp;
|
demux_packet_t *dp;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
@ -2054,19 +2053,19 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct block_info {
|
struct block_info {
|
||||||
uint64_t length;
|
|
||||||
uint64_t duration;
|
uint64_t duration;
|
||||||
bool simple, keyframe;
|
bool simple, keyframe;
|
||||||
uint64_t timecode;
|
uint64_t timecode;
|
||||||
mkv_track_t *track;
|
mkv_track_t *track;
|
||||||
uint8_t *data;
|
bstr data;
|
||||||
void *alloc;
|
void *alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_block(struct block_info *block)
|
static void free_block(struct block_info *block)
|
||||||
{
|
{
|
||||||
free(block->alloc);
|
free(block->alloc);
|
||||||
block->data = block->alloc = NULL;
|
block->alloc = NULL;
|
||||||
|
block->data = (bstr){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void index_block(demuxer_t *demuxer, struct block_info *block)
|
static void index_block(demuxer_t *demuxer, struct block_info *block)
|
||||||
@ -2082,29 +2081,34 @@ static int read_block(demuxer_t *demuxer, struct block_info *block)
|
|||||||
{
|
{
|
||||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||||
stream_t *s = demuxer->stream;
|
stream_t *s = demuxer->stream;
|
||||||
int tmp, num;
|
int num;
|
||||||
int16_t time;
|
int16_t time;
|
||||||
|
uint64_t length;
|
||||||
int res = -1;
|
int res = -1;
|
||||||
|
|
||||||
free_block(block);
|
free_block(block);
|
||||||
block->length = ebml_read_length(s, NULL);
|
length = ebml_read_length(s, NULL);
|
||||||
if (block->length < 6 || block->length > 500000000)
|
if (length > 500000000)
|
||||||
goto exit;
|
goto exit;
|
||||||
block->data = block->alloc = malloc(block->length + AV_LZO_INPUT_PADDING);
|
block->alloc = malloc(length + AV_LZO_INPUT_PADDING);
|
||||||
|
block->data = (bstr){block->alloc, length};
|
||||||
demuxer->filepos = stream_tell(s);
|
demuxer->filepos = stream_tell(s);
|
||||||
if (stream_read(s, block->data, block->length) != (int) block->length)
|
if (stream_read(s, block->data.start, block->data.len) != block->data.len)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
// Parse header of the Block element
|
// Parse header of the Block element
|
||||||
/* first byte(s): track num */
|
/* first byte(s): track num */
|
||||||
num = ebml_read_vlen_uint(block->data, &tmp);
|
num = ebml_read_vlen_uint(&block->data);
|
||||||
block->data += tmp;
|
if (num == EBML_UINT_INVALID)
|
||||||
|
goto exit;
|
||||||
/* time (relative to cluster time) */
|
/* time (relative to cluster time) */
|
||||||
time = block->data[0] << 8 | block->data[1];
|
if (block->data.len < 3)
|
||||||
block->data += 2;
|
goto exit;
|
||||||
block->length -= tmp + 2;
|
time = block->data.start[0] << 8 | block->data.start[1];
|
||||||
|
block->data.start += 2;
|
||||||
|
block->data.len -= 2;
|
||||||
if (block->simple)
|
if (block->simple)
|
||||||
block->keyframe = block->data[0] & 0x80;
|
block->keyframe = block->data.start[0] & 0x80;
|
||||||
block->timecode = time * mkv_d->tc_scale + mkv_d->cluster_tc;
|
block->timecode = time * mkv_d->tc_scale + mkv_d->cluster_tc;
|
||||||
for (int i = 0; i < mkv_d->num_tracks; i++) {
|
for (int i = 0; i < mkv_d->num_tracks; i++) {
|
||||||
if (mkv_d->tracks[i]->tnum == num) {
|
if (mkv_d->tracks[i]->tnum == num) {
|
||||||
@ -2128,22 +2132,18 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
|
|||||||
{
|
{
|
||||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||||
demux_stream_t *ds = NULL;
|
demux_stream_t *ds = NULL;
|
||||||
uint64_t old_length;
|
|
||||||
uint8_t laces;
|
uint8_t laces;
|
||||||
int i, use_this_block = 1;
|
int i, use_this_block = 1;
|
||||||
double current_pts;
|
double current_pts;
|
||||||
uint8_t *block = block_info->data;
|
bstr data = block_info->data;
|
||||||
uint64_t length = block_info->length;
|
|
||||||
bool keyframe = block_info->keyframe;
|
bool keyframe = block_info->keyframe;
|
||||||
uint64_t block_duration = block_info->duration;
|
uint64_t block_duration = block_info->duration;
|
||||||
uint64_t tc = block_info->timecode;
|
uint64_t tc = block_info->timecode;
|
||||||
mkv_track_t *track = block_info->track;
|
mkv_track_t *track = block_info->track;
|
||||||
uint32_t lace_size[MAX_NUM_LACES];
|
uint32_t lace_size[MAX_NUM_LACES];
|
||||||
|
|
||||||
old_length = length;
|
if (demux_mkv_read_block_lacing(&data, &laces, lace_size))
|
||||||
if (demux_mkv_read_block_lacing(block, &length, &laces, lace_size))
|
|
||||||
return 0;
|
return 0;
|
||||||
block += old_length - length;
|
|
||||||
|
|
||||||
current_pts = tc / 1e9;
|
current_pts = tc / 1e9;
|
||||||
|
|
||||||
@ -2160,12 +2160,12 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
|
|||||||
sh_audio_t *sh = (sh_audio_t *) ds->sh;
|
sh_audio_t *sh = (sh_audio_t *) ds->sh;
|
||||||
|
|
||||||
if (block_duration != 0) {
|
if (block_duration != 0) {
|
||||||
sh->i_bps = length * 1e9 / block_duration;
|
sh->i_bps = data.len * 1e9 / block_duration;
|
||||||
track->fix_i_bps = 0;
|
track->fix_i_bps = 0;
|
||||||
} else if (track->qt_last_a_pts == 0.0)
|
} else if (track->qt_last_a_pts == 0.0)
|
||||||
track->qt_last_a_pts = current_pts;
|
track->qt_last_a_pts = current_pts;
|
||||||
else if (track->qt_last_a_pts != current_pts) {
|
else if (track->qt_last_a_pts != current_pts) {
|
||||||
sh->i_bps = length / (current_pts - track->qt_last_a_pts);
|
sh->i_bps = data.len / (current_pts - track->qt_last_a_pts);
|
||||||
track->fix_i_bps = 0;
|
track->fix_i_bps = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2196,22 +2196,19 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
|
|||||||
mkv_d->last_filepos = demuxer->filepos;
|
mkv_d->last_filepos = demuxer->filepos;
|
||||||
|
|
||||||
for (i = 0; i < laces; i++) {
|
for (i = 0; i < laces; i++) {
|
||||||
|
bstr block = bstr_splice(data, 0, lace_size[i]);
|
||||||
if (ds == demuxer->video && track->realmedia)
|
if (ds == demuxer->video && track->realmedia)
|
||||||
handle_realvideo(demuxer, track, block, lace_size[i],
|
handle_realvideo(demuxer, track, block, keyframe);
|
||||||
keyframe);
|
|
||||||
else if (ds == demuxer->audio && track->realmedia)
|
else if (ds == demuxer->audio && track->realmedia)
|
||||||
handle_realaudio(demuxer, track, block, lace_size[i],
|
handle_realaudio(demuxer, track, block, keyframe);
|
||||||
keyframe);
|
|
||||||
else {
|
else {
|
||||||
int size = lace_size[i];
|
|
||||||
demux_packet_t *dp;
|
demux_packet_t *dp;
|
||||||
uint8_t *buffer;
|
bstr buffer = demux_mkv_decode(track, block, 1);
|
||||||
demux_mkv_decode(track, block, &buffer, &size, 1);
|
if (buffer.start) {
|
||||||
if (buffer) {
|
dp = new_demux_packet(buffer.len);
|
||||||
dp = new_demux_packet(size);
|
memcpy(dp->buffer, buffer.start, buffer.len);
|
||||||
memcpy(dp->buffer, buffer, size);
|
if (buffer.start != block.start)
|
||||||
if (buffer != block)
|
talloc_free(buffer.start);
|
||||||
talloc_free(buffer);
|
|
||||||
dp->keyframe = keyframe;
|
dp->keyframe = keyframe;
|
||||||
/* If default_duration is 0, assume no pts value is known
|
/* If default_duration is 0, assume no pts value is known
|
||||||
* for packets after the first one (rather than all pts
|
* for packets after the first one (rather than all pts
|
||||||
@ -2223,7 +2220,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
|
|||||||
ds_add_packet(ds, dp);
|
ds_add_packet(ds, dp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block += lace_size[i];
|
data = bstr_cut(data, lace_size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds == demuxer->video) {
|
if (ds == demuxer->video) {
|
||||||
@ -2278,7 +2275,7 @@ static int read_block_group(demuxer_t *demuxer, int64_t end,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return block->data ? 1 : 0;
|
return block->data.start ? 1 : 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
free_block(block);
|
free_block(block);
|
||||||
|
25
demux/ebml.c
25
demux/ebml.c
@ -64,44 +64,49 @@ uint32_t ebml_read_id(stream_t *s, int *length)
|
|||||||
/*
|
/*
|
||||||
* Read a variable length unsigned int.
|
* Read a variable length unsigned int.
|
||||||
*/
|
*/
|
||||||
uint64_t ebml_read_vlen_uint(uint8_t *buffer, int *length)
|
uint64_t ebml_read_vlen_uint(bstr *buffer)
|
||||||
{
|
{
|
||||||
int i, j, num_ffs = 0, len_mask = 0x80;
|
int i, j, num_ffs = 0, len_mask = 0x80;
|
||||||
uint64_t num;
|
uint64_t num;
|
||||||
|
|
||||||
for (i = 0, num = *buffer++; i < 8 && !(num & len_mask); i++)
|
if (buffer->len == 0)
|
||||||
|
return EBML_UINT_INVALID;
|
||||||
|
|
||||||
|
for (i = 0, num = buffer->start[0]; i < 8 && !(num & len_mask); i++)
|
||||||
len_mask >>= 1;
|
len_mask >>= 1;
|
||||||
if (i >= 8)
|
if (i >= 8)
|
||||||
return EBML_UINT_INVALID;
|
return EBML_UINT_INVALID;
|
||||||
j = i + 1;
|
j = i + 1;
|
||||||
if (length)
|
|
||||||
*length = j;
|
|
||||||
if ((int) (num &= (len_mask - 1)) == len_mask - 1)
|
if ((int) (num &= (len_mask - 1)) == len_mask - 1)
|
||||||
num_ffs++;
|
num_ffs++;
|
||||||
while (i--) {
|
if (j > buffer->len)
|
||||||
num = (num << 8) | *buffer++;
|
return EBML_UINT_INVALID;
|
||||||
|
for (int n = 0; n < i; n++) {
|
||||||
|
num = (num << 8) | buffer->start[n + 1];
|
||||||
if ((num & 0xFF) == 0xFF)
|
if ((num & 0xFF) == 0xFF)
|
||||||
num_ffs++;
|
num_ffs++;
|
||||||
}
|
}
|
||||||
if (j == num_ffs)
|
if (j == num_ffs)
|
||||||
return EBML_UINT_INVALID;
|
return EBML_UINT_INVALID;
|
||||||
|
buffer->start += j;
|
||||||
|
buffer->len -= j;
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a variable length signed int.
|
* Read a variable length signed int.
|
||||||
*/
|
*/
|
||||||
int64_t ebml_read_vlen_int(uint8_t *buffer, int *length)
|
int64_t ebml_read_vlen_int(bstr *buffer)
|
||||||
{
|
{
|
||||||
uint64_t unum;
|
uint64_t unum;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
/* read as unsigned number first */
|
/* read as unsigned number first */
|
||||||
unum = ebml_read_vlen_uint(buffer, &l);
|
size_t len = buffer->len;
|
||||||
|
unum = ebml_read_vlen_uint(buffer);
|
||||||
if (unum == EBML_UINT_INVALID)
|
if (unum == EBML_UINT_INVALID)
|
||||||
return EBML_INT_INVALID;
|
return EBML_INT_INVALID;
|
||||||
if (length)
|
l = len - buffer->len;
|
||||||
*length = l;
|
|
||||||
|
|
||||||
return unum - ((1 << ((7 * l) - 1)) - 1);
|
return unum - ((1 << ((7 * l) - 1)) - 1);
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,8 @@ struct ebml_parse_ctx {
|
|||||||
|
|
||||||
|
|
||||||
uint32_t ebml_read_id (stream_t *s, int *length);
|
uint32_t ebml_read_id (stream_t *s, int *length);
|
||||||
uint64_t ebml_read_vlen_uint (uint8_t *buffer, int *length);
|
uint64_t ebml_read_vlen_uint (bstr *buffer);
|
||||||
int64_t ebml_read_vlen_int (uint8_t *buffer, int *length);
|
int64_t ebml_read_vlen_int (bstr *buffer);
|
||||||
uint64_t ebml_read_length (stream_t *s, int *length);
|
uint64_t ebml_read_length (stream_t *s, int *length);
|
||||||
uint64_t ebml_read_uint (stream_t *s, uint64_t *length);
|
uint64_t ebml_read_uint (stream_t *s, uint64_t *length);
|
||||||
int64_t ebml_read_int (stream_t *s, uint64_t *length);
|
int64_t ebml_read_int (stream_t *s, uint64_t *length);
|
||||||
|
Loading…
Reference in New Issue
Block a user