00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avcodec.h"
00023 #include "adx.h"
00024 #include "bytestream.h"
00025 #include "put_bits.h"
00026
00036 static void adx_encode(ADXContext *c, uint8_t *adx, const int16_t *wav,
00037 ADXChannelState *prev, int channels)
00038 {
00039 PutBitContext pb;
00040 int scale;
00041 int i, j;
00042 int s0, s1, s2, d;
00043 int max = 0;
00044 int min = 0;
00045 int data[BLOCK_SAMPLES];
00046
00047 s1 = prev->s1;
00048 s2 = prev->s2;
00049 for (i = 0, j = 0; j < 32; i += channels, j++) {
00050 s0 = wav[i];
00051 d = ((s0 << COEFF_BITS) - c->coeff[0] * s1 - c->coeff[1] * s2) >> COEFF_BITS;
00052 data[j] = d;
00053 if (max < d)
00054 max = d;
00055 if (min > d)
00056 min = d;
00057 s2 = s1;
00058 s1 = s0;
00059 }
00060 prev->s1 = s1;
00061 prev->s2 = s2;
00062
00063 if (max == 0 && min == 0) {
00064 memset(adx, 0, BLOCK_SIZE);
00065 return;
00066 }
00067
00068 if (max / 7 > -min / 8)
00069 scale = max / 7;
00070 else
00071 scale = -min / 8;
00072
00073 if (scale == 0)
00074 scale = 1;
00075
00076 AV_WB16(adx, scale);
00077
00078 init_put_bits(&pb, adx + 2, 16);
00079 for (i = 0; i < BLOCK_SAMPLES; i++)
00080 put_sbits(&pb, 4, av_clip(data[i] / scale, -8, 7));
00081 flush_put_bits(&pb);
00082 }
00083
00084 #define HEADER_SIZE 36
00085
00086 static int adx_encode_header(AVCodecContext *avctx, uint8_t *buf, int bufsize)
00087 {
00088 ADXContext *c = avctx->priv_data;
00089
00090 if (bufsize < HEADER_SIZE)
00091 return AVERROR(EINVAL);
00092
00093 bytestream_put_be16(&buf, 0x8000);
00094 bytestream_put_be16(&buf, HEADER_SIZE - 4);
00095 bytestream_put_byte(&buf, 3);
00096 bytestream_put_byte(&buf, BLOCK_SIZE);
00097 bytestream_put_byte(&buf, 4);
00098 bytestream_put_byte(&buf, avctx->channels);
00099 bytestream_put_be32(&buf, avctx->sample_rate);
00100 bytestream_put_be32(&buf, 0);
00101 bytestream_put_be16(&buf, c->cutoff);
00102 bytestream_put_byte(&buf, 3);
00103 bytestream_put_byte(&buf, 0);
00104 bytestream_put_be32(&buf, 0);
00105 bytestream_put_be32(&buf, 0);
00106 bytestream_put_be16(&buf, 0);
00107 bytestream_put_buffer(&buf, "(c)CRI", 6);
00108
00109 return HEADER_SIZE;
00110 }
00111
00112 static av_cold int adx_encode_init(AVCodecContext *avctx)
00113 {
00114 ADXContext *c = avctx->priv_data;
00115
00116 if (avctx->channels > 2) {
00117 av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n");
00118 return AVERROR(EINVAL);
00119 }
00120 avctx->frame_size = BLOCK_SAMPLES;
00121
00122 avctx->coded_frame = avcodec_alloc_frame();
00123
00124
00125 c->cutoff = 500;
00126 ff_adx_calculate_coeffs(c->cutoff, avctx->sample_rate, COEFF_BITS, c->coeff);
00127
00128 return 0;
00129 }
00130
00131 static av_cold int adx_encode_close(AVCodecContext *avctx)
00132 {
00133 av_freep(&avctx->coded_frame);
00134 return 0;
00135 }
00136
00137 static int adx_encode_frame(AVCodecContext *avctx, uint8_t *frame,
00138 int buf_size, void *data)
00139 {
00140 ADXContext *c = avctx->priv_data;
00141 const int16_t *samples = data;
00142 uint8_t *dst = frame;
00143 int ch;
00144
00145 if (!c->header_parsed) {
00146 int hdrsize;
00147 if ((hdrsize = adx_encode_header(avctx, dst, buf_size)) < 0) {
00148 av_log(avctx, AV_LOG_ERROR, "output buffer is too small\n");
00149 return AVERROR(EINVAL);
00150 }
00151 dst += hdrsize;
00152 buf_size -= hdrsize;
00153 c->header_parsed = 1;
00154 }
00155 if (buf_size < BLOCK_SIZE * avctx->channels) {
00156 av_log(avctx, AV_LOG_ERROR, "output buffer is too small\n");
00157 return AVERROR(EINVAL);
00158 }
00159
00160 for (ch = 0; ch < avctx->channels; ch++) {
00161 adx_encode(c, dst, samples + ch, &c->prev[ch], avctx->channels);
00162 dst += BLOCK_SIZE;
00163 }
00164 return dst - frame;
00165 }
00166
00167 AVCodec ff_adpcm_adx_encoder = {
00168 .name = "adpcm_adx",
00169 .type = AVMEDIA_TYPE_AUDIO,
00170 .id = CODEC_ID_ADPCM_ADX,
00171 .priv_data_size = sizeof(ADXContext),
00172 .init = adx_encode_init,
00173 .encode = adx_encode_frame,
00174 .close = adx_encode_close,
00175 .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
00176 AV_SAMPLE_FMT_NONE },
00177 .long_name = NULL_IF_CONFIG_SMALL("SEGA CRI ADX ADPCM"),
00178 };