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:
parent
59892dd4cc
commit
3f3531f560
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user