summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-05-30 17:40:55 +0200
committerwm4 <wm4@nowhere>2013-05-30 17:45:05 +0200
commit3f3531f5607cd973488260aa00c752c3a74496a5 (patch)
treede514bf7511991d78b3c5898cf1dd97d5c63ed4a /demux/demux_mkv.c
parent59892dd4cc1bc29bfbc533f61fb404fb919f4906 (diff)
downloadmpv-3f3531f5607cd973488260aa00c752c3a74496a5.tar.bz2
mpv-3f3531f5607cd973488260aa00c752c3a74496a5.tar.xz
demux_mkv: fix wavpack in mkv
Libav introduced a silent API breakage by changing what wavpack packets the libavcodec decoder accepts. Originally the libavcodec codec accepted Matroska-style wavpack packets. Libav commit 9b6f47c removed this capability from the libavcodec code, and added code to libavformat's Matroska demuxer to "rearrange" wavpack packets. Since demux_mkv still sent Matroska-style packets, playback failed. Fix this by "rearranging" packets in demux_mkv as well by copying libavformat's code. (The best kind of fix.) Tested with [CCCP]_Mega_Lossless_Audio_Test.mkv, as well as with a sample generated by mkvmerge.
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r--demux/demux_mkv.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 3d8efaf211..4b0decff1a 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -2058,6 +2058,97 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
}
}
+// Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30)
+// Originally added with Libav commit 9b6f47c
+// License: LGPL v2.1 or later
+// Author header: The FFmpeg Project (this function still came from Libav)
+// Modified to use talloc, removed ffmpeg/libav specific error codes.
+static int libav_parse_wavpack(mkv_track_t *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 offset = 0;
+
+ if (srclen < 12 || track->private_size < 2)
+ return -1;
+
+ ver = AV_RL16(track->private_data);
+
+ 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)
+ goto fail;
+ blocksize = AV_RL32(src);
+ src += 4;
+ srclen -= 4;
+ } else
+ blocksize = srclen;
+
+ if (blocksize > srclen)
+ goto fail;
+
+ tmp = talloc_realloc(NULL, dst, uint8_t, dstlen + blocksize + 32);
+ if (!tmp)
+ 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:
+ talloc_free(dst);
+ return -1;
+}
+
+static void mkv_parse_packet(mkv_track_t *track, bstr *buffer)
+{
+ if (track->a_formattag == mmioFOURCC('W', 'V', 'P', 'K')) {
+ int size = buffer->len;
+ uint8_t *parsed;
+ if (libav_parse_wavpack(track, buffer->start, &parsed, &size) >= 0) {
+ buffer->start = parsed;
+ buffer->len = size;
+ }
+ }
+}
+
struct block_info {
uint64_t duration;
bool simple, keyframe;
@@ -2204,6 +2295,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
handle_realaudio(demuxer, track, block, keyframe);
else {
bstr buffer = demux_mkv_decode(track, block, 1);
+ mkv_parse_packet(track, &buffer);
if (buffer.start) {
demux_packet_t *dp =
new_demux_packet_from(buffer.start, buffer.len);