diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-09-20 20:37:26 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-09-20 20:39:47 +0200 |
commit | 8c51ea54897c2d8671b38efecc1422ad4ad344f9 (patch) | |
tree | 5db81f5cb6c19150fe84252d8636c83c40b140fb /libavformat | |
parent | b8044972c4f23e2d2fdf2c5a8ba67019a5045149 (diff) | |
parent | c831ebf61629d219ebcaa9f02d262e67aad09d83 (diff) | |
download | ffmpeg-8c51ea54897c2d8671b38efecc1422ad4ad344f9.tar.gz |
Merge commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83'
* commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83':
matroskadec: split frame parsing
matroskadec: split laces parsing
Conflicts:
libavformat/matroskadec.c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/matroskadec.c | 541 |
1 files changed, 294 insertions, 247 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index bc0f72863b..eb34ef4ee9 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1884,6 +1884,266 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska) } } +static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, + int size, int type, + uint32_t **lace_buf, int *laces) +{ + 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); + + *lace_buf[0] = size; + return 0; + } + + av_assert0(size > 0); + *laces = *data + 1; + data += 1; + size -= 1; + lace_size = av_mallocz(*laces * sizeof(int)); + if (!lace_size) + return AVERROR(ENOMEM); + + switch (type) { + case 0x1: /* Xiph lacing */ { + uint8_t temp; + uint32_t total = 0; + for (n = 0; res == 0 && n < *laces - 1; n++) { + while (1) { + if (size == 0) { + res = AVERROR_EOF; + break; + } + temp = *data; + lace_size[n] += temp; + data += 1; + size -= 1; + if (temp != 0xff) + break; + } + total += lace_size[n]; + } + if (size <= total) { + res = AVERROR_INVALIDDATA; + break; + } + + lace_size[n] = size - total; + break; + } + + case 0x2: /* fixed-size lacing */ + if (size != (size / *laces) * *laces) { + res = AVERROR_INVALIDDATA; + break; + } + 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; + break; + } + data += n; + size -= n; + total = lace_size[0] = num; + for (n = 1; res == 0 && n < *laces - 1; n++) { + int64_t snum; + int r; + r = matroska_ebmlnum_sint(matroska, data, size, &snum); + if (r < 0) { + av_log(matroska->ctx, AV_LOG_INFO, + "EBML block data error\n"); + res = r; + break; + } + data += r; + size -= r; + lace_size[n] = lace_size[n - 1] + snum; + total += lace_size[n]; + } + if (size <= total) { + res = AVERROR_INVALIDDATA; + break; + } + lace_size[*laces - 1] = size - total; + break; + } + } + + *buf = data; + *lace_buf = lace_size; + + return res; +} + +static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, + MatroskaTrack *track, + AVStream *st, + uint8_t *data, int size, + uint64_t timecode, uint64_t duration, + int64_t pos) +{ + int a = st->codec->block_align; + int sps = track->audio.sub_packet_size; + int cfs = track->audio.coded_framesize; + int h = track->audio.sub_packet_h; + int y = track->audio.sub_packet_cnt; + int w = track->audio.frame_size; + int x; + + if (!track->audio.pkt_cnt) { + if (track->audio.sub_packet_cnt == 0) + track->audio.buf_timecode = timecode; + if (st->codec->codec_id == AV_CODEC_ID_RA_288) { + if (size < cfs * h / 2) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Corrupt int4 RM-style audio packet size\n"); + return AVERROR_INVALIDDATA; + } + for (x=0; x<h/2; x++) + memcpy(track->audio.buf+x*2*w+y*cfs, + data+x*cfs, cfs); + } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) { + if (size < w) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Corrupt sipr RM-style audio packet size\n"); + return AVERROR_INVALIDDATA; + } + memcpy(track->audio.buf + y*w, data, w); + } else { + if (size < sps * w / sps) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Corrupt generic RM-style audio packet size\n"); + return AVERROR_INVALIDDATA; + } + for (x=0; x<w/sps; x++) + memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); + } + + if (++track->audio.sub_packet_cnt >= h) { + if (st->codec->codec_id == AV_CODEC_ID_SIPR) + ff_rm_reorder_sipr_data(track->audio.buf, h, w); + track->audio.sub_packet_cnt = 0; + track->audio.pkt_cnt = h*w / a; + } + } + + while (track->audio.pkt_cnt) { + AVPacket *pkt = av_mallocz(sizeof(AVPacket)); + av_new_packet(pkt, a); + memcpy(pkt->data, track->audio.buf + + a * (h*w / a - track->audio.pkt_cnt--), a); + pkt->pts = track->audio.buf_timecode; + track->audio.buf_timecode = AV_NOPTS_VALUE; + pkt->pos = pos; + pkt->stream_index = st->index; + dynarray_add(&matroska->packets,&matroska->num_packets,pkt); + } + + return 0; +} +static int matroska_parse_frame(MatroskaDemuxContext *matroska, + MatroskaTrack *track, + AVStream *st, + uint8_t *data, int pkt_size, + uint64_t timecode, uint64_t lace_duration, + int64_t pos, int is_keyframe) +{ + MatroskaTrackEncoding *encodings = track->encodings.elem; + uint8_t *pkt_data = data; + int offset = 0, res; + AVPacket *pkt; + + if (encodings && encodings->scope & 1) { + res = matroska_decode_buffer(&pkt_data, &pkt_size, track); + if (res < 0) + return res; + } + + if (st->codec->codec_id == AV_CODEC_ID_PRORES) + offset = 8; + + pkt = av_mallocz(sizeof(AVPacket)); + /* XXX: prevent data copy... */ + if (av_new_packet(pkt, pkt_size + offset) < 0) { + av_free(pkt); + return AVERROR(ENOMEM); + } + + if (st->codec->codec_id == AV_CODEC_ID_PRORES) { + uint8_t *buf = pkt->data; + bytestream_put_be32(&buf, pkt_size); + bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f')); + } + + memcpy(pkt->data + offset, pkt_data, pkt_size); + + if (pkt_data != data) + av_free(pkt_data); + + pkt->flags = is_keyframe; + pkt->stream_index = st->index; + + if (track->ms_compat) + pkt->dts = timecode; + else + pkt->pts = timecode; + pkt->pos = pos; + if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) { + /* + * For backward compatibility. + * Historically, we have put subtitle duration + * in convergence_duration, on the off chance + * that the time_scale is less than 1us, which + * could result in a 32bit overflow on the + * normal duration field. + */ + pkt->convergence_duration = lace_duration; + } + + if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE || + lace_duration <= INT_MAX) { + /* + * For non subtitle tracks, just store the duration + * as normal. + * + * If it's a subtitle track and duration value does + * not overflow a uint32, then also store it normally. + */ + pkt->duration = lace_duration; + } + + if (st->codec->codec_id == AV_CODEC_ID_SSA) + matroska_fix_ass_packet(matroska, pkt, lace_duration); + + if (matroska->prev_pkt && + timecode != AV_NOPTS_VALUE && + matroska->prev_pkt->pts == timecode && + matroska->prev_pkt->stream_index == st->index && + st->codec->codec_id == AV_CODEC_ID_SSA) + matroska_merge_packets(matroska->prev_pkt, pkt); + else { + dynarray_add(&matroska->packets,&matroska->num_packets,pkt); + matroska->prev_pkt = pkt; + } + + return 0; +} + 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, @@ -1893,7 +2153,6 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, MatroskaTrack *track; int res = 0; AVStream *st; - AVPacket *pkt; int16_t block_time; uint32_t *lace_size = NULL; int n, flags, laces = 0; @@ -1946,261 +2205,49 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, 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; + res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1, + &lace_size, &laces); - case 0x1: /* Xiph lacing */ - case 0x2: /* fixed-size lacing */ - case 0x3: /* EBML lacing */ - av_assert0(size>0); // size <=3 is checked before size-=3 above - laces = (*data) + 1; - data += 1; - size -= 1; - lace_size = av_mallocz(laces * sizeof(int)); - - switch ((flags & 0x06) >> 1) { - case 0x1: /* Xiph lacing */ { - uint8_t temp; - uint32_t total = 0; - for (n = 0; res == 0 && n < laces - 1; n++) { - while (1) { - if (size == 0) { - res = -1; - break; - } - temp = *data; - lace_size[n] += temp; - data += 1; - size -= 1; - if (temp != 0xff) - break; - } - total += lace_size[n]; - } - if (size <= total) { - res = AVERROR_INVALIDDATA; - goto end; - } - lace_size[n] = size - total; - break; - } + if (res) + goto end; - case 0x2: /* fixed-size lacing */ - if (size != (size / laces) * laces) { - res = AVERROR_INVALIDDATA; - goto end; - } - for (n = 0; n < laces; n++) - lace_size[n] = size / laces; - break; + if (!duration) + duration = track->default_duration * laces / matroska->time_scale; - case 0x3: /* EBML lacing */ { - 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; - } - data += n; - size -= n; - total = lace_size[0] = num; - for (n = 1; res == 0 && n < laces - 1; n++) { - int64_t snum; - int r; - r = matroska_ebmlnum_sint(matroska, data, size, &snum); - if (r < 0) { - av_log(matroska->ctx, AV_LOG_INFO, - "EBML block data error\n"); - res = r; - goto end; - } - data += r; - size -= r; - lace_size[n] = lace_size[n - 1] + snum; - total += lace_size[n]; - } - if (size <= total) { - res = AVERROR_INVALIDDATA; - goto end; - } - lace_size[laces - 1] = size - total; - break; - } - } - break; - } - - if (res == 0) { - if (!duration) - duration = track->default_duration * laces / matroska->time_scale; - - if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time)) - track->end_timecode = FFMAX(track->end_timecode, timecode+duration); - - for (n = 0; n < laces; n++) { - int64_t lace_duration = duration*(n+1) / laces - duration*n / laces; - - if (lace_size[n] > size) { - av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n"); - break; - } - - if ((st->codec->codec_id == AV_CODEC_ID_RA_288 || - st->codec->codec_id == AV_CODEC_ID_COOK || - st->codec->codec_id == AV_CODEC_ID_SIPR || - st->codec->codec_id == AV_CODEC_ID_ATRAC3) && - st->codec->block_align && track->audio.sub_packet_size) { - int a = st->codec->block_align; - int sps = track->audio.sub_packet_size; - int cfs = track->audio.coded_framesize; - int h = track->audio.sub_packet_h; - int y = track->audio.sub_packet_cnt; - int w = track->audio.frame_size; - int x; - - if (!track->audio.pkt_cnt) { - if (track->audio.sub_packet_cnt == 0) - track->audio.buf_timecode = timecode; - if (st->codec->codec_id == AV_CODEC_ID_RA_288) { - if (size < cfs * h / 2) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Corrupt int4 RM-style audio packet size\n"); - res = AVERROR_INVALIDDATA; - goto end; - } - for (x=0; x<h/2; x++) - memcpy(track->audio.buf+x*2*w+y*cfs, - data+x*cfs, cfs); - } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) { - if (size < w) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Corrupt sipr RM-style audio packet size\n"); - res = AVERROR_INVALIDDATA; - goto end; - } - memcpy(track->audio.buf + y*w, data, w); - } else { - if (size < sps * w / sps) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Corrupt generic RM-style audio packet size\n"); - res = AVERROR_INVALIDDATA; - goto end; - } - for (x=0; x<w/sps; x++) - memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); - } - - if (++track->audio.sub_packet_cnt >= h) { - if (st->codec->codec_id == AV_CODEC_ID_SIPR) - ff_rm_reorder_sipr_data(track->audio.buf, h, w); - track->audio.sub_packet_cnt = 0; - track->audio.pkt_cnt = h*w / a; - } - } - while (track->audio.pkt_cnt) { - pkt = av_mallocz(sizeof(AVPacket)); - av_new_packet(pkt, a); - memcpy(pkt->data, track->audio.buf - + a * (h*w / a - track->audio.pkt_cnt--), a); - pkt->pts = track->audio.buf_timecode; - track->audio.buf_timecode = AV_NOPTS_VALUE; - pkt->pos = pos; - pkt->stream_index = st->index; - dynarray_add(&matroska->packets,&matroska->num_packets,pkt); - } - } else { - MatroskaTrackEncoding *encodings = track->encodings.elem; - uint32_t pkt_size = lace_size[n]; - uint8_t *pkt_data = data; - int offset = 0; - - if (encodings && encodings->scope & 1) { - res = matroska_decode_buffer(&pkt_data, &pkt_size, track); - if (res < 0) - break; - } - - if (st->codec->codec_id == AV_CODEC_ID_PRORES) - offset = 8; - - pkt = av_mallocz(sizeof(AVPacket)); - /* XXX: prevent data copy... */ - if (av_new_packet(pkt, pkt_size + offset) < 0) { - av_free(pkt); - res = AVERROR(ENOMEM); - break; - } + if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time)) + track->end_timecode = FFMAX(track->end_timecode, timecode+duration); - if (st->codec->codec_id == AV_CODEC_ID_PRORES) { - uint8_t *buf = pkt->data; - bytestream_put_be32(&buf, pkt_size); - bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f')); - } + for (n = 0; n < laces; n++) { + int64_t lace_duration = duration*(n+1) / laces - duration*n / laces; - memcpy(pkt->data + offset, pkt_data, pkt_size); - - if (pkt_data != data) - av_free(pkt_data); - - if (n == 0) - pkt->flags = is_keyframe; - pkt->stream_index = st->index; - - if (track->ms_compat) - pkt->dts = timecode; - else - pkt->pts = timecode; - pkt->pos = pos; - if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) { - /* - * For backward compatibility. - * Historically, we have put subtitle duration - * in convergence_duration, on the off chance - * that the time_scale is less than 1us, which - * could result in a 32bit overflow on the - * normal duration field. - */ - pkt->convergence_duration = lace_duration; - } + if (lace_size[n] > size) { + av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n"); + break; + } - if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE || - lace_duration <= INT_MAX) { - /* - * For non subtitle tracks, just store the duration - * as normal. - * - * If it's a subtitle track and duration value does - * not overflow a uint32, then also store it normally. - */ - pkt->duration = lace_duration; - } + if ((st->codec->codec_id == AV_CODEC_ID_RA_288 || + st->codec->codec_id == AV_CODEC_ID_COOK || + st->codec->codec_id == AV_CODEC_ID_SIPR || + st->codec->codec_id == AV_CODEC_ID_ATRAC3) && + st->codec->block_align && track->audio.sub_packet_size) { - if (st->codec->codec_id == AV_CODEC_ID_SSA) - matroska_fix_ass_packet(matroska, pkt, lace_duration); - - if (matroska->prev_pkt && - timecode != AV_NOPTS_VALUE && - matroska->prev_pkt->pts == timecode && - matroska->prev_pkt->stream_index == st->index && - st->codec->codec_id == AV_CODEC_ID_SSA) - matroska_merge_packets(matroska->prev_pkt, pkt); - else { - dynarray_add(&matroska->packets,&matroska->num_packets,pkt); - matroska->prev_pkt = pkt; - } - } + res = matroska_parse_rm_audio(matroska, track, st, data, size, + timecode, duration, pos); + if (res) + goto end; - if (timecode != AV_NOPTS_VALUE) - timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE; - data += lace_size[n]; - size -= lace_size[n]; + } else { + res = matroska_parse_frame(matroska, track, st, data, lace_size[n], + timecode, lace_duration, + pos, !n? is_keyframe : 0); + if (res) + goto end; } + + if (timecode != AV_NOPTS_VALUE) + timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE; + data += lace_size[n]; + size -= lace_size[n]; } end: |