aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2013-05-27 09:44:27 +0200
committerAnton Khirnov <anton@khirnov.net>2013-05-28 08:14:35 +0200
commit9b6f47c44807f14788e909c4c71db58eebba8277 (patch)
treeed68064c1ed437c8d65b439eac10a7dac1add236
parent5074f4545c439420daebe4c2f28ed216440b6ec7 (diff)
downloadffmpeg-9b6f47c44807f14788e909c4c71db58eebba8277.tar.gz
matroskadec: export full wavpack blocks.
This allows us to get rid of demuxer-specific hacks in the decoder and will allow streamcopy from matroska once we have a wavpack muxer.
-rw-r--r--libavcodec/wavpack.c52
-rw-r--r--libavformat/matroskadec.c98
2 files changed, 110 insertions, 40 deletions
diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 3a0fe272a8..4cf9478b8b 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -135,7 +135,6 @@ typedef struct WavpackContext {
int fdec_num;
int multichannel;
- int mkv_mode;
int block;
int samples;
int ch_offset;
@@ -724,14 +723,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;
@@ -783,15 +774,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);
@@ -811,9 +798,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
@@ -1154,14 +1138,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) {
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
s->samples);
@@ -1185,17 +1163,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
}
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",
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 3b801e0845..d88b34fef7 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1929,6 +1929,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,
@@ -1947,6 +2029,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;
@@ -1996,6 +2090,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
}
return 0;
+fail:
+ if (pkt_data != data)
+ av_freep(&pkt_data);
+ return res;
}
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,