int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
} SmackVContext;
+typedef struct HuffEntry {
+ uint8_t value;
+ uint8_t length;
+} HuffEntry;
+
/**
* Context used for code reconstructing
*/
typedef struct HuffContext {
- int length;
int current;
- uint32_t *bits;
- int *lengths;
- int *values;
+ HuffEntry entries[256];
} HuffContext;
/* common parameters used for decode_bigtree */
int current, length;
int *values;
VLC *v1, *v2;
- int *recode1, *recode2;
+ uint8_t vals[2];
int escapes[3];
int *last;
} DBCtx;
* Can read SMKTREE_DECODE_MAX_RECURSION before the first check;
* does not overread gb on success.
*/
-static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
+static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, int length)
{
if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) {
av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n");
}
if(!get_bits1(gb)){ //Leaf
- if(hc->current >= hc->length){
+ if (hc->current >= 256) {
av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
return AVERROR_INVALIDDATA;
}
if (get_bits_left(gb) < 8)
return AVERROR_INVALIDDATA;
- hc->bits[hc->current] = prefix;
- hc->lengths[hc->current] = length;
- hc->values[hc->current] = get_bits(gb, 8);
- hc->current++;
+ hc->entries[hc->current++] = (HuffEntry){ get_bits(gb, 8), length };
return 0;
} else { //Node
int r;
length++;
- r = smacker_decode_tree(gb, hc, prefix, length);
+ r = smacker_decode_tree(gb, hc, length);
if(r)
return r;
- return smacker_decode_tree(gb, hc, prefix | (1U << (length - 1)), length);
+ return smacker_decode_tree(gb, hc, length);
}
}
return AVERROR_INVALIDDATA;
if(!get_bits1(gb)){ //Leaf
int val, i1, i2;
- i1 = ctx->v1->table ? get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3) : 0;
- i2 = ctx->v2->table ? get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3) : 0;
- val = ctx->recode1[i1] | (ctx->recode2[i2] << 8);
+ i1 = ctx->v1->table ? get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3)
+ : ctx->vals[0];
+ i2 = ctx->v2->table ? get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3)
+ : ctx->vals[1];
+ val = i1 | (i2 << 8);
if(val == ctx->escapes[0]) {
ctx->last[0] = ctx->current;
val = 0;
*/
static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int **recodes, int *last, int size)
{
- HuffContext h[2] = { 0 };
VLC vlc[2] = { { 0 } };
int escapes[3];
DBCtx ctx;
}
for (int i = 0; i < 2; i++) {
- h[i].length = 256;
- h[i].current = 0;
- h[i].bits = av_malloc(256 * sizeof(h[i].bits[0]));
- h[i].lengths = av_malloc(256 * sizeof(h[i].lengths[0]));
- h[i].values = av_malloc(256 * sizeof(h[i].values[0]));
- if (!h[i].bits || !h[i].lengths || !h[i].values) {
- err = AVERROR(ENOMEM);
- goto error;
- }
+ HuffContext h;
+ h.current = 0;
if (!get_bits1(gb)) {
- h[i].values[0] = 0;
+ ctx.vals[i] = 0;
av_log(smk->avctx, AV_LOG_ERROR, "Skipping %s bytes tree\n",
i ? "high" : "low");
continue;
}
- err = smacker_decode_tree(gb, &h[i], 0, 0);
+ err = smacker_decode_tree(gb, &h, 0);
if (err < 0)
goto error;
skip_bits1(gb);
- if (h[i].current > 1) {
- err = init_vlc(&vlc[i], SMKTREE_BITS, h[i].current,
- INIT_VLC_DEFAULT_SIZES(h[i].lengths),
- INIT_VLC_DEFAULT_SIZES(h[i].bits),
- INIT_VLC_LE);
+ if (h.current > 1) {
+ err = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
+ &h.entries[0].length, sizeof(*h.entries),
+ &h.entries[0].value, sizeof(*h.entries), 1,
+ 0, INIT_VLC_OUTPUT_LE, smk->avctx);
if (err < 0) {
av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
goto error;
}
- }
+ } else
+ ctx.vals[i] = h.entries[0].value;
}
escapes[0] = get_bits(gb, 16);
ctx.escapes[2] = escapes[2];
ctx.v1 = &vlc[0];
ctx.v2 = &vlc[1];
- ctx.recode1 = h[0].values;
- ctx.recode2 = h[1].values;
ctx.last = last;
ctx.length = (size + 3) >> 2;
ctx.current = 0;
error:
for (int i = 0; i < 2; i++) {
ff_free_vlc(&vlc[i]);
- av_free(h[i].bits);
- av_free(h[i].lengths);
- av_free(h[i].values);
}
return err;
case SMK_BLK_FULL:
mode = 0;
if(avctx->codec_tag == MKTAG('S', 'M', 'K', '4')) { // In case of Smacker v4 we have three modes
+ if (get_bits_left(&gb) < 1)
+ return AVERROR_INVALIDDATA;
if(get_bits1(&gb)) mode = 1;
else if(get_bits1(&gb)) mode = 2;
}
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
GetBitContext gb;
- HuffContext h[4] = { { 0 } };
VLC vlc[4] = { { 0 } };
int16_t *samples;
uint8_t *samples8;
- int val;
+ uint8_t values[4];
int i, res, ret;
int unp_size;
int bits, stereo;
- int pred[2] = {0, 0};
+ unsigned pred[2], val;
if (buf_size <= 4) {
av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
// Initialize
for(i = 0; i < (1 << (bits + stereo)); i++) {
- h[i].length = 256;
- h[i].current = 0;
- h[i].bits = av_malloc(256 * sizeof(h[i].bits));
- h[i].lengths = av_malloc(256 * sizeof(h[i].lengths));
- h[i].values = av_malloc(256 * sizeof(h[i].values));
- if (!h[i].bits || !h[i].lengths || !h[i].values) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
+ HuffContext h;
+ h.current = 0;
skip_bits1(&gb);
- if ((ret = smacker_decode_tree(&gb, &h[i], 0, 0)) < 0)
+ if ((ret = smacker_decode_tree(&gb, &h, 0)) < 0)
goto error;
skip_bits1(&gb);
- if(h[i].current > 1) {
- ret = init_vlc(&vlc[i], SMKTREE_BITS, h[i].current,
- h[i].lengths, sizeof(int), sizeof(int),
- h[i].bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
+ if (h.current > 1) {
+ ret = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
+ &h.entries[0].length, sizeof(*h.entries),
+ &h.entries[0].value, sizeof(*h.entries), 1,
+ 0, INIT_VLC_OUTPUT_LE, avctx);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
goto error;
}
- }
+ } else
+ values[i] = h.entries[0].value;
}
/* this codec relies on wraparound instead of clipping audio */
if(bits) { //decode 16-bit data
for(i = stereo; i >= 0; i--)
- pred[i] = sign_extend(av_bswap16(get_bits(&gb, 16)), 16);
+ pred[i] = av_bswap16(get_bits(&gb, 16));
for(i = 0; i <= stereo; i++)
*samples++ = pred[i];
for(; i < unp_size / 2; i++) {
+ unsigned idx = 2 * (i & stereo);
if (get_bits_left(&gb) < 0) {
ret = AVERROR_INVALIDDATA;
goto error;
}
- if(i & stereo) {
- if(vlc[2].table)
- res = get_vlc2(&gb, vlc[2].table, SMKTREE_BITS, 3);
- else
- res = 0;
- val = h[2].values[res];
- if(vlc[3].table)
- res = get_vlc2(&gb, vlc[3].table, SMKTREE_BITS, 3);
- else
- res = 0;
- val |= h[3].values[res] << 8;
- pred[1] += (unsigned)sign_extend(val, 16);
- *samples++ = pred[1];
- } else {
- if(vlc[0].table)
- res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
- else
- res = 0;
- val = h[0].values[res];
- if(vlc[1].table)
- res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
- else
- res = 0;
- val |= h[1].values[res] << 8;
- pred[0] += (unsigned)sign_extend(val, 16);
- *samples++ = pred[0];
- }
+ if (vlc[idx].table)
+ res = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+ else
+ res = values[idx];
+ val = res;
+ if (vlc[++idx].table)
+ res = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+ else
+ res = values[idx];
+ val |= res << 8;
+ pred[idx / 2] += val;
+ *samples++ = pred[idx / 2];
}
} else { //8-bit data
for(i = stereo; i >= 0; i--)
for(i = 0; i <= stereo; i++)
*samples8++ = pred[i];
for(; i < unp_size; i++) {
+ unsigned idx = i & stereo;
if (get_bits_left(&gb) < 0) {
ret = AVERROR_INVALIDDATA;
goto error;
}
- if(i & stereo){
- if(vlc[1].table)
- res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
- else
- res = 0;
- pred[1] += sign_extend(h[1].values[res], 8);
- *samples8++ = pred[1];
- } else {
- if(vlc[0].table)
- res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
- else
- res = 0;
- pred[0] += sign_extend(h[0].values[res], 8);
- *samples8++ = pred[0];
- }
+ if (vlc[idx].table)
+ val = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+ else
+ val = values[idx];
+ pred[idx] += val;
+ *samples8++ = pred[idx];
}
}
error:
for(i = 0; i < 4; i++) {
ff_free_vlc(&vlc[i]);
- av_free(h[i].bits);
- av_free(h[i].lengths);
- av_free(h[i].values);
}
return ret;
.close = decode_end,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
- .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE,
};
AVCodec ff_smackaud_decoder = {
.init = smka_decode_init,
.decode = smka_decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};