1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-01 04:31:39 +00:00

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.
This commit is contained in:
wm4 2013-05-30 17:40:55 +02:00
parent 59892dd4cc
commit 3f3531f560

View File

@ -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);