Merge remote-tracking branch 'qatar/master'

* qatar/master:
  smacker: assign video frame PTS
  matroskadec: export full wavpack blocks.

Conflicts:
	libavcodec/wavpack.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2013-05-28 11:58:46 +02:00
commit 3ed3aaab32
3 changed files with 111 additions and 40 deletions

View File

@ -137,7 +137,6 @@ typedef struct WavpackContext {
int fdec_num;
int multichannel;
int mkv_mode;
int block;
int samples;
int ch_offset;
@ -730,14 +729,6 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx)
: AV_CH_LAYOUT_MONO;
s->multichannel = avctx->channels > 2;
/* lavf demuxer does not provide extradata, Matroska stores 0x403
* there, use this to detect decoding mode for multichannel */
s->mkv_mode = 0;
if (s->multichannel && avctx->extradata && avctx->extradata_size == 2) {
int ver = AV_RL16(avctx->extradata);
if (ver >= 0x402 && ver <= 0x410)
s->mkv_mode = 1;
}
s->fdec_num = 0;
@ -789,15 +780,11 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
bytestream2_init(&gb, buf, buf_size);
if (!wc->mkv_mode) {
s->samples = bytestream2_get_le32(&gb);
if (s->samples != wc->samples) {
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
"a sequence: %d and %d\n", wc->samples, s->samples);
return AVERROR_INVALIDDATA;
}
} else {
s->samples = wc->samples;
s->samples = bytestream2_get_le32(&gb);
if (s->samples != wc->samples) {
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
"a sequence: %d and %d\n", wc->samples, s->samples);
return AVERROR_INVALIDDATA;
}
s->frame_flags = bytestream2_get_le32(&gb);
bpp = av_get_bytes_per_sample(avctx->sample_fmt);
@ -822,9 +809,6 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
if (s->stereo)
samples_r = data[wc->ch_offset + 1];
if (wc->mkv_mode)
bytestream2_skip(&gb, 4); // skip block size;
wc->ch_offset += 1 + s->stereo;
// parse metadata blocks
@ -1165,14 +1149,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
s->ch_offset = 0;
/* determine number of samples */
if (s->mkv_mode) {
s->samples = AV_RL32(buf);
buf += 4;
frame_flags = AV_RL32(buf);
} else {
s->samples = AV_RL32(buf + 20);
frame_flags = AV_RL32(buf + 24);
}
s->samples = AV_RL32(buf + 20);
frame_flags = AV_RL32(buf + 24);
if (s->samples <= 0 || s->samples > WV_MAX_SAMPLES) {
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
s->samples);
@ -1195,17 +1173,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
frame->nb_samples = s->samples;
while (buf_size > 0) {
if (!s->mkv_mode) {
if (buf_size <= WV_HEADER_SIZE)
break;
frame_size = AV_RL32(buf + 4) - 12;
buf += 20;
buf_size -= 20;
} else {
if (buf_size < 12) // MKV files can have zero flags after last block
break;
frame_size = AV_RL32(buf + 8) + 12;
}
if (buf_size <= WV_HEADER_SIZE)
break;
frame_size = AV_RL32(buf + 4) - 12;
buf += 20;
buf_size -= 20;
if (frame_size <= 0 || frame_size > buf_size) {
av_log(avctx, AV_LOG_ERROR,
"Block %d has invalid size (size %d vs. %d bytes left)\n",

View File

@ -2144,6 +2144,88 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
return 0;
}
/* reconstruct full wavpack blocks from mangled matroska ones */
static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
uint8_t **pdst, int *size)
{
uint8_t *dst = NULL;
int dstlen = 0;
int srclen = *size;
uint32_t samples;
uint16_t ver;
int ret, offset = 0;
if (srclen < 12 || track->stream->codec->extradata_size < 2)
return AVERROR_INVALIDDATA;
ver = AV_RL16(track->stream->codec->extradata);
samples = AV_RL32(src);
src += 4;
srclen -= 4;
while (srclen >= 8) {
int multiblock;
uint32_t blocksize;
uint8_t *tmp;
uint32_t flags = AV_RL32(src);
uint32_t crc = AV_RL32(src + 4);
src += 8;
srclen -= 8;
multiblock = (flags & 0x1800) != 0x1800;
if (multiblock) {
if (srclen < 4) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
blocksize = AV_RL32(src);
src += 4;
srclen -= 4;
} else
blocksize = srclen;
if (blocksize > srclen) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
tmp = av_realloc(dst, dstlen + blocksize + 32);
if (!tmp) {
ret = AVERROR(ENOMEM);
goto fail;
}
dst = tmp;
dstlen += blocksize + 32;
AV_WL32(dst + offset, MKTAG('w', 'v', 'p', 'k')); // tag
AV_WL32(dst + offset + 4, blocksize + 24); // blocksize - 8
AV_WL16(dst + offset + 8, ver); // version
AV_WL16(dst + offset + 10, 0); // track/index_no
AV_WL32(dst + offset + 12, 0); // total samples
AV_WL32(dst + offset + 16, 0); // block index
AV_WL32(dst + offset + 20, samples); // number of samples
AV_WL32(dst + offset + 24, flags); // flags
AV_WL32(dst + offset + 28, crc); // crc
memcpy (dst + offset + 32, src, blocksize); // block data
src += blocksize;
srclen -= blocksize;
offset += blocksize + 32;
}
*pdst = dst;
*size = dstlen;
return 0;
fail:
av_freep(&dst);
return ret;
}
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track,
AVStream *st,
@ -2163,6 +2245,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
return res;
}
if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) {
uint8_t *wv_data;
res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
if (res < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a wavpack block.\n");
goto fail;
}
if (pkt_data != data)
av_freep(&pkt_data);
pkt_data = wv_data;
}
if (st->codec->codec_id == AV_CODEC_ID_PRORES)
offset = 8;
@ -2249,6 +2343,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
#endif
return 0;
fail:
if (pkt_data != data)
av_freep(&pkt_data);
return res;
}
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,

View File

@ -338,6 +338,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
if(ret != frame_size)
return AVERROR(EIO);
pkt->stream_index = smk->videoindex;
pkt->pts = smk->cur_frame;
pkt->size = ret + 769;
smk->cur_frame++;
smk->nextpos = avio_tell(s->pb);