parent
4746653466
commit
c89e075d5a
7 changed files with 628 additions and 2 deletions
@ -0,0 +1,615 @@ |
||||
/*
|
||||
* Interplay ACM decoder |
||||
* |
||||
* Copyright (c) 2004-2008 Marko Kreen |
||||
* Copyright (c) 2008 Adam Gashlin |
||||
* Copyright (c) 2015 Paul B Mahol |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#include "libavutil/intreadwrite.h" |
||||
#include "avcodec.h" |
||||
#define BITSTREAM_READER_LE |
||||
#include "get_bits.h" |
||||
#include "internal.h" |
||||
|
||||
static const int8_t map_1bit[] = { -1, +1 }; |
||||
static const int8_t map_2bit_near[] = { -2, -1, +1, +2 }; |
||||
static const int8_t map_2bit_far[] = { -3, -2, +2, +3 }; |
||||
static const int8_t map_3bit[] = { -4, -3, -2, -1, +1, +2, +3, +4 }; |
||||
|
||||
static int mul_3x3 [3 * 3 * 3]; |
||||
static int mul_3x5 [5 * 5 * 5]; |
||||
static int mul_2x11[11 * 11]; |
||||
|
||||
typedef struct InterplayACMContext { |
||||
GetBitContext gb; |
||||
uint8_t *bitstream; |
||||
int max_framesize; |
||||
int bitstream_size; |
||||
int bitstream_index; |
||||
|
||||
int level; |
||||
int rows; |
||||
int cols; |
||||
int wrapbuf_len; |
||||
int block_len; |
||||
int skip; |
||||
|
||||
int *block; |
||||
int *wrapbuf; |
||||
int *ampbuf; |
||||
int *midbuf; |
||||
} InterplayACMContext; |
||||
|
||||
static av_cold int decode_init(AVCodecContext *avctx) |
||||
{ |
||||
InterplayACMContext *s = avctx->priv_data; |
||||
int x1, x2, x3; |
||||
|
||||
if (avctx->extradata_size < 14) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
s->level = AV_RL16(avctx->extradata + 12) & 0xf; |
||||
s->rows = AV_RL16(avctx->extradata + 12) >> 4; |
||||
s->cols = 1 << s->level; |
||||
s->wrapbuf_len = 2 * s->cols - 2; |
||||
s->block_len = s->rows * s->cols; |
||||
s->max_framesize = s->block_len; |
||||
|
||||
s->block = av_calloc(s->block_len, sizeof(int)); |
||||
s->wrapbuf = av_calloc(s->wrapbuf_len, sizeof(int)); |
||||
s->ampbuf = av_calloc(0x10000, sizeof(int)); |
||||
s->bitstream = av_calloc(s->max_framesize, sizeof(*s->bitstream)); |
||||
if (!s->block || !s->wrapbuf || !s->ampbuf || !s->bitstream) |
||||
return AVERROR(ENOMEM); |
||||
|
||||
s->midbuf = s->ampbuf + 0x8000; |
||||
avctx->sample_fmt = AV_SAMPLE_FMT_S16; |
||||
|
||||
for (x3 = 0; x3 < 3; x3++) |
||||
for (x2 = 0; x2 < 3; x2++) |
||||
for (x1 = 0; x1 < 3; x1++) |
||||
mul_3x3[x1 + x2 * 3 + x3* 3 * 3] = x1 + (x2 << 4) + (x3 << 8); |
||||
for (x3 = 0; x3 < 5; x3++) |
||||
for (x2 = 0; x2 < 5; x2++) |
||||
for (x1 = 0; x1 < 5; x1++) |
||||
mul_3x5[x1 + x2 * 5 + x3 * 5 * 5] = x1 + (x2 << 4) + (x3 << 8); |
||||
for (x2 = 0; x2 < 11; x2++) |
||||
for (x1 = 0; x1 < 11; x1++) |
||||
mul_2x11[x1 + x2 * 11] = x1 + (x2 << 4); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#define set_pos(s, r, c, idx) do { \ |
||||
unsigned pos = ((r) << s->level) + (c); \
|
||||
s->block[pos] = s->midbuf[(idx)]; \
|
||||
} while (0) |
||||
|
||||
static int zero(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
unsigned i; |
||||
|
||||
for (i = 0; i < s->rows; i++) |
||||
set_pos(s, i, col, 0); |
||||
return 0; |
||||
} |
||||
|
||||
static int bad(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
return AVERROR_INVALIDDATA; |
||||
} |
||||
|
||||
static int linear(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned int i; |
||||
int b, middle = 1 << (ind - 1); |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits(gb, ind); |
||||
set_pos(s, i, col, b - middle); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k13(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i++, col, 0); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
b = get_bits1(gb); |
||||
set_pos(s, i, col, map_1bit[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k12(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
set_pos(s, i, col, map_1bit[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k24(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i++, col, 0); |
||||
if (i >= s->rows) break; |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 2); |
||||
set_pos(s, i, col, map_2bit_near[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k23(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 2); |
||||
set_pos(s, i, col, map_2bit_near[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k35(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i++, col, 0); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
b = get_bits1(gb); |
||||
set_pos(s, i, col, map_1bit[b]); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 2); |
||||
set_pos(s, i, col, map_2bit_far[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k34(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
b = get_bits1(gb); |
||||
set_pos(s, i, col, map_1bit[b]); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 2); |
||||
set_pos(s, i, col, map_2bit_far[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k45(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); i++; |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 3); |
||||
set_pos(s, i, col, map_3bit[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int k44(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
b = get_bits1(gb); |
||||
if (b == 0) { |
||||
set_pos(s, i, col, 0); |
||||
continue; |
||||
} |
||||
|
||||
b = get_bits(gb, 3); |
||||
set_pos(s, i, col, map_3bit[b]); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int t15(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
int n1, n2, n3; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
/* b = (x1) + (x2 * 3) + (x3 * 9) */ |
||||
b = get_bits(gb, 5); |
||||
|
||||
n1 = (mul_3x3[b] & 0x0F) - 1; |
||||
n2 = ((mul_3x3[b] >> 4) & 0x0F) - 1; |
||||
n3 = ((mul_3x3[b] >> 8) & 0x0F) - 1; |
||||
|
||||
set_pos(s, i++, col, n1); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i++, col, n2); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, n3); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int t27(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
int n1, n2, n3; |
||||
|
||||
for (i = 0; i < s->rows; i++) { |
||||
/* b = (x1) + (x2 * 5) + (x3 * 25) */ |
||||
b = get_bits(gb, 7); |
||||
|
||||
n1 = (mul_3x5[b] & 0x0F) - 2; |
||||
n2 = ((mul_3x5[b] >> 4) & 0x0F) - 2; |
||||
n3 = ((mul_3x5[b] >> 8) & 0x0F) - 2; |
||||
|
||||
set_pos(s, i++, col, n1); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i++, col, n2); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, n3); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int t37(InterplayACMContext *s, unsigned ind, unsigned col) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, b; |
||||
int n1, n2; |
||||
for (i = 0; i < s->rows; i++) { |
||||
/* b = (x1) + (x2 * 11) */ |
||||
b = get_bits(gb, 7); |
||||
|
||||
n1 = (mul_2x11[b] & 0x0F) - 5; |
||||
n2 = ((mul_2x11[b] >> 4) & 0x0F) - 5; |
||||
|
||||
set_pos(s, i++, col, n1); |
||||
if (i >= s->rows) |
||||
break; |
||||
set_pos(s, i, col, n2); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
typedef int (*filler)(InterplayACMContext *s, unsigned ind, unsigned col); |
||||
|
||||
static const filler filler_list[] = { |
||||
zero, bad, bad, linear, |
||||
linear, linear, linear, linear, |
||||
linear, linear, linear, linear, |
||||
linear, linear, linear, linear, |
||||
linear, k13, k12, t15, |
||||
k24, k23, t27, k35, |
||||
k34, bad, k45, k44, |
||||
bad, t37, bad, bad, |
||||
}; |
||||
|
||||
static int fill_block(InterplayACMContext *s) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
unsigned i, ind; |
||||
int ret; |
||||
|
||||
for (i = 0; i < s->cols; i++) { |
||||
ind = get_bits(gb, 5); |
||||
ret = filler_list[ind](s, ind, i); |
||||
if (ret < 0) |
||||
return ret; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void juggle(int *wrap_p, int *block_p, unsigned sub_len, unsigned sub_count) |
||||
{ |
||||
unsigned i, j; |
||||
int *p, r0, r1, r2, r3; |
||||
|
||||
for (i = 0; i < sub_len; i++) { |
||||
p = block_p; |
||||
r0 = wrap_p[0]; |
||||
r1 = wrap_p[1]; |
||||
for (j = 0; j < sub_count/2; j++) { |
||||
r2 = *p; |
||||
*p = r1 * 2 + (r0 + r2); |
||||
p += sub_len; |
||||
r3 = *p; |
||||
*p = r2 * 2 - (r1 + r3); |
||||
p += sub_len; |
||||
r0 = r2; |
||||
r1 = r3; |
||||
} |
||||
|
||||
*wrap_p++ = r0; |
||||
*wrap_p++ = r1; |
||||
block_p++; |
||||
} |
||||
} |
||||
|
||||
static void juggle_block(InterplayACMContext *s) |
||||
{ |
||||
unsigned sub_count, sub_len, todo_count, step_subcount, i; |
||||
int *wrap_p, *block_p, *p; |
||||
|
||||
/* juggle only if subblock_len > 1 */ |
||||
if (s->level == 0) |
||||
return; |
||||
|
||||
/* 2048 / subblock_len */ |
||||
if (s->level > 9) |
||||
step_subcount = 1; |
||||
else |
||||
step_subcount = (2048 >> s->level) - 2; |
||||
|
||||
/* Apply juggle() (rows)x(cols)
|
||||
* from (step_subcount * 2) x (subblock_len/2) |
||||
* to (step_subcount * subblock_len) x (1) |
||||
*/ |
||||
todo_count = s->rows; |
||||
block_p = s->block; |
||||
while (1) { |
||||
wrap_p = s->wrapbuf; |
||||
sub_count = step_subcount; |
||||
if (sub_count > todo_count) |
||||
sub_count = todo_count; |
||||
|
||||
sub_len = s->cols / 2; |
||||
sub_count *= 2; |
||||
|
||||
juggle(wrap_p, block_p, sub_len, sub_count); |
||||
wrap_p += sub_len * 2; |
||||
|
||||
for (i = 0, p = block_p; i < sub_count; i++) { |
||||
p[0]++; |
||||
p += sub_len; |
||||
} |
||||
|
||||
while (sub_len > 1) { |
||||
sub_len /= 2; |
||||
sub_count *= 2; |
||||
juggle(wrap_p, block_p, sub_len, sub_count); |
||||
wrap_p += sub_len * 2; |
||||
} |
||||
|
||||
if (todo_count <= step_subcount) |
||||
break; |
||||
|
||||
todo_count -= step_subcount; |
||||
block_p += step_subcount << s->level; |
||||
} |
||||
} |
||||
|
||||
static int decode_block(InterplayACMContext *s) |
||||
{ |
||||
GetBitContext *gb = &s->gb; |
||||
int pwr, count, val, i, x, ret; |
||||
|
||||
pwr = get_bits(gb, 4); |
||||
val = get_bits(gb, 16); |
||||
|
||||
count = 1 << pwr; |
||||
|
||||
for (i = 0, x = 0; i < count; i++) { |
||||
s->midbuf[i] = x; |
||||
x += val; |
||||
} |
||||
|
||||
for (i = 1, x = -val; i <= count; i++) { |
||||
s->midbuf[-i] = x; |
||||
x -= val; |
||||
} |
||||
|
||||
ret = fill_block(s); |
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
juggle_block(s); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int decode_frame(AVCodecContext *avctx, void *data, |
||||
int *got_frame_ptr, AVPacket *pkt) |
||||
{ |
||||
InterplayACMContext *s = avctx->priv_data; |
||||
GetBitContext *gb = &s->gb; |
||||
AVFrame *frame = data; |
||||
const uint8_t *buf; |
||||
int16_t *samples; |
||||
int ret, n, buf_size, input_buf_size; |
||||
|
||||
if (!pkt->size && !s->bitstream_size) { |
||||
*got_frame_ptr = 0; |
||||
return 0; |
||||
} |
||||
|
||||
buf_size = FFMIN(pkt->size, s->max_framesize - s->bitstream_size); |
||||
input_buf_size = buf_size; |
||||
if (s->bitstream_index + s->bitstream_size + buf_size > s->max_framesize) { |
||||
memmove(s->bitstream, &s->bitstream[s->bitstream_index], s->bitstream_size); |
||||
s->bitstream_index = 0; |
||||
} |
||||
if (pkt->data) |
||||
memcpy(&s->bitstream[s->bitstream_index + s->bitstream_size], pkt->data, buf_size); |
||||
buf = &s->bitstream[s->bitstream_index]; |
||||
buf_size += s->bitstream_size; |
||||
s->bitstream_size = buf_size; |
||||
if (buf_size < s->max_framesize && pkt->data) { |
||||
*got_frame_ptr = 0; |
||||
return input_buf_size; |
||||
} |
||||
|
||||
if ((ret = init_get_bits8(gb, buf, buf_size)) < 0) |
||||
return ret; |
||||
|
||||
frame->nb_samples = s->block_len / avctx->channels; |
||||
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
||||
return ret; |
||||
|
||||
skip_bits(gb, s->skip); |
||||
ret = decode_block(s); |
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
samples = (int16_t *)frame->data[0]; |
||||
for (n = 0; n < frame->nb_samples * avctx->channels; n++) { |
||||
int val = s->block[n] >> s->level; |
||||
*samples++ = val; |
||||
} |
||||
|
||||
*got_frame_ptr = 1; |
||||
s->skip = get_bits_count(gb) - 8 * (get_bits_count(gb) / 8); |
||||
n = get_bits_count(gb) / 8; |
||||
|
||||
if (n > buf_size && pkt->data) { |
||||
s->bitstream_size = 0; |
||||
s->bitstream_index = 0; |
||||
return AVERROR_INVALIDDATA; |
||||
} |
||||
|
||||
if (s->bitstream_size) { |
||||
s->bitstream_index += n; |
||||
s->bitstream_size -= n; |
||||
return input_buf_size; |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
static av_cold int decode_close(AVCodecContext *avctx) |
||||
{ |
||||
InterplayACMContext *s = avctx->priv_data; |
||||
|
||||
av_freep(&s->block); |
||||
av_freep(&s->wrapbuf); |
||||
av_freep(&s->ampbuf); |
||||
av_freep(&s->bitstream); |
||||
s->bitstream_size = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
AVCodec ff_interplay_acm_decoder = { |
||||
.name = "interplayacm", |
||||
.long_name = NULL_IF_CONFIG_SMALL("Interplay ACM"), |
||||
.type = AVMEDIA_TYPE_AUDIO, |
||||
.id = AV_CODEC_ID_INTERPLAY_ACM, |
||||
.init = decode_init, |
||||
.close = decode_close, |
||||
.decode = decode_frame, |
||||
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, |
||||
.priv_data_size = sizeof(InterplayACMContext), |
||||
}; |
Loading…
Reference in new issue