yading@10
|
1 /*
|
yading@10
|
2 * Westwood SNDx codecs
|
yading@10
|
3 * Copyright (c) 2005 Konstantin Shishkov
|
yading@10
|
4 *
|
yading@10
|
5 * This file is part of FFmpeg.
|
yading@10
|
6 *
|
yading@10
|
7 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
8 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
9 * License as published by the Free Software Foundation; either
|
yading@10
|
10 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
11 *
|
yading@10
|
12 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
15 * Lesser General Public License for more details.
|
yading@10
|
16 *
|
yading@10
|
17 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
18 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 #include <stdint.h>
|
yading@10
|
23
|
yading@10
|
24 #include "libavutil/channel_layout.h"
|
yading@10
|
25 #include "libavutil/common.h"
|
yading@10
|
26 #include "libavutil/intreadwrite.h"
|
yading@10
|
27 #include "avcodec.h"
|
yading@10
|
28 #include "internal.h"
|
yading@10
|
29
|
yading@10
|
30 /**
|
yading@10
|
31 * @file
|
yading@10
|
32 * Westwood SNDx codecs
|
yading@10
|
33 *
|
yading@10
|
34 * Reference documents about VQA format and its audio codecs
|
yading@10
|
35 * can be found here:
|
yading@10
|
36 * http://www.multimedia.cx
|
yading@10
|
37 */
|
yading@10
|
38
|
yading@10
|
39 static const int8_t ws_adpcm_4bit[] = {
|
yading@10
|
40 -9, -8, -6, -5, -4, -3, -2, -1,
|
yading@10
|
41 0, 1, 2, 3, 4, 5, 6, 8
|
yading@10
|
42 };
|
yading@10
|
43
|
yading@10
|
44 static av_cold int ws_snd_decode_init(AVCodecContext *avctx)
|
yading@10
|
45 {
|
yading@10
|
46 avctx->channels = 1;
|
yading@10
|
47 avctx->channel_layout = AV_CH_LAYOUT_MONO;
|
yading@10
|
48 avctx->sample_fmt = AV_SAMPLE_FMT_U8;
|
yading@10
|
49
|
yading@10
|
50 return 0;
|
yading@10
|
51 }
|
yading@10
|
52
|
yading@10
|
53 static int ws_snd_decode_frame(AVCodecContext *avctx, void *data,
|
yading@10
|
54 int *got_frame_ptr, AVPacket *avpkt)
|
yading@10
|
55 {
|
yading@10
|
56 AVFrame *frame = data;
|
yading@10
|
57 const uint8_t *buf = avpkt->data;
|
yading@10
|
58 int buf_size = avpkt->size;
|
yading@10
|
59
|
yading@10
|
60 int in_size, out_size, ret;
|
yading@10
|
61 int sample = 128;
|
yading@10
|
62 uint8_t *samples;
|
yading@10
|
63 uint8_t *samples_end;
|
yading@10
|
64
|
yading@10
|
65 if (!buf_size)
|
yading@10
|
66 return 0;
|
yading@10
|
67
|
yading@10
|
68 if (buf_size < 4) {
|
yading@10
|
69 av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
|
yading@10
|
70 return AVERROR(EINVAL);
|
yading@10
|
71 }
|
yading@10
|
72
|
yading@10
|
73 out_size = AV_RL16(&buf[0]);
|
yading@10
|
74 in_size = AV_RL16(&buf[2]);
|
yading@10
|
75 buf += 4;
|
yading@10
|
76
|
yading@10
|
77 if (in_size > buf_size) {
|
yading@10
|
78 av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
|
yading@10
|
79 return AVERROR_INVALIDDATA;
|
yading@10
|
80 }
|
yading@10
|
81
|
yading@10
|
82 /* get output buffer */
|
yading@10
|
83 frame->nb_samples = out_size;
|
yading@10
|
84 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
|
yading@10
|
85 return ret;
|
yading@10
|
86 samples = frame->data[0];
|
yading@10
|
87 samples_end = samples + out_size;
|
yading@10
|
88
|
yading@10
|
89 if (in_size == out_size) {
|
yading@10
|
90 memcpy(samples, buf, out_size);
|
yading@10
|
91 *got_frame_ptr = 1;
|
yading@10
|
92 return buf_size;
|
yading@10
|
93 }
|
yading@10
|
94
|
yading@10
|
95 while (samples < samples_end && buf - avpkt->data < buf_size) {
|
yading@10
|
96 int code, smp, size;
|
yading@10
|
97 uint8_t count;
|
yading@10
|
98 code = *buf >> 6;
|
yading@10
|
99 count = *buf & 0x3F;
|
yading@10
|
100 buf++;
|
yading@10
|
101
|
yading@10
|
102 /* make sure we don't write past the output buffer */
|
yading@10
|
103 switch (code) {
|
yading@10
|
104 case 0: smp = 4 * (count + 1); break;
|
yading@10
|
105 case 1: smp = 2 * (count + 1); break;
|
yading@10
|
106 case 2: smp = (count & 0x20) ? 1 : count + 1; break;
|
yading@10
|
107 default: smp = count + 1; break;
|
yading@10
|
108 }
|
yading@10
|
109 if (samples_end - samples < smp)
|
yading@10
|
110 break;
|
yading@10
|
111
|
yading@10
|
112 /* make sure we don't read past the input buffer */
|
yading@10
|
113 size = ((code == 2 && (count & 0x20)) || code == 3) ? 0 : count + 1;
|
yading@10
|
114 if ((buf - avpkt->data) + size > buf_size)
|
yading@10
|
115 break;
|
yading@10
|
116
|
yading@10
|
117 switch (code) {
|
yading@10
|
118 case 0: /* ADPCM 2-bit */
|
yading@10
|
119 for (count++; count > 0; count--) {
|
yading@10
|
120 code = *buf++;
|
yading@10
|
121 sample += ( code & 0x3) - 2;
|
yading@10
|
122 sample = av_clip_uint8(sample);
|
yading@10
|
123 *samples++ = sample;
|
yading@10
|
124 sample += ((code >> 2) & 0x3) - 2;
|
yading@10
|
125 sample = av_clip_uint8(sample);
|
yading@10
|
126 *samples++ = sample;
|
yading@10
|
127 sample += ((code >> 4) & 0x3) - 2;
|
yading@10
|
128 sample = av_clip_uint8(sample);
|
yading@10
|
129 *samples++ = sample;
|
yading@10
|
130 sample += (code >> 6) - 2;
|
yading@10
|
131 sample = av_clip_uint8(sample);
|
yading@10
|
132 *samples++ = sample;
|
yading@10
|
133 }
|
yading@10
|
134 break;
|
yading@10
|
135 case 1: /* ADPCM 4-bit */
|
yading@10
|
136 for (count++; count > 0; count--) {
|
yading@10
|
137 code = *buf++;
|
yading@10
|
138 sample += ws_adpcm_4bit[code & 0xF];
|
yading@10
|
139 sample = av_clip_uint8(sample);
|
yading@10
|
140 *samples++ = sample;
|
yading@10
|
141 sample += ws_adpcm_4bit[code >> 4];
|
yading@10
|
142 sample = av_clip_uint8(sample);
|
yading@10
|
143 *samples++ = sample;
|
yading@10
|
144 }
|
yading@10
|
145 break;
|
yading@10
|
146 case 2: /* no compression */
|
yading@10
|
147 if (count & 0x20) { /* big delta */
|
yading@10
|
148 int8_t t;
|
yading@10
|
149 t = count;
|
yading@10
|
150 t <<= 3;
|
yading@10
|
151 sample += t >> 3;
|
yading@10
|
152 sample = av_clip_uint8(sample);
|
yading@10
|
153 *samples++ = sample;
|
yading@10
|
154 } else { /* copy */
|
yading@10
|
155 memcpy(samples, buf, smp);
|
yading@10
|
156 samples += smp;
|
yading@10
|
157 buf += smp;
|
yading@10
|
158 sample = buf[-1];
|
yading@10
|
159 }
|
yading@10
|
160 break;
|
yading@10
|
161 default: /* run */
|
yading@10
|
162 memset(samples, sample, smp);
|
yading@10
|
163 samples += smp;
|
yading@10
|
164 }
|
yading@10
|
165 }
|
yading@10
|
166
|
yading@10
|
167 frame->nb_samples = samples - frame->data[0];
|
yading@10
|
168 *got_frame_ptr = 1;
|
yading@10
|
169
|
yading@10
|
170 return buf_size;
|
yading@10
|
171 }
|
yading@10
|
172
|
yading@10
|
173 AVCodec ff_ws_snd1_decoder = {
|
yading@10
|
174 .name = "ws_snd1",
|
yading@10
|
175 .type = AVMEDIA_TYPE_AUDIO,
|
yading@10
|
176 .id = AV_CODEC_ID_WESTWOOD_SND1,
|
yading@10
|
177 .init = ws_snd_decode_init,
|
yading@10
|
178 .decode = ws_snd_decode_frame,
|
yading@10
|
179 .capabilities = CODEC_CAP_DR1,
|
yading@10
|
180 .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"),
|
yading@10
|
181 };
|