mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
matroskadec: export full wavpack blocks.
This allows us to get rid of demuxer-specific hacks in the decoder and will allow streamcopy from matroska once we have a wavpack muxer.
This commit is contained in:
parent
5074f4545c
commit
9b6f47c448
@ -135,7 +135,6 @@ typedef struct WavpackContext {
|
||||
int fdec_num;
|
||||
|
||||
int multichannel;
|
||||
int mkv_mode;
|
||||
int block;
|
||||
int samples;
|
||||
int ch_offset;
|
||||
@ -724,14 +723,6 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx)
|
||||
: AV_CH_LAYOUT_MONO;
|
||||
|
||||
s->multichannel = avctx->channels > 2;
|
||||
/* lavf demuxer does not provide extradata, Matroska stores 0x403
|
||||
* there, use this to detect decoding mode for multichannel */
|
||||
s->mkv_mode = 0;
|
||||
if (s->multichannel && avctx->extradata && avctx->extradata_size == 2) {
|
||||
int ver = AV_RL16(avctx->extradata);
|
||||
if (ver >= 0x402 && ver <= 0x410)
|
||||
s->mkv_mode = 1;
|
||||
}
|
||||
|
||||
s->fdec_num = 0;
|
||||
|
||||
@ -783,16 +774,12 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
|
||||
|
||||
bytestream2_init(&gb, buf, buf_size);
|
||||
|
||||
if (!wc->mkv_mode) {
|
||||
s->samples = bytestream2_get_le32(&gb);
|
||||
if (s->samples != wc->samples) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
|
||||
"a sequence: %d and %d\n", wc->samples, s->samples);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
} else {
|
||||
s->samples = wc->samples;
|
||||
}
|
||||
s->frame_flags = bytestream2_get_le32(&gb);
|
||||
bpp = av_get_bytes_per_sample(avctx->sample_fmt);
|
||||
orig_bpp = ((s->frame_flags & 0x03) + 1) << 3;
|
||||
@ -811,9 +798,6 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
|
||||
if (s->stereo)
|
||||
samples_r = data[wc->ch_offset + 1];
|
||||
|
||||
if (wc->mkv_mode)
|
||||
bytestream2_skip(&gb, 4); // skip block size;
|
||||
|
||||
wc->ch_offset += 1 + s->stereo;
|
||||
|
||||
// parse metadata blocks
|
||||
@ -1154,14 +1138,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
|
||||
s->ch_offset = 0;
|
||||
|
||||
/* determine number of samples */
|
||||
if (s->mkv_mode) {
|
||||
s->samples = AV_RL32(buf);
|
||||
buf += 4;
|
||||
frame_flags = AV_RL32(buf);
|
||||
} else {
|
||||
s->samples = AV_RL32(buf + 20);
|
||||
frame_flags = AV_RL32(buf + 24);
|
||||
}
|
||||
if (s->samples <= 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
|
||||
s->samples);
|
||||
@ -1185,17 +1163,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
|
||||
}
|
||||
|
||||
while (buf_size > 0) {
|
||||
if (!s->mkv_mode) {
|
||||
if (buf_size <= WV_HEADER_SIZE)
|
||||
break;
|
||||
frame_size = AV_RL32(buf + 4) - 12;
|
||||
buf += 20;
|
||||
buf_size -= 20;
|
||||
} else {
|
||||
if (buf_size < 12) // MKV files can have zero flags after last block
|
||||
break;
|
||||
frame_size = AV_RL32(buf + 8) + 12;
|
||||
}
|
||||
if (frame_size <= 0 || frame_size > buf_size) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"Block %d has invalid size (size %d vs. %d bytes left)\n",
|
||||
|
@ -1929,6 +1929,88 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
int ret, offset = 0;
|
||||
|
||||
if (srclen < 12 || track->stream->codec->extradata_size < 2)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
ver = AV_RL16(track->stream->codec->extradata);
|
||||
|
||||
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 matroska_parse_frame(MatroskaDemuxContext *matroska,
|
||||
MatroskaTrack *track,
|
||||
AVStream *st,
|
||||
@ -1947,6 +2029,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
|
||||
return res;
|
||||
}
|
||||
|
||||
if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) {
|
||||
uint8_t *wv_data;
|
||||
res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
|
||||
if (res < 0) {
|
||||
av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a wavpack block.\n");
|
||||
goto fail;
|
||||
}
|
||||
if (pkt_data != data)
|
||||
av_freep(&pkt_data);
|
||||
pkt_data = wv_data;
|
||||
}
|
||||
|
||||
if (st->codec->codec_id == AV_CODEC_ID_PRORES)
|
||||
offset = 8;
|
||||
|
||||
@ -1996,6 +2090,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (pkt_data != data)
|
||||
av_freep(&pkt_data);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
|
||||
|
Loading…
Reference in New Issue
Block a user