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 AVPacket *avpkt)
00052 {
00053 const uint8_t *buf = avpkt->data;
00054 int buf_size = avpkt->size;
00055
00056
00057 int in_size, out_size;
00058 int sample = 0;
00059 int i;
00060 short *samples = data;
00061
00062 if (!buf_size)
00063 return 0;
00064
00065 out_size = AV_RL16(&buf[0]);
00066 *data_size = out_size * 2;
00067 in_size = AV_RL16(&buf[2]);
00068 buf += 4;
00069
00070 if (out_size > *data_size) {
00071 av_log(avctx, AV_LOG_ERROR, "Frame is too large to fit in buffer\n");
00072 return -1;
00073 }
00074 if (in_size > buf_size) {
00075 av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
00076 return -1;
00077 }
00078 if (in_size == out_size) {
00079 for (i = 0; i < out_size; i++)
00080 *samples++ = (*buf++ - 0x80) << 8;
00081 return buf_size;
00082 }
00083
00084 while (out_size > 0) {
00085 int code;
00086 uint8_t count;
00087 code = (*buf) >> 6;
00088 count = (*buf) & 0x3F;
00089 buf++;
00090 switch(code) {
00091 case 0:
00092 for (count++; count > 0; count--) {
00093 code = *buf++;
00094 sample += ws_adpcm_2bit[code & 0x3];
00095 CLIP8(sample);
00096 *samples++ = sample << 8;
00097 sample += ws_adpcm_2bit[(code >> 2) & 0x3];
00098 CLIP8(sample);
00099 *samples++ = sample << 8;
00100 sample += ws_adpcm_2bit[(code >> 4) & 0x3];
00101 CLIP8(sample);
00102 *samples++ = sample << 8;
00103 sample += ws_adpcm_2bit[(code >> 6) & 0x3];
00104 CLIP8(sample);
00105 *samples++ = sample << 8;
00106 out_size -= 4;
00107 }
00108 break;
00109 case 1:
00110 for (count++; count > 0; count--) {
00111 code = *buf++;
00112 sample += ws_adpcm_4bit[code & 0xF];
00113 CLIP8(sample);
00114 *samples++ = sample << 8;
00115 sample += ws_adpcm_4bit[code >> 4];
00116 CLIP8(sample);
00117 *samples++ = sample << 8;
00118 out_size -= 2;
00119 }
00120 break;
00121 case 2:
00122 if (count & 0x20) {
00123 char t;
00124 t = count;
00125 t <<= 3;
00126 sample += t >> 3;
00127 *samples++ = sample << 8;
00128 out_size--;
00129 } else {
00130 for (count++; count > 0; count--) {
00131 *samples++ = (*buf++ - 0x80) << 8;
00132 out_size--;
00133 }
00134 sample = buf[-1] - 0x80;
00135 }
00136 break;
00137 default:
00138 for(count++; count > 0; count--) {
00139 *samples++ = sample << 8;
00140 out_size--;
00141 }
00142 }
00143 }
00144
00145 return buf_size;
00146 }
00147
00148 AVCodec ws_snd1_decoder = {
00149 "ws_snd1",
00150 AVMEDIA_TYPE_AUDIO,
00151 CODEC_ID_WESTWOOD_SND1,
00152 0,
00153 ws_snd_decode_init,
00154 NULL,
00155 NULL,
00156 ws_snd_decode_frame,
00157 .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"),
00158 };