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 fdec_num;
|
||||||
|
|
||||||
int multichannel;
|
int multichannel;
|
||||||
int mkv_mode;
|
|
||||||
int block;
|
int block;
|
||||||
int samples;
|
int samples;
|
||||||
int ch_offset;
|
int ch_offset;
|
||||||
@ -724,14 +723,6 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx)
|
|||||||
: AV_CH_LAYOUT_MONO;
|
: AV_CH_LAYOUT_MONO;
|
||||||
|
|
||||||
s->multichannel = avctx->channels > 2;
|
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;
|
s->fdec_num = 0;
|
||||||
|
|
||||||
@ -783,16 +774,12 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
|
|||||||
|
|
||||||
bytestream2_init(&gb, buf, buf_size);
|
bytestream2_init(&gb, buf, buf_size);
|
||||||
|
|
||||||
if (!wc->mkv_mode) {
|
|
||||||
s->samples = bytestream2_get_le32(&gb);
|
s->samples = bytestream2_get_le32(&gb);
|
||||||
if (s->samples != wc->samples) {
|
if (s->samples != wc->samples) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
|
av_log(avctx, AV_LOG_ERROR, "Mismatching number of samples in "
|
||||||
"a sequence: %d and %d\n", wc->samples, s->samples);
|
"a sequence: %d and %d\n", wc->samples, s->samples);
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
s->samples = wc->samples;
|
|
||||||
}
|
|
||||||
s->frame_flags = bytestream2_get_le32(&gb);
|
s->frame_flags = bytestream2_get_le32(&gb);
|
||||||
bpp = av_get_bytes_per_sample(avctx->sample_fmt);
|
bpp = av_get_bytes_per_sample(avctx->sample_fmt);
|
||||||
orig_bpp = ((s->frame_flags & 0x03) + 1) << 3;
|
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)
|
if (s->stereo)
|
||||||
samples_r = data[wc->ch_offset + 1];
|
samples_r = data[wc->ch_offset + 1];
|
||||||
|
|
||||||
if (wc->mkv_mode)
|
|
||||||
bytestream2_skip(&gb, 4); // skip block size;
|
|
||||||
|
|
||||||
wc->ch_offset += 1 + s->stereo;
|
wc->ch_offset += 1 + s->stereo;
|
||||||
|
|
||||||
// parse metadata blocks
|
// parse metadata blocks
|
||||||
@ -1154,14 +1138,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
|
|||||||
s->ch_offset = 0;
|
s->ch_offset = 0;
|
||||||
|
|
||||||
/* determine number of samples */
|
/* 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);
|
s->samples = AV_RL32(buf + 20);
|
||||||
frame_flags = AV_RL32(buf + 24);
|
frame_flags = AV_RL32(buf + 24);
|
||||||
}
|
|
||||||
if (s->samples <= 0) {
|
if (s->samples <= 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
|
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
|
||||||
s->samples);
|
s->samples);
|
||||||
@ -1185,17 +1163,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (buf_size > 0) {
|
while (buf_size > 0) {
|
||||||
if (!s->mkv_mode) {
|
|
||||||
if (buf_size <= WV_HEADER_SIZE)
|
if (buf_size <= WV_HEADER_SIZE)
|
||||||
break;
|
break;
|
||||||
frame_size = AV_RL32(buf + 4) - 12;
|
frame_size = AV_RL32(buf + 4) - 12;
|
||||||
buf += 20;
|
buf += 20;
|
||||||
buf_size -= 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) {
|
if (frame_size <= 0 || frame_size > buf_size) {
|
||||||
av_log(avctx, AV_LOG_ERROR,
|
av_log(avctx, AV_LOG_ERROR,
|
||||||
"Block %d has invalid size (size %d vs. %d bytes left)\n",
|
"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;
|
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,
|
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
|
||||||
MatroskaTrack *track,
|
MatroskaTrack *track,
|
||||||
AVStream *st,
|
AVStream *st,
|
||||||
@ -1947,6 +2029,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
|
|||||||
return res;
|
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)
|
if (st->codec->codec_id == AV_CODEC_ID_PRORES)
|
||||||
offset = 8;
|
offset = 8;
|
||||||
|
|
||||||
@ -1996,6 +2090,10 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
if (pkt_data != data)
|
||||||
|
av_freep(&pkt_data);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
|
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
|
||||||
|
Loading…
Reference in New Issue
Block a user