• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

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 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 <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     if (avctx->channels != 1) {
00045         av_log_ask_for_sample(avctx, "unsupported number of channels\n");
00046         return AVERROR(EINVAL);
00047     }
00048 
00049     avctx->sample_fmt = AV_SAMPLE_FMT_U8;
00050     return 0;
00051 }
00052 
00053 static int ws_snd_decode_frame(AVCodecContext *avctx,
00054                 void *data, int *data_size,
00055                 AVPacket *avpkt)
00056 {
00057     const uint8_t *buf = avpkt->data;
00058     int buf_size = avpkt->size;
00059 //    WSSNDContext *c = avctx->priv_data;
00060 
00061     int in_size, out_size;
00062     int sample = 128;
00063     int i;
00064     uint8_t *samples = data;
00065 
00066     if (!buf_size)
00067         return 0;
00068 
00069     if (buf_size < 4) {
00070         av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
00071         return AVERROR(EINVAL);
00072     }
00073 
00074     out_size = AV_RL16(&buf[0]);
00075     in_size = AV_RL16(&buf[2]);
00076     buf += 4;
00077 
00078     if (out_size > *data_size) {
00079         av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
00080         return -1;
00081     }
00082     if (in_size > buf_size) {
00083         av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
00084         return -1;
00085     }
00086 
00087     if (in_size == out_size) {
00088         for (i = 0; i < out_size; i++)
00089             *samples++ = *buf++;
00090         *data_size = out_size;
00091         return buf_size;
00092     }
00093 
00094     while (out_size > 0 && buf - avpkt->data < buf_size) {
00095         int code, smp, size;
00096         uint8_t count;
00097         code = (*buf) >> 6;
00098         count = (*buf) & 0x3F;
00099         buf++;
00100 
00101         /* make sure we don't write more than out_size samples */
00102         switch (code) {
00103         case 0:  smp = 4*(count+1);                    break;
00104         case 1:  smp = 2*(count+1);                    break;
00105         case 2:  smp = (count & 0x20) ? 1 : count + 1; break;
00106         default: smp = count + 1;                      break;
00107         }
00108         if (out_size < smp) {
00109             out_size = 0;
00110             break;
00111         }
00112 
00113         /* make sure we don't read past the input buffer */
00114         size = ((code == 2 && (count & 0x20)) || code == 3) ? 0 : count + 1;
00115         if ((buf - avpkt->data) + size > buf_size)
00116             break;
00117 
00118         switch(code) {
00119         case 0: /* ADPCM 2-bit */
00120             for (count++; count > 0; count--) {
00121                 code = *buf++;
00122                 sample += ws_adpcm_2bit[code & 0x3];
00123                 sample = av_clip_uint8(sample);
00124                 *samples++ = sample;
00125                 sample += ws_adpcm_2bit[(code >> 2) & 0x3];
00126                 sample = av_clip_uint8(sample);
00127                 *samples++ = sample;
00128                 sample += ws_adpcm_2bit[(code >> 4) & 0x3];
00129                 sample = av_clip_uint8(sample);
00130                 *samples++ = sample;
00131                 sample += ws_adpcm_2bit[(code >> 6) & 0x3];
00132                 sample = av_clip_uint8(sample);
00133                 *samples++ = sample;
00134                 out_size -= 4;
00135             }
00136             break;
00137         case 1: /* ADPCM 4-bit */
00138             for (count++; count > 0; count--) {
00139                 code = *buf++;
00140                 sample += ws_adpcm_4bit[code & 0xF];
00141                 sample = av_clip_uint8(sample);
00142                 *samples++ = sample;
00143                 sample += ws_adpcm_4bit[code >> 4];
00144                 sample = av_clip_uint8(sample);
00145                 *samples++ = sample;
00146                 out_size -= 2;
00147             }
00148             break;
00149         case 2: /* no compression */
00150             if (count & 0x20) { /* big delta */
00151                 int8_t t;
00152                 t = count;
00153                 t <<= 3;
00154                 sample += t >> 3;
00155                 sample = av_clip_uint8(sample);
00156                 *samples++ = sample;
00157                 out_size--;
00158             } else { /* copy */
00159                 for (count++; count > 0; count--) {
00160                     *samples++ = *buf++;
00161                     out_size--;
00162                 }
00163                 sample = buf[-1];
00164             }
00165             break;
00166         default: /* run */
00167             for(count++; count > 0; count--) {
00168                 *samples++ = sample;
00169                 out_size--;
00170             }
00171         }
00172     }
00173 
00174     *data_size = samples - (uint8_t *)data;
00175 
00176     return buf_size;
00177 }
00178 
00179 AVCodec ff_ws_snd1_decoder = {
00180     "ws_snd1",
00181     AVMEDIA_TYPE_AUDIO,
00182     CODEC_ID_WESTWOOD_SND1,
00183     0,
00184     ws_snd_decode_init,
00185     NULL,
00186     NULL,
00187     ws_snd_decode_frame,
00188     .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"),
00189 };

Generated on Fri Feb 22 2013 07:24:29 for FFmpeg by  doxygen 1.7.1