libavcodec/adxenc.c
Go to the documentation of this file.
00001 /*
00002  * ADX ADPCM codecs
00003  * Copyright (c) 2001,2003 BERO
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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);              /* header signature */
00094     bytestream_put_be16(&buf, HEADER_SIZE - 4);     /* copyright offset */
00095     bytestream_put_byte(&buf, 3);                   /* encoding */
00096     bytestream_put_byte(&buf, BLOCK_SIZE);          /* block size */
00097     bytestream_put_byte(&buf, 4);                   /* sample size */
00098     bytestream_put_byte(&buf, avctx->channels);     /* channels */
00099     bytestream_put_be32(&buf, avctx->sample_rate);  /* sample rate */
00100     bytestream_put_be32(&buf, 0);                   /* total sample count */
00101     bytestream_put_be16(&buf, c->cutoff);           /* cutoff frequency */
00102     bytestream_put_byte(&buf, 3);                   /* version */
00103     bytestream_put_byte(&buf, 0);                   /* flags */
00104     bytestream_put_be32(&buf, 0);                   /* unknown */
00105     bytestream_put_be32(&buf, 0);                   /* loop enabled */
00106     bytestream_put_be16(&buf, 0);                   /* padding */
00107     bytestream_put_buffer(&buf, "(c)CRI", 6);       /* copyright signature */
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     /* the cutoff can be adjusted, but this seems to work pretty well */
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 };