summaryrefslogtreecommitdiff
path: root/libavformat/matroskadec.c
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 /libavformat/matroskadec.c
parent5074f4545c439420daebe4c2f28ed216440b6ec7 (diff)
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.
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r--libavformat/matroskadec.c98
1 files changed, 98 insertions, 0 deletions
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,