| @@ -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: | |||