diff options
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r-- | libavformat/matroskadec.c | 288 |
1 files changed, 158 insertions, 130 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 2de1d48334..c75df51bb4 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1855,6 +1855,141 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, 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 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_SSA) + matroska_fix_ass_packet(matroska, pkt, 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, @@ -1864,7 +1999,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; @@ -1917,139 +2051,33 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1, &lace_size, &laces); - if (res == 0) { - for (n = 0; n < laces; n++) { - 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 (res) + goto end; - 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++) { + 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) { - 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_TEXT) - pkt->convergence_duration = duration; - else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE) - pkt->duration = duration; - - if (st->codec->codec_id == AV_CODEC_ID_SSA) - matroska_fix_ass_packet(matroska, pkt, 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 = duration ? timecode + 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, + pos, !n? is_keyframe : 0); + if (res) + goto end; } + + if (timecode != AV_NOPTS_VALUE) + timecode = duration ? timecode + duration : AV_NOPTS_VALUE; + data += lace_size[n]; + size -= lace_size[n]; } end: |