avformat/matroskadec: Support ContentCompression for all codecs

The Matroska demuxer has three functions for creating packets out of
the data read: One for certain RealAudio codecs (ATRAC3, cook, sipr,
RealAudio 28.8), one for WebVTT (actually, the WebM flavour of it) and
one for all the others. Only the last function supported Matroska's
ContentCompression (e.g. it reversed zlib compression or added the
removed headers to the packets). But in Matroska, all tracks are allowed
to be compressed. This commit adds support for this.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
This commit is contained in:
Andreas Rheinhardt 2019-12-06 09:53:34 +01:00
parent 96012d17a9
commit 979b5b8959
1 changed files with 44 additions and 35 deletions

View File

@ -3192,10 +3192,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
} }
/* reconstruct full wavpack blocks from mangled matroska ones */ /* reconstruct full wavpack blocks from mangled matroska ones */
static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, static int matroska_parse_wavpack(MatroskaTrack *track,
uint8_t **pdst, int *size) uint8_t **data, int *size)
{ {
uint8_t *dst = NULL; uint8_t *dst = NULL;
uint8_t *src = *data;
int dstlen = 0; int dstlen = 0;
int srclen = *size; int srclen = *size;
uint32_t samples; uint32_t samples;
@ -3265,7 +3266,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
*pdst = dst; *data = dst;
*size = dstlen; *size = dstlen;
return 0; return 0;
@ -3275,8 +3276,8 @@ fail:
return ret; return ret;
} }
static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src, static int matroska_parse_prores(MatroskaTrack *track,
uint8_t **pdst, int *size) uint8_t **data, int *size)
{ {
uint8_t *dst; uint8_t *dst;
int dstlen = *size + 8; int dstlen = *size + 8;
@ -3287,10 +3288,10 @@ static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
AV_WB32(dst, dstlen); AV_WB32(dst, dstlen);
AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f')); AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
memcpy(dst + 8, src, dstlen - 8); memcpy(dst + 8, *data, dstlen - 8);
memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
*pdst = dst; *data = dst;
*size = dstlen; *size = dstlen;
return 0; return 0;
@ -3413,54 +3414,46 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
static int matroska_parse_frame(MatroskaDemuxContext *matroska, static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track, AVStream *st, MatroskaTrack *track, AVStream *st,
AVBufferRef *buf, uint8_t *data, int pkt_size, AVBufferRef *buf, uint8_t **data, int pkt_size,
uint64_t timecode, uint64_t lace_duration, uint64_t timecode, uint64_t lace_duration,
int64_t pos, int is_keyframe, int64_t pos, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size, uint8_t *additional, uint64_t additional_id, int additional_size,
int64_t discard_padding) int64_t discard_padding)
{ {
uint8_t *pkt_data = data; uint8_t *pkt_data = *data;
int res = 0; int res = 0;
AVPacket pktl, *pkt = &pktl; AVPacket pktl, *pkt = &pktl;
if (track->needs_decoding) {
res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
if (res < 0)
return res;
}
if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) { if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) {
uint8_t *wv_data; res = matroska_parse_wavpack(track, &pkt_data, &pkt_size);
res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
if (res < 0) { if (res < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, av_log(matroska->ctx, AV_LOG_ERROR,
"Error parsing a wavpack block.\n"); "Error parsing a wavpack block.\n");
goto fail; goto fail;
} }
if (pkt_data != data) if (!buf)
av_freep(&pkt_data); av_freep(data);
pkt_data = wv_data; buf = NULL;
} }
if (st->codecpar->codec_id == AV_CODEC_ID_PRORES && if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
AV_RB32(pkt_data + 4) != MKBETAG('i', 'c', 'p', 'f')) { AV_RB32(pkt_data + 4) != MKBETAG('i', 'c', 'p', 'f')) {
uint8_t *pr_data; res = matroska_parse_prores(track, &pkt_data, &pkt_size);
res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
if (res < 0) { if (res < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, av_log(matroska->ctx, AV_LOG_ERROR,
"Error parsing a prores block.\n"); "Error parsing a prores block.\n");
goto fail; goto fail;
} }
if (pkt_data != data) if (!buf)
av_freep(&pkt_data); av_freep(data);
pkt_data = pr_data; buf = NULL;
} }
if (!pkt_size && !additional_size) if (!pkt_size && !additional_size)
goto no_output; goto no_output;
av_init_packet(pkt); av_init_packet(pkt);
if (pkt_data != data) if (!buf)
pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE, pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE,
NULL, NULL, 0); NULL, NULL, 0);
else else
@ -3531,8 +3524,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
no_output: no_output:
fail: fail:
if (pkt_data != data) if (!buf)
av_freep(&pkt_data); av_freep(data);
return res; return res;
} }
@ -3634,25 +3627,41 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
for (n = 0; n < laces; n++) { for (n = 0; n < laces; n++) {
int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces; int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;
uint8_t *out_data = data;
int out_size = lace_size[n];
if (track->needs_decoding) {
res = matroska_decode_buffer(&out_data, &out_size, track);
if (res < 0)
return res;
/* Given that we are here means that out_data is no longer
* owned by buf, so set it to NULL. This depends upon
* zero-length header removal compression being ignored. */
av_assert1(out_data != data);
buf = NULL;
}
if (track->audio.buf) { if (track->audio.buf) {
res = matroska_parse_rm_audio(matroska, track, st, data, res = matroska_parse_rm_audio(matroska, track, st,
lace_size[n], out_data, out_size,
timecode, pos); timecode, pos);
if (!buf)
av_free(out_data);
if (res) if (res)
return res; return res;
} else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) { } else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) {
res = matroska_parse_webvtt(matroska, track, st, res = matroska_parse_webvtt(matroska, track, st,
data, lace_size[n], out_data, out_size,
timecode, lace_duration, timecode, lace_duration,
pos); pos);
if (!buf)
av_free(out_data);
if (res) if (res)
return res; return res;
} else { } else {
res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n], res = matroska_parse_frame(matroska, track, st, buf, &out_data,
timecode, lace_duration, pos, out_size, timecode, lace_duration,
!n ? is_keyframe : 0, pos, !n ? is_keyframe : 0,
additional, additional_id, additional_size, additional, additional_id, additional_size,
discard_padding); discard_padding);
if (res) if (res)