From: Michael Niedermayer Date: Thu, 20 Sep 2012 18:37:26 +0000 (+0200) Subject: Merge commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83' X-Git-Tag: n1.1-dev~134 X-Git-Url: http://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff_plain/8c51ea54897c2d8671b38efecc1422ad4ad344f9 Merge commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83' * commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83': matroskadec: split frame parsing matroskadec: split laces parsing Conflicts: libavformat/matroskadec.c Merged-by: Michael Niedermayer --- 8c51ea54897c2d8671b38efecc1422ad4ad344f9 diff --cc libavformat/matroskadec.c index bc0f728,c75df51..eb34ef4 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@@ -1884,6 -1749,247 +1884,266 @@@ static void matroska_clear_queue(Matros } } + 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; + } + - assert(size > 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) * size) { ++ 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; xaudio.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; xaudio.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 duration, ++ 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_TEXT) - pkt->convergence_duration = duration; - else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE) - pkt->duration = duration; ++ 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, duration); ++ 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, @@@ -1936,271 -2042,42 +2195,59 @@@ } if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { - if (!is_keyframe || timecode < matroska->skip_to_timecode) + if (timecode < matroska->skip_to_timecode) return res; - matroska->skip_to_keyframe = 0; + if (!st->skip_to_keyframe) { + av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n"); + matroska->skip_to_keyframe = 0; + } + if (is_keyframe) + 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; xaudio.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; xaudio.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, duration, ++ timecode, lace_duration, + pos, !n? is_keyframe : 0); + if (res) + goto end; } + + if (timecode != AV_NOPTS_VALUE) - timecode = duration ? timecode + duration : AV_NOPTS_VALUE; ++ timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE; + data += lace_size[n]; + size -= lace_size[n]; } end: