Libav 0.7.1
libavcodec/ws-snd1.c
Go to the documentation of this file.
00001 /*
00002  * Westwood SNDx codecs
00003  * Copyright (c) 2005 Konstantin Shishkov
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include <stdint.h>
00023 #include "libavutil/intreadwrite.h"
00024 #include "avcodec.h"
00025 
00035 static const int8_t ws_adpcm_2bit[] = { -2, -1, 0, 1};
00036 static const int8_t ws_adpcm_4bit[] = {
00037     -9, -8, -6, -5, -4, -3, -2, -1,
00038      0,  1,  2,  3,  4,  5,  6,  8 };
00039 
00040 static av_cold int ws_snd_decode_init(AVCodecContext * avctx)
00041 {
00042 //    WSSNDContext *c = avctx->priv_data;
00043 
00044     avctx->sample_fmt = AV_SAMPLE_FMT_U8;
00045     return 0;
00046 }
00047 
00048 static int ws_snd_decode_frame(AVCodecContext *avctx,
00049                 void *data, int *data_size,
00050                 AVPacket *avpkt)
00051 {
00052     const uint8_t *buf = avpkt->data;
00053     int buf_size = avpkt->size;
00054 //    WSSNDContext *c = avctx->priv_data;
00055 
00056     int in_size, out_size;
00057     int sample = 128;
00058     int i;
00059     uint8_t *samples = data;
00060 
00061     if (!buf_size)
00062         return 0;
00063 
00064     if (buf_size < 4) {
00065         av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
00066         return AVERROR(EINVAL);
00067     }
00068 
00069     out_size = AV_RL16(&buf[0]);
00070     in_size = AV_RL16(&buf[2]);
00071     buf += 4;
00072 
00073     if (out_size > *data_size) {
00074         av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
00075         return -1;
00076     }
00077     if (in_size > buf_size) {
00078         av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
00079         return -1;
00080     }
00081 
00082     if (in_size == out_size) {
00083         for (i = 0; i < out_size; i++)
00084             *samples++ = *buf++;
00085         *data_size = out_size;
00086         return buf_size;
00087     }
00088 
00089     while (out_size > 0 && buf - avpkt->data < buf_size) {
00090         int code, smp, size;
00091         uint8_t count;
00092         code = (*buf) >> 6;
00093         count = (*buf) & 0x3F;
00094         buf++;
00095 
00096         /* make sure we don't write more than out_size samples */
00097         switch (code) {
00098         case 0:  smp = 4*(count+1);                    break;
00099         case 1:  smp = 2*(count+1);                    break;
00100         case 2:  smp = (count & 0x20) ? 1 : count + 1; break;
00101         default: smp = count + 1;                      break;
00102         }
00103         if (out_size < smp) {
00104             out_size = 0;
00105             break;
00106         }
00107 
00108         /* make sure we don't read past the input buffer */
00109         size = ((code == 2 && (count & 0x20)) || code == 3) ? 0 : count + 1;
00110         if ((buf - avpkt->data) + size > buf_size)
00111             break;
00112 
00113         switch(code) {
00114         case 0: /* ADPCM 2-bit */
00115             for (count++; count > 0; count--) {
00116                 code = *buf++;
00117                 sample += ws_adpcm_2bit[code & 0x3];
00118                 sample = av_clip_uint8(sample);
00119                 *samples++ = sample;
00120                 sample += ws_adpcm_2bit[(code >> 2) & 0x3];
00121                 sample = av_clip_uint8(sample);
00122                 *samples++ = sample;
00123                 sample += ws_adpcm_2bit[(code >> 4) & 0x3];
00124                 sample = av_clip_uint8(sample);
00125                 *samples++ = sample;
00126                 sample += ws_adpcm_2bit[(code >> 6) & 0x3];
00127                 sample = av_clip_uint8(sample);
00128                 *samples++ = sample;
00129                 out_size -= 4;
00130             }
00131             break;
00132         case 1: /* ADPCM 4-bit */
00133             for (count++; count > 0; count--) {
00134                 code = *buf++;
00135                 sample += ws_adpcm_4bit[code & 0xF];
00136                 sample = av_clip_uint8(sample);
00137                 *samples++ = sample;
00138                 sample += ws_adpcm_4bit[code >> 4];
00139                 sample = av_clip_uint8(sample);
00140                 *samples++ = sample;
00141                 out_size -= 2;
00142             }
00143             break;
00144         case 2: /* no compression */
00145             if (count & 0x20) { /* big delta */
00146                 int8_t t;
00147                 t = count;
00148                 t <<= 3;
00149                 sample += t >> 3;
00150                 sample = av_clip_uint8(sample);
00151                 *samples++ = sample;
00152                 out_size--;
00153             } else { /* copy */
00154                 for (count++; count > 0; count--) {
00155                     *samples++ = *buf++;
00156                     out_size--;
00157                 }
00158                 sample = buf[-1];
00159             }
00160             break;
00161         default: /* run */
00162             for(count++; count > 0; count--) {
00163                 *samples++ = sample;
00164                 out_size--;
00165             }
00166         }
00167     }
00168 
00169     *data_size = samples - (uint8_t *)data;
00170 
00171     return buf_size;
00172 }
00173 
00174 AVCodec ff_ws_snd1_decoder = {
00175     "ws_snd1",
00176     AVMEDIA_TYPE_AUDIO,
00177     CODEC_ID_WESTWOOD_SND1,
00178     0,
00179     ws_snd_decode_init,
00180     NULL,
00181     NULL,
00182     ws_snd_decode_frame,
00183     .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"),
00184 };