From 3f3531f5607cd973488260aa00c752c3a74496a5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 30 May 2013 17:40:55 +0200 Subject: 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. --- demux/demux_mkv.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'demux/demux_mkv.c') 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); -- cgit v1.2.3