1/* 2 * Westwood SNDx codecs 3 * Copyright (c) 2005 Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/intreadwrite.h" 23#include "avcodec.h" 24 25/** 26 * @file libavcodec/ws-snd1.c 27 * Westwood SNDx codecs. 28 * 29 * Reference documents about VQA format and its audio codecs 30 * can be found here: 31 * http://www.multimedia.cx 32 */ 33 34static const char ws_adpcm_2bit[] = { -2, -1, 0, 1}; 35static const char ws_adpcm_4bit[] = { 36 -9, -8, -6, -5, -4, -3, -2, -1, 37 0, 1, 2, 3, 4, 5, 6, 8 }; 38 39#define CLIP8(a) if(a>127)a=127;if(a<-128)a=-128; 40 41static av_cold int ws_snd_decode_init(AVCodecContext * avctx) 42{ 43// WSSNDContext *c = avctx->priv_data; 44 45 avctx->sample_fmt = SAMPLE_FMT_S16; 46 return 0; 47} 48 49static int ws_snd_decode_frame(AVCodecContext *avctx, 50 void *data, int *data_size, 51 const uint8_t *buf, int buf_size) 52{ 53// WSSNDContext *c = avctx->priv_data; 54 55 int in_size, out_size; 56 int sample = 0; 57 int i; 58 short *samples = data; 59 60 if (!buf_size) 61 return 0; 62 63 out_size = AV_RL16(&buf[0]); 64 *data_size = out_size * 2; 65 in_size = AV_RL16(&buf[2]); 66 buf += 4; 67 68 if (out_size > *data_size) { 69 av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n"); 70 return -1; 71 } 72 if (in_size > buf_size) { 73 av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n"); 74 return -1; 75 } 76 if (in_size == out_size) { 77 for (i = 0; i < out_size; i++) 78 *samples++ = (*buf++ - 0x80) << 8; 79 return buf_size; 80 } 81 82 while (out_size > 0) { 83 int code; 84 uint8_t count; 85 code = (*buf) >> 6; 86 count = (*buf) & 0x3F; 87 buf++; 88 switch(code) { 89 case 0: /* ADPCM 2-bit */ 90 for (count++; count > 0; count--) { 91 code = *buf++; 92 sample += ws_adpcm_2bit[code & 0x3]; 93 CLIP8(sample); 94 *samples++ = sample << 8; 95 sample += ws_adpcm_2bit[(code >> 2) & 0x3]; 96 CLIP8(sample); 97 *samples++ = sample << 8; 98 sample += ws_adpcm_2bit[(code >> 4) & 0x3]; 99 CLIP8(sample); 100 *samples++ = sample << 8; 101 sample += ws_adpcm_2bit[(code >> 6) & 0x3]; 102 CLIP8(sample); 103 *samples++ = sample << 8; 104 out_size -= 4; 105 } 106 break; 107 case 1: /* ADPCM 4-bit */ 108 for (count++; count > 0; count--) { 109 code = *buf++; 110 sample += ws_adpcm_4bit[code & 0xF]; 111 CLIP8(sample); 112 *samples++ = sample << 8; 113 sample += ws_adpcm_4bit[code >> 4]; 114 CLIP8(sample); 115 *samples++ = sample << 8; 116 out_size -= 2; 117 } 118 break; 119 case 2: /* no compression */ 120 if (count & 0x20) { /* big delta */ 121 char t; 122 t = count; 123 t <<= 3; 124 sample += t >> 3; 125 *samples++ = sample << 8; 126 out_size--; 127 } else { /* copy */ 128 for (count++; count > 0; count--) { 129 *samples++ = (*buf++ - 0x80) << 8; 130 out_size--; 131 } 132 sample = buf[-1] - 0x80; 133 } 134 break; 135 default: /* run */ 136 for(count++; count > 0; count--) { 137 *samples++ = sample << 8; 138 out_size--; 139 } 140 } 141 } 142 143 return buf_size; 144} 145 146AVCodec ws_snd1_decoder = { 147 "ws_snd1", 148 CODEC_TYPE_AUDIO, 149 CODEC_ID_WESTWOOD_SND1, 150 0, 151 ws_snd_decode_init, 152 NULL, 153 NULL, 154 ws_snd_decode_frame, 155 .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"), 156}; 157