00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "avcodec.h"
00024
00034 static const char ws_adpcm_2bit[] = { -2, -1, 0, 1};
00035 static const char ws_adpcm_4bit[] = {
00036 -9, -8, -6, -5, -4, -3, -2, -1,
00037 0, 1, 2, 3, 4, 5, 6, 8 };
00038
00039 #define CLIP8(a) if(a>127)a=127;if(a<-128)a=-128;
00040
00041 static av_cold int ws_snd_decode_init(AVCodecContext * avctx)
00042 {
00043
00044
00045 avctx->sample_fmt = SAMPLE_FMT_S16;
00046 return 0;
00047 }
00048
00049 static int ws_snd_decode_frame(AVCodecContext *avctx,
00050 void *data, int *data_size,
00051 const uint8_t *buf, int buf_size)
00052 {
00053
00054
00055 int in_size, out_size;
00056 int sample = 0;
00057 int i;
00058 short *samples = data;
00059
00060 if (!buf_size)
00061 return 0;
00062
00063 out_size = AV_RL16(&buf[0]);
00064 *data_size = out_size * 2;
00065 in_size = AV_RL16(&buf[2]);
00066 buf += 4;
00067
00068 if (out_size > *data_size) {
00069 av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
00070 return -1;
00071 }
00072 if (in_size > buf_size) {
00073 av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
00074 return -1;
00075 }
00076 if (in_size == out_size) {
00077 for (i = 0; i < out_size; i++)
00078 *samples++ = (*buf++ - 0x80) << 8;
00079 return buf_size;
00080 }
00081
00082 while (out_size > 0) {
00083 int code;
00084 uint8_t count;
00085 code = (*buf) >> 6;
00086 count = (*buf) & 0x3F;
00087 buf++;
00088 switch(code) {
00089 case 0:
00090 for (count++; count > 0; count--) {
00091 code = *buf++;
00092 sample += ws_adpcm_2bit[code & 0x3];
00093 CLIP8(sample);
00094 *samples++ = sample << 8;
00095 sample += ws_adpcm_2bit[(code >> 2) & 0x3];
00096 CLIP8(sample);
00097 *samples++ = sample << 8;
00098 sample += ws_adpcm_2bit[(code >> 4) & 0x3];
00099 CLIP8(sample);
00100 *samples++ = sample << 8;
00101 sample += ws_adpcm_2bit[(code >> 6) & 0x3];
00102 CLIP8(sample);
00103 *samples++ = sample << 8;
00104 out_size -= 4;
00105 }
00106 break;
00107 case 1:
00108 for (count++; count > 0; count--) {
00109 code = *buf++;
00110 sample += ws_adpcm_4bit[code & 0xF];
00111 CLIP8(sample);
00112 *samples++ = sample << 8;
00113 sample += ws_adpcm_4bit[code >> 4];
00114 CLIP8(sample);
00115 *samples++ = sample << 8;
00116 out_size -= 2;
00117 }
00118 break;
00119 case 2:
00120 if (count & 0x20) {
00121 char t;
00122 t = count;
00123 t <<= 3;
00124 sample += t >> 3;
00125 *samples++ = sample << 8;
00126 out_size--;
00127 } else {
00128 for (count++; count > 0; count--) {
00129 *samples++ = (*buf++ - 0x80) << 8;
00130 out_size--;
00131 }
00132 sample = buf[-1] - 0x80;
00133 }
00134 break;
00135 default:
00136 for(count++; count > 0; count--) {
00137 *samples++ = sample << 8;
00138 out_size--;
00139 }
00140 }
00141 }
00142
00143 return buf_size;
00144 }
00145
00146 AVCodec ws_snd1_decoder = {
00147 "ws_snd1",
00148 CODEC_TYPE_AUDIO,
00149 CODEC_ID_WESTWOOD_SND1,
00150 0,
00151 ws_snd_decode_init,
00152 NULL,
00153 NULL,
00154 ws_snd_decode_frame,
00155 .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"),
00156 };