aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/hcadec.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2023-09-05 23:14:58 +0200
committerPaul B Mahol <onemda@gmail.com>2023-09-05 23:24:01 +0200
commitd464a687c9dd03246795d62151809167e8381932 (patch)
treedf823875da7f56fbe98496b38b56e492ddd8debb /libavcodec/hcadec.c
parent39f6d9c5c1272da15fcc6ca9186ce40661326e84 (diff)
downloadffmpeg-d464a687c9dd03246795d62151809167e8381932.tar.gz
avcodec/hcadec: support decoding with extradata provided in first packet
Diffstat (limited to 'libavcodec/hcadec.c')
-rw-r--r--libavcodec/hcadec.c67
1 files changed, 52 insertions, 15 deletions
diff --git a/libavcodec/hcadec.c b/libavcodec/hcadec.c
index 2f019a8214..96e9a909a9 100644
--- a/libavcodec/hcadec.c
+++ b/libavcodec/hcadec.c
@@ -101,24 +101,19 @@ static inline unsigned ceil2(unsigned a, unsigned b)
return (b > 0) ? (a / b + ((a % b) ? 1 : 0)) : 0;
}
-static av_cold int decode_init(AVCodecContext *avctx)
+static int init_hca(AVCodecContext *avctx, const uint8_t *extradata,
+ const int extradata_size)
{
HCAContext *c = avctx->priv_data;
GetByteContext gb0, *const gb = &gb0;
int8_t r[16] = { 0 };
- float scale = 1.f / 8.f;
unsigned b, chunk;
int version, ret;
- avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
- c->crc_table = av_crc_get_table(AV_CRC_16_ANSI);
-
- if (avctx->ch_layout.nb_channels <= 0 || avctx->ch_layout.nb_channels > 16)
- return AVERROR(EINVAL);
-
- if (avctx->extradata_size < 36)
+ if (extradata_size < 36)
return AVERROR_INVALIDDATA;
- bytestream2_init(gb, avctx->extradata, avctx->extradata_size);
+
+ bytestream2_init(gb, extradata, extradata_size);
bytestream2_skipu(gb, 4);
version = bytestream2_get_be16(gb);
@@ -161,7 +156,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
if (c->total_band_count > FF_ARRAY_ELEMS(c->ch->imdct_in))
return AVERROR_INVALIDDATA;
-
while (bytestream2_get_bytes_left(gb) >= 4) {
chunk = bytestream2_get_be32u(gb);
if (chunk == MKBETAG('v', 'b', 'r', 0)) {
@@ -243,11 +237,36 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
+ return 0;
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ HCAContext *c = avctx->priv_data;
+ float scale = 1.f / 8.f;
+ int ret;
+
+ avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+ c->crc_table = av_crc_get_table(AV_CRC_16_ANSI);
+
+ if (avctx->ch_layout.nb_channels <= 0 || avctx->ch_layout.nb_channels > 16)
+ return AVERROR(EINVAL);
+
c->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);
if (!c->fdsp)
return AVERROR(ENOMEM);
- return av_tx_init(&c->tx_ctx, &c->tx_fn, AV_TX_FLOAT_MDCT, 1, 128, &scale, 0);
+ ret = av_tx_init(&c->tx_ctx, &c->tx_fn, AV_TX_FLOAT_MDCT, 1, 128, &scale, 0);
+ if (ret < 0)
+ return ret;
+
+ if (avctx->extradata_size != 0 && avctx->extradata_size < 36)
+ return AVERROR_INVALIDDATA;
+
+ if (!avctx->extradata_size)
+ return 0;
+
+ return init_hca(avctx, avctx->extradata, avctx->extradata_size);
}
static void run_imdct(HCAContext *c, ChannelContext *ch, int index, float *out)
@@ -385,16 +404,34 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
HCAContext *c = avctx->priv_data;
- int ch, ret, packed_noise_level;
+ int ch, offset = 0, ret, packed_noise_level;
GetBitContext gb0, *const gb = &gb0;
float **samples;
+ if (avpkt->size <= 8)
+ return AVERROR_INVALIDDATA;
+
+ if (AV_RN16(avpkt->data) != 0xFFFF) {
+ if (AV_RL32(avpkt->data) != MKTAG('H','C','A',0)) {
+ return AVERROR_INVALIDDATA;
+ } else if (AV_RB16(avpkt->data + 6) <= avpkt->size) {
+ ret = init_hca(avctx, avpkt->data, AV_RB16(avpkt->data + 6));
+ if (ret < 0)
+ return ret;
+ offset = AV_RB16(avpkt->data + 6);
+ if (offset == avpkt->size)
+ return avpkt->size;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
if (avctx->err_recognition & AV_EF_CRCCHECK) {
- if (av_crc(c->crc_table, 0, avpkt->data, avpkt->size))
+ if (av_crc(c->crc_table, 0, avpkt->data + offset, avpkt->size - offset))
return AVERROR_INVALIDDATA;
}
- if ((ret = init_get_bits8(gb, avpkt->data, avpkt->size)) < 0)
+ if ((ret = init_get_bits8(gb, avpkt->data + offset, avpkt->size - offset)) < 0)
return ret;
if (get_bits(gb, 16) != 0xFFFF)