diff options
author | Hendrik Leppkes <h.leppkes@gmail.com> | 2013-07-13 12:27:34 +0400 |
---|---|---|
committer | Hendrik Leppkes <h.leppkes@gmail.com> | 2017-08-04 20:12:12 +0300 |
commit | 10f5f18d174baf6fd15d9018b214cbb4d6a4bd92 (patch) | |
tree | 0071a89b18a383a39280b0662cd210061fe6088d | |
parent | d48a3716785c12e6510ad61ccbf2c0520172db00 (diff) |
matroskadec_haali: export full wavpack blocks
-rw-r--r-- | libavformat/matroskadec_haali.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/libavformat/matroskadec_haali.c b/libavformat/matroskadec_haali.c index 2f4036a1bc..9648ebb223 100644 --- a/libavformat/matroskadec_haali.c +++ b/libavformat/matroskadec_haali.c @@ -963,6 +963,8 @@ static int mkv_generate_extradata(AVFormatContext *s, TrackInfo *info, enum AVCo avio_wl16(&b, info->AV.Audio.BitDepth); avio_wl32(&b, mkv_TruncFloat(info->AV.Audio.OutputSamplingFreq)); avio_wl32(&b, s->duration * info->AV.Audio.OutputSamplingFreq); + } else if (codec_id == AV_CODEC_ID_WAVPACK) { + return 0; } if (*extradata_ptr) @@ -1346,6 +1348,88 @@ static void mkv_packet_param_change(AVFormatContext *s, TrackInfo *info, enum AV } } +/* 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 = 0; + int ret, offset = 0; + + if (srclen < 12) + return AVERROR_INVALIDDATA; + + if (track->info->CodecPrivateSize >= 2) + ver = AV_RL16(track->info->CodecPrivate); + + 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 mkv_read_packet(AVFormatContext *s, AVPacket *pkt) { MatroskaDemuxContext *ctx = (MatroskaDemuxContext *)s->priv_data; @@ -1431,6 +1515,19 @@ again: } } + if (track->stream->codec->codec_id == AV_CODEC_ID_WAVPACK) { + uint8_t *wv_data; + int wv_size = pkt->size; + ret = matroska_parse_wavpack(track, pkt->data, &wv_data, &wv_size); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Error parsing a wavpack block.\n"); + av_free_packet(pkt); + return ret; + } + av_buffer_unref(pkt->buf); + av_packet_from_data(pkt, wv_data, wv_size); + } + if (track->refresh_extradata) { mkv_packet_param_change(s, track->info, track->stream->codec->codec_id, pkt); track->refresh_extradata = 0; |