mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
790f793844
There are lots of files that don't need it: The number of object files that actually need it went down from 2011 to 884 here. Keep it for external users in order to not cause breakages. Also improve the other headers a bit while just at it. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
650 lines
16 KiB
C
650 lines
16 KiB
C
/*
|
|
* 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 "libavutil/mem.h"
|
|
#include "libavutil/thread.h"
|
|
|
|
#define BITSTREAM_READER_LE
|
|
#include "avcodec.h"
|
|
#include "codec_internal.h"
|
|
#include "decode.h"
|
|
#include "get_bits.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 {
|
|
AVCodecContext *avctx;
|
|
GetBitContext gb;
|
|
uint8_t *bitstream;
|
|
int max_framesize;
|
|
uint64_t max_samples;
|
|
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 void decode_init_static(void)
|
|
{
|
|
for (int x3 = 0; x3 < 3; x3++)
|
|
for (int x2 = 0; x2 < 3; x2++)
|
|
for (int x1 = 0; x1 < 3; x1++)
|
|
mul_3x3[x1 + x2 * 3 + x3 * 3 * 3] = x1 + (x2 << 4) + (x3 << 8);
|
|
for (int x3 = 0; x3 < 5; x3++)
|
|
for (int x2 = 0; x2 < 5; x2++)
|
|
for (int x1 = 0; x1 < 5; x1++)
|
|
mul_3x5[x1 + x2 * 5 + x3 * 5 * 5] = x1 + (x2 << 4) + (x3 << 8);
|
|
for (int x2 = 0; x2 < 11; x2++)
|
|
for (int x1 = 0; x1 < 11; x1++)
|
|
mul_2x11[x1 + x2 * 11] = x1 + (x2 << 4);
|
|
}
|
|
|
|
static av_cold int decode_init(AVCodecContext *avctx)
|
|
{
|
|
static AVOnce init_static_once = AV_ONCE_INIT;
|
|
InterplayACMContext *s = avctx->priv_data;
|
|
|
|
s->avctx = avctx;
|
|
if (avctx->extradata_size < 14)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
if (avctx->ch_layout.nb_channels <= 0) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid number of channels: %d\n", avctx->ch_layout.nb_channels);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
s->max_samples = AV_RL32(avctx->extradata + 4) / avctx->ch_layout.nb_channels;
|
|
if (s->max_samples == 0)
|
|
s->max_samples = UINT64_MAX;
|
|
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 + AV_INPUT_BUFFER_PADDING_SIZE / sizeof(*s->bitstream) + 1, 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;
|
|
|
|
ff_thread_once(&init_static_once, decode_init_static);
|
|
|
|
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);
|
|
if (b > 26) {
|
|
av_log(s->avctx, AV_LOG_ERROR, "Too large b = %d > 26\n", b);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
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);
|
|
if (b > 124) {
|
|
av_log(s->avctx, AV_LOG_ERROR, "Too large b = %d > 124\n", b);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
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);
|
|
if (b > 120) {
|
|
av_log(s->avctx, AV_LOG_ERROR, "Too large b = %d > 120\n", b);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
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;
|
|
unsigned int 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 -= (unsigned)val;
|
|
}
|
|
|
|
ret = fill_block(s);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
juggle_block(s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
|
|
int *got_frame_ptr, AVPacket *pkt)
|
|
{
|
|
InterplayACMContext *s = avctx->priv_data;
|
|
GetBitContext *gb = &s->gb;
|
|
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 = FFMIN(s->block_len / avctx->ch_layout.nb_channels, s->max_samples);
|
|
s->max_samples -= FFMIN(frame->nb_samples, s->max_samples);
|
|
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->ch_layout.nb_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 > 0) {
|
|
s->bitstream_index += n;
|
|
s->bitstream_size -= FFMIN(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;
|
|
}
|
|
|
|
const FFCodec ff_interplay_acm_decoder = {
|
|
.p.name = "interplayacm",
|
|
CODEC_LONG_NAME("Interplay ACM"),
|
|
.p.type = AVMEDIA_TYPE_AUDIO,
|
|
.p.id = AV_CODEC_ID_INTERPLAY_ACM,
|
|
.init = decode_init,
|
|
.close = decode_close,
|
|
FF_CODEC_DECODE_CB(decode_frame),
|
|
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1,
|
|
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
|
|
.priv_data_size = sizeof(InterplayACMContext),
|
|
};
|