You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
14 KiB

/*
* Wavesynth pseudo-codec
* Copyright (c) 2011 Nicolas George
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "avcodec.h"
#include "internal.h"
#define SIN_BITS 14
#define WS_MAX_CHANNELS 32
#define INF_TS 0x7FFFFFFFFFFFFFFF
#define PINK_UNIT 128
/*
Format of the extradata and packets
THIS INFORMATION IS NOT PART OF THE PUBLIC API OR ABI.
IT CAN CHANGE WITHOUT NOTIFICATION.
All numbers are in little endian.
The codec extradata define a set of intervals with uniform content.
Overlapping intervals are added together.
extradata:
uint32 number of intervals
... intervals
interval:
int64 start timestamp; time_base must be 1/sample_rate;
start timestamps must be in ascending order
int64 end timestamp
uint32 type
uint32 channels mask
... additional information, depends on type
sine interval (type fourcc "SINE"):
int32 start frequency, in 1/(1<<16) Hz
int32 end frequency
int32 start amplitude, 1<<16 is the full amplitude
int32 end amplitude
uint32 start phase, 0 is sin(0), 0x20000000 is sin(pi/2), etc.;
n | (1<<31) means to match the phase of previous channel #n
pink noise interval (type fourcc "NOIS"):
int32 start amplitude
int32 end amplitude
The input packets encode the time and duration of the requested segment.
packet:
int64 start timestamp
int32 duration
*/
enum ws_interval_type {
WS_SINE = MKTAG('S','I','N','E'),
WS_NOISE = MKTAG('N','O','I','S'),
};
struct ws_interval {
int64_t ts_start, ts_end;
uint64_t phi0, dphi0, ddphi;
uint64_t amp0, damp;
uint64_t phi, dphi, amp;
uint32_t channels;
enum ws_interval_type type;
int next;
};
struct wavesynth_context {
int64_t cur_ts;
int64_t next_ts;
int32_t *sin;
AVFrame frame;
struct ws_interval *inter;
uint32_t dither_state;
uint32_t pink_state;
int32_t pink_pool[PINK_UNIT];
unsigned pink_need, pink_pos;
int nb_inter;
int cur_inter;
int next_inter;
};
#define LCG_A 1284865837
#define LCG_C 4150755663
#define LCG_AI 849225893 /* A*AI = 1 [mod 1<<32] */
static uint32_t lcg_next(uint32_t *s)
{
*s = *s * LCG_A + LCG_C;
return *s;
}
static void lcg_seek(uint32_t *s, int64_t dt)
{
uint32_t a, c, t = *s;
if (dt >= 0) {
a = LCG_A;
c = LCG_C;
} else { /* coefficients for a step backward */
a = LCG_AI;
c = (uint32_t)(LCG_AI * LCG_C);
dt = -dt;
}
while (dt) {
if (dt & 1)
t = a * t + c;
c *= a + 1; /* coefficients for a double step */
a *= a;
dt >>= 1;
}
*s = t;
}
/* Emulate pink noise by summing white noise at the sampling frequency,
* white noise at half the sampling frequency (each value taken twice),
* etc., with a total of 8 octaves.
* This is known as the Voss-McCartney algorithm. */
static void pink_fill(struct wavesynth_context *ws)
{
int32_t vt[7] = { 0 }, v = 0;
int i, j;
ws->pink_pos = 0;
if (!ws->pink_need)
return;
for (i = 0; i < PINK_UNIT; i++) {
for (j = 0; j < 7; j++) {
if ((i >> j) & 1)
break;
v -= vt[j];
vt[j] = (int32_t)lcg_next(&ws->pink_state) >> 3;
v += vt[j];
}
ws->pink_pool[i] = v + ((int32_t)lcg_next(&ws->pink_state) >> 3);
}
lcg_next(&ws->pink_state); /* so we use exactly 256 steps */
}
/**
* @return (1<<64) * a / b, without overflow, if a < b
*/
static uint64_t frac64(uint64_t a, uint64_t b)
{
uint64_t r = 0;
int i;
if (b < (uint64_t)1 << 32) { /* b small, use two 32-bits steps */
a <<= 32;
return ((a / b) << 32) | ((a % b) << 32) / b;
}
if (b < (uint64_t)1 << 48) { /* b medium, use four 16-bits steps */
for (i = 0; i < 4; i++) {
a <<= 16;
r = (r << 16) | (a / b);
a %= b;
}
return r;
}
for (i = 63; i >= 0; i--) {
if (a >= (uint64_t)1 << 63 || a << 1 >= b) {
r |= (uint64_t)1 << i;
a = (a << 1) - b;
} else {
a <<= 1;
}
}
return r;
}
static uint64_t phi_at(struct ws_interval *in, int64_t ts)
{
uint64_t dt = ts - in->ts_start;
uint64_t dt2 = dt & 1 ? /* dt * (dt - 1) / 2 without overflow */
dt * ((dt - 1) >> 1) : (dt >> 1) * (dt - 1);
return in->phi0 + dt * in->dphi0 + dt2 * in->ddphi;
}
static void wavesynth_seek(struct wavesynth_context *ws, int64_t ts)
{
int *last, i;
struct ws_interval *in;
last = &ws->cur_inter;
for (i = 0; i < ws->nb_inter; i++) {
in = &ws->inter[i];
if (ts < in->ts_start)
break;
if (ts >= in->ts_end)
continue;
*last = i;
last = &in->next;
in->phi = phi_at(in, ts);
in->dphi = in->dphi0 + (ts - in->ts_start) * in->ddphi;
in->amp = in->amp0 + (ts - in->ts_start) * in->damp;
}
ws->next_inter = i;
ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS;
*last = -1;
lcg_seek(&ws->dither_state, ts - ws->cur_ts);
if (ws->pink_need) {
int64_t pink_ts_cur = (ws->cur_ts + PINK_UNIT - 1) & ~(PINK_UNIT - 1);
int64_t pink_ts_next = ts & ~(PINK_UNIT - 1);
int pos = ts & (PINK_UNIT - 1);
lcg_seek(&ws->pink_state, (pink_ts_next - pink_ts_cur) << 1);
if (pos) {
pink_fill(ws);
ws->pink_pos = pos;
} else {
ws->pink_pos = PINK_UNIT;
}
}
ws->cur_ts = ts;
}
static int wavesynth_parse_extradata(AVCodecContext *avc)
{
struct wavesynth_context *ws = avc->priv_data;
struct ws_interval *in;
uint8_t *edata, *edata_end;
int32_t f1, f2, a1, a2;
uint32_t phi;
int64_t dphi1, dphi2, dt, cur_ts = -0x8000000000000000;
int i;
if (avc->extradata_size < 4)
return AVERROR(EINVAL);
edata = avc->extradata;
edata_end = edata + avc->extradata_size;
ws->nb_inter = AV_RL32(edata);
edata += 4;
if (ws->nb_inter < 0)
return AVERROR(EINVAL);
ws->inter = av_calloc(ws->nb_inter, sizeof(*ws->inter));
if (!ws->inter)
return AVERROR(ENOMEM);
for (i = 0; i < ws->nb_inter; i++) {
in = &ws->inter[i];
if (edata_end - edata < 24)
return AVERROR(EINVAL);
in->ts_start = AV_RL64(edata + 0);
in->ts_end = AV_RL64(edata + 8);
in->type = AV_RL32(edata + 16);
in->channels = AV_RL32(edata + 20);
edata += 24;
if (in->ts_start < cur_ts || in->ts_end <= in->ts_start)
return AVERROR(EINVAL);
cur_ts = in->ts_start;
dt = in->ts_end - in->ts_start;
switch (in->type) {
case WS_SINE:
if (edata_end - edata < 20)
return AVERROR(EINVAL);
f1 = AV_RL32(edata + 0);
f2 = AV_RL32(edata + 4);
a1 = AV_RL32(edata + 8);
a2 = AV_RL32(edata + 12);
phi = AV_RL32(edata + 16);
edata += 20;
dphi1 = frac64(f1, (int64_t)avc->sample_rate << 16);
dphi2 = frac64(f2, (int64_t)avc->sample_rate << 16);
in->dphi0 = dphi1;
in->ddphi = (dphi2 - dphi1) / dt;
if (phi & 0x80000000) {
phi &= ~0x80000000;
if (phi >= i)
return AVERROR(EINVAL);
in->phi0 = phi_at(&ws->inter[phi], in->ts_start);
} else {
in->phi0 = (uint64_t)phi << 33;
}
break;
case WS_NOISE:
if (edata_end - edata < 8)
return AVERROR(EINVAL);
a1 = AV_RL32(edata + 0);
a2 = AV_RL32(edata + 4);
edata += 8;
break;
default:
return AVERROR(EINVAL);
}
in->amp0 = (int64_t)a1 << 32;
in->damp = (((int64_t)a2 << 32) - ((int64_t)a1 << 32)) / dt;
}
if (edata != edata_end)
return AVERROR(EINVAL);
return 0;
}
static av_cold int wavesynth_init(AVCodecContext *avc)
{
struct wavesynth_context *ws = avc->priv_data;
int i, r;
if (avc->channels > WS_MAX_CHANNELS) {
av_log(avc, AV_LOG_ERROR,
"This implementation is limited to %d channels.\n",
WS_MAX_CHANNELS);
return AVERROR(EINVAL);
}
r = wavesynth_parse_extradata(avc);
if (r < 0) {
av_log(avc, AV_LOG_ERROR, "Invalid intervals definitions.\n");
goto fail;
}
ws->sin = av_malloc(sizeof(*ws->sin) << SIN_BITS);
if (!ws->sin) {
r = AVERROR(ENOMEM);
goto fail;
}
for (i = 0; i < 1 << SIN_BITS; i++)
ws->sin[i] = floor(32767 * sin(2 * M_PI * i / (1 << SIN_BITS)));
ws->dither_state = MKTAG('D','I','T','H');
for (i = 0; i < ws->nb_inter; i++)
ws->pink_need += ws->inter[i].type == WS_NOISE;
ws->pink_state = MKTAG('P','I','N','K');
ws->pink_pos = PINK_UNIT;
avcodec_get_frame_defaults(&ws->frame);
avc->coded_frame = &ws->frame;
wavesynth_seek(ws, 0);
avc->sample_fmt = AV_SAMPLE_FMT_S16;
return 0;
fail:
av_free(ws->inter);
av_free(ws->sin);
return r;
}
static void wavesynth_synth_sample(struct wavesynth_context *ws, int64_t ts,
int32_t *channels)
{
int32_t amp, val, *cv;
struct ws_interval *in;
int i, *last, pink;
uint32_t c, all_ch = 0;
i = ws->cur_inter;
last = &ws->cur_inter;
if (ws->pink_pos == PINK_UNIT)
pink_fill(ws);
pink = ws->pink_pool[ws->pink_pos++] >> 16;
while (i >= 0) {
in = &ws->inter[i];
i = in->next;
if (ts >= in->ts_end) {
*last = i;
continue;
}
last = &in->next;
amp = in->amp >> 32;
in->amp += in->damp;
switch (in->type) {
case WS_SINE:
val = amp * ws->sin[in->phi >> (64 - SIN_BITS)];
in->phi += in->dphi;
in->dphi += in->ddphi;
break;
case WS_NOISE:
val = amp * pink;
break;
default:
val = 0;
}
all_ch |= in->channels;
for (c = in->channels, cv = channels; c; c >>= 1, cv++)
if (c & 1)
*cv += val;
}
val = (int32_t)lcg_next(&ws->dither_state) >> 16;
for (c = all_ch, cv = channels; c; c >>= 1, cv++)
if (c & 1)
*cv += val;
}
static void wavesynth_enter_intervals(struct wavesynth_context *ws, int64_t ts)
{
int *last, i;
struct ws_interval *in;
last = &ws->cur_inter;
for (i = ws->cur_inter; i >= 0; i = ws->inter[i].next)
last = &ws->inter[i].next;
for (i = ws->next_inter; i < ws->nb_inter; i++) {
in = &ws->inter[i];
if (ts < in->ts_start)
break;
if (ts >= in->ts_end)
continue;
*last = i;
last = &in->next;
in->phi = in->phi0;
in->dphi = in->dphi0;
in->amp = in->amp0;
}
ws->next_inter = i;
ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS;
*last = -1;
}
static int wavesynth_decode(AVCodecContext *avc, void *rframe, int *rgot_frame,
AVPacket *packet)
{
struct wavesynth_context *ws = avc->priv_data;
int64_t ts;
int duration;
int s, c, r;
int16_t *pcm;
int32_t channels[WS_MAX_CHANNELS];
*rgot_frame = 0;
if (packet->size != 12)
return AVERROR_INVALIDDATA;
ts = AV_RL64(packet->data);
if (ts != ws->cur_ts)
wavesynth_seek(ws, ts);
duration = AV_RL32(packet->data + 8);
if (duration <= 0)
return AVERROR(EINVAL);
ws->frame.nb_samples = duration;
Merge commit '759001c534287a96dc96d1e274665feb7059145d' * commit '759001c534287a96dc96d1e274665feb7059145d': lavc decoders: work with refcounted frames. Anton Khirnov (1): lavc decoders: work with refcounted frames. Clément Bœsch (47): lavc/ansi: reset file lavc/ansi: re-do refcounted frame changes from Anton fraps: reset file lavc/fraps: switch to refcounted frames gifdec: reset file lavc/gifdec: switch to refcounted frames dsicinav: resolve conflicts smc: resolve conflicts zmbv: resolve conflicts rpza: resolve conflicts vble: resolve conflicts xxan: resolve conflicts targa: resolve conflicts vmnc: resolve conflicts utvideodec: resolve conflicts tscc: resolve conflicts ulti: resolve conflicts ffv1dec: resolve conflicts dnxhddec: resolve conflicts v210dec: resolve conflicts vp3: resolve conflicts vcr1: resolve conflicts v210x: resolve conflicts wavpack: resolve conflicts pngdec: fix compilation roqvideodec: resolve conflicts pictordec: resolve conflicts mdec: resolve conflicts tiertexseqv: resolve conflicts smacker: resolve conflicts vb: resolve conflicts vqavideo: resolve conflicts xl: resolve conflicts tmv: resolve conflicts vmdav: resolve conflicts truemotion1: resolve conflicts truemotion2: resolve conflicts lcldec: fix compilation libcelt_dec: fix compilation qdrw: fix compilation r210dec: fix compilation rl2: fix compilation wnv1: fix compilation yop: fix compilation tiff: resolve conflicts interplayvideo: fix compilation qpeg: resolve conflicts (FIXME/TESTME). Hendrik Leppkes (33): 012v: convert to refcounted frames 8bps: fix compilation 8svx: resolve conflicts 4xm: resolve conflicts aasc: resolve conflicts bfi: fix compilation aura: fix compilation alsdec: resolve conflicts avrndec: convert to refcounted frames avuidec: convert to refcounted frames bintext: convert to refcounted frames cavsdec: resolve conflicts brender_pix: convert to refcounted frames cinepak: resolve conflicts cinepak: avoid using AVFrame struct directly in private context cljr: fix compilation cpia: convert to refcounted frames cscd: resolve conflicts iff: resolve conflicts and do proper conversion to refcounted frames 4xm: fix reference frame handling cyuv: fix compilation dxa: fix compilation eacmv: fix compilation eamad: fix compilation eatgv: fix compilation escape124: remove unused variable. escape130: convert to refcounted frames evrcdec: convert to refcounted frames exr: convert to refcounted frames mvcdec: convert to refcounted frames paf: properly free the frame data on decode close sgirle: convert to refcounted frames lavfi/moviesrc: use refcounted frames Michael Niedermayer (56): Merge commit '759001c534287a96dc96d1e274665feb7059145d' resolve conflicts in headers motion_est: resolve conflict mpeg4videodec: fix conflicts dpcm conflict fix dpx: fix conflicts indeo3: resolve confilcts kmvc: resolve conflicts kmvc: resolve conflicts h264: resolve conflicts utils: resolve conflicts rawdec: resolve conflcits mpegvideo: resolve conflicts svq1enc: resolve conflicts mpegvideo: dont clear data, fix assertion failure on fate vsynth1 with threads pthreads: resolve conflicts frame_thread_encoder: simple compilefix not yet tested snow: update to buffer refs crytsalhd: fix compile dirac: switch to new API sonic: update to new API svq1: resolve conflict, update to new API ffwavesynth: update to new buffer API g729: update to new API indeo5: fix compile j2kdec: update to new buffer API linopencore-amr: fix compile libvorbisdec: update to new API loco: fix compile paf: update to new API proresdec: update to new API vp56: update to new api / resolve conflicts xface: convert to refcounted frames xan: fix compile&fate v408: update to ref counted buffers v308: update to ref counted buffers yuv4dec: update to ref counted buffers y41p: update to ref counted frames xbm: update to refcounted frames targa_y216: update to refcounted buffers qpeg: fix fate/crash cdxl: fix fate tscc: fix reget buffer useage targa_y216dec: fix style msmpeg4: fix fate h264: ref_picture() copy fields that have been lost too update_frame_pool: use channel field h264: Put code that prevents deadlocks back mpegvideo: dont allow last == current wmalossless: fix buffer ref messup ff_alloc_picture: free tables in case of dimension mismatches h264: fix null pointer dereference and assertion failure frame_thread_encoder: update to bufrefs ec: fix used arrays snowdec: fix off by 1 error in dimensions check h264: disallow single unpaired fields as references of frames Paul B Mahol (2): lavc/vima: convert to refcounted frames sanm: convert to refcounted frames Conflicts: libavcodec/4xm.c libavcodec/8bps.c libavcodec/8svx.c libavcodec/aasc.c libavcodec/alsdec.c libavcodec/anm.c libavcodec/ansi.c libavcodec/avs.c libavcodec/bethsoftvideo.c libavcodec/bfi.c libavcodec/c93.c libavcodec/cavsdec.c libavcodec/cdgraphics.c libavcodec/cinepak.c libavcodec/cljr.c libavcodec/cscd.c libavcodec/dnxhddec.c libavcodec/dpcm.c libavcodec/dpx.c libavcodec/dsicinav.c libavcodec/dvdec.c libavcodec/dxa.c libavcodec/eacmv.c libavcodec/eamad.c libavcodec/eatgq.c libavcodec/eatgv.c libavcodec/eatqi.c libavcodec/error_resilience.c libavcodec/escape124.c libavcodec/ffv1.h libavcodec/ffv1dec.c libavcodec/flicvideo.c libavcodec/fraps.c libavcodec/frwu.c libavcodec/g723_1.c libavcodec/gifdec.c libavcodec/h264.c libavcodec/h264.h libavcodec/h264_direct.c libavcodec/h264_loopfilter.c libavcodec/h264_refs.c libavcodec/huffyuvdec.c libavcodec/idcinvideo.c libavcodec/iff.c libavcodec/indeo2.c libavcodec/indeo3.c libavcodec/internal.h libavcodec/interplayvideo.c libavcodec/ivi_common.c libavcodec/jvdec.c libavcodec/kgv1dec.c libavcodec/kmvc.c libavcodec/lagarith.c libavcodec/libopenjpegdec.c libavcodec/mdec.c libavcodec/mimic.c libavcodec/mjpegbdec.c libavcodec/mjpegdec.c libavcodec/mmvideo.c libavcodec/motion_est.c libavcodec/motionpixels.c libavcodec/mpc7.c libavcodec/mpeg12.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo.c libavcodec/mpegvideo.h libavcodec/msrle.c libavcodec/msvideo1.c libavcodec/nuv.c libavcodec/options_table.h libavcodec/pcx.c libavcodec/pictordec.c libavcodec/pngdec.c libavcodec/pnmdec.c libavcodec/pthread.c libavcodec/qpeg.c libavcodec/qtrle.c libavcodec/r210dec.c libavcodec/rawdec.c libavcodec/roqvideodec.c libavcodec/rpza.c libavcodec/smacker.c libavcodec/smc.c libavcodec/svq1dec.c libavcodec/svq1enc.c libavcodec/targa.c libavcodec/tiertexseqv.c libavcodec/tiff.c libavcodec/tmv.c libavcodec/truemotion1.c libavcodec/truemotion2.c libavcodec/tscc.c libavcodec/ulti.c libavcodec/utils.c libavcodec/utvideodec.c libavcodec/v210dec.c libavcodec/v210x.c libavcodec/vb.c libavcodec/vble.c libavcodec/vcr1.c libavcodec/vmdav.c libavcodec/vmnc.c libavcodec/vp3.c libavcodec/vp56.c libavcodec/vp56.h libavcodec/vp6.c libavcodec/vqavideo.c libavcodec/wavpack.c libavcodec/xl.c libavcodec/xxan.c libavcodec/zmbv.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
12 years ago
r = ff_get_buffer(avc, &ws->frame, 0);
if (r < 0)
return r;
pcm = (int16_t *)ws->frame.data[0];
for (s = 0; s < duration; s++, ts++) {
memset(channels, 0, avc->channels * sizeof(*channels));
if (ts >= ws->next_ts)
wavesynth_enter_intervals(ws, ts);
wavesynth_synth_sample(ws, ts, channels);
for (c = 0; c < avc->channels; c++)
*(pcm++) = channels[c] >> 16;
}
ws->cur_ts += duration;
*rgot_frame = 1;
*(AVFrame *)rframe = ws->frame;
return packet->size;
}
static av_cold int wavesynth_close(AVCodecContext *avc)
{
struct wavesynth_context *ws = avc->priv_data;
av_free(ws->sin);
av_free(ws->inter);
return 0;
}
AVCodec ff_ffwavesynth_decoder = {
.name = "wavesynth",
.type = AVMEDIA_TYPE_AUDIO,
Merge commit '36ef5369ee9b336febc2c270f8718cec4476cb85' * commit '36ef5369ee9b336febc2c270f8718cec4476cb85': Replace all CODEC_ID_* with AV_CODEC_ID_* lavc: add AV prefix to codec ids. Conflicts: doc/APIchanges doc/examples/decoding_encoding.c doc/examples/muxing.c ffmpeg.c ffprobe.c ffserver.c libavcodec/8svx.c libavcodec/avcodec.h libavcodec/dnxhd_parser.c libavcodec/dvdsubdec.c libavcodec/error_resilience.c libavcodec/h263dec.c libavcodec/libvorbisenc.c libavcodec/mjpeg_parser.c libavcodec/mjpegenc.c libavcodec/mpeg12.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo.c libavcodec/mpegvideo_enc.c libavcodec/pcm.c libavcodec/r210dec.c libavcodec/utils.c libavcodec/v210dec.c libavcodec/version.h libavdevice/alsa-audio-dec.c libavdevice/bktr.c libavdevice/v4l2.c libavformat/asfdec.c libavformat/asfenc.c libavformat/avformat.h libavformat/avidec.c libavformat/caf.c libavformat/electronicarts.c libavformat/flacdec.c libavformat/flvdec.c libavformat/flvenc.c libavformat/framecrcenc.c libavformat/img2.c libavformat/img2dec.c libavformat/img2enc.c libavformat/ipmovie.c libavformat/isom.c libavformat/matroska.c libavformat/matroskadec.c libavformat/matroskaenc.c libavformat/mov.c libavformat/movenc.c libavformat/mp3dec.c libavformat/mpeg.c libavformat/mpegts.c libavformat/mxf.c libavformat/mxfdec.c libavformat/mxfenc.c libavformat/nsvdec.c libavformat/nut.c libavformat/oggenc.c libavformat/pmpdec.c libavformat/rawdec.c libavformat/rawenc.c libavformat/riff.c libavformat/sdp.c libavformat/utils.c libavformat/vocenc.c libavformat/wtv.c libavformat/xmv.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
12 years ago
.id = AV_CODEC_ID_FFWAVESYNTH,
.priv_data_size = sizeof(struct wavesynth_context),
.init = wavesynth_init,
.close = wavesynth_close,
.decode = wavesynth_decode,
.capabilities = CODEC_CAP_DR1,
.long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"),
};