Mercurial > mplayer.hg
annotate libmpcodecs/ad_dk3adpcm.c @ 18049:77a3b0d11ca5
Limit the number of entires to the amount that does fit into the chunk.
the function need rewrite as it assumes quite many things that are not guaranteed by the specifications.
author | iive |
---|---|
date | Thu, 06 Apr 2006 20:04:02 +0000 |
parents | d8755974657a |
children | 1767c271d710 |
rev | line source |
---|---|
5408 | 1 /* |
2 DK3 ADPCM Decoder for MPlayer | |
3 by Mike Melanson | |
4 | |
7191
1eadce15446c
-afm/-vfm help implemenetd, some cosmetics of ad/vd codec names/comments
arpi
parents:
7180
diff
changeset
|
5 "This format number was used by Duck Corp. but not officially |
1eadce15446c
-afm/-vfm help implemenetd, some cosmetics of ad/vd codec names/comments
arpi
parents:
7180
diff
changeset
|
6 registered with Microsoft" |
1eadce15446c
-afm/-vfm help implemenetd, some cosmetics of ad/vd codec names/comments
arpi
parents:
7180
diff
changeset
|
7 |
5408 | 8 This file is responsible for decoding audio data encoded with |
9 Duck Corp's DK3 ADPCM algorithm. Details about the data format | |
10 can be found here: | |
11 http://www.pcisys.net/~melanson/codecs/ | |
12 */ | |
13 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
14 #include <stdio.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
15 #include <stdlib.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
16 #include <unistd.h> |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
17 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
18 #include "config.h" |
5408 | 19 #include "bswap.h" |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
20 #include "ad_internal.h" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
21 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
22 static ad_info_t info = |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
23 { |
7191
1eadce15446c
-afm/-vfm help implemenetd, some cosmetics of ad/vd codec names/comments
arpi
parents:
7180
diff
changeset
|
24 "Duck Corp. DK3 ADPCM decoder", |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
25 "dk3adpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
26 "Nick Kurshev", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
27 "Mike Melanson", |
7191
1eadce15446c
-afm/-vfm help implemenetd, some cosmetics of ad/vd codec names/comments
arpi
parents:
7180
diff
changeset
|
28 "" |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
29 }; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
30 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
31 LIBAD_EXTERN(dk3adpcm) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
32 |
5408 | 33 #define DK3_ADPCM_PREAMBLE_SIZE 16 |
34 | |
35 #define LE_16(x) (le2me_16(*(unsigned short *)(x))) | |
36 #define LE_32(x) (le2me_32(*(unsigned int *)(x))) | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
37 |
5408 | 38 // useful macros |
39 // clamp a number between 0 and 88 | |
40 #define CLAMP_0_TO_88(x) if (x < 0) x = 0; else if (x > 88) x = 88; | |
41 // clamp a number within a signed 16-bit range | |
42 #define CLAMP_S16(x) if (x < -32768) x = -32768; \ | |
43 else if (x > 32767) x = 32767; | |
44 // clamp a number above 16 | |
45 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
46 // sign extend a 16-bit value | |
47 #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; | |
48 // sign extend a 4-bit value | |
49 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
50 | |
51 // pertinent tables | |
52 static int adpcm_step[89] = | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
53 { |
5408 | 54 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, |
55 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, | |
56 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, | |
57 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, | |
58 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, | |
59 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, | |
60 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, | |
61 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, | |
62 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 | |
63 }; | |
64 | |
65 static int adpcm_index[16] = | |
66 { | |
67 -1, -1, -1, -1, 2, 4, 6, 8, | |
68 -1, -1, -1, -1, 2, 4, 6, 8 | |
69 }; | |
70 | |
71 static int preinit(sh_audio_t *sh_audio) | |
72 { | |
73 sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 6; | |
74 sh_audio->ds->ss_div = | |
75 (sh_audio->wf->nBlockAlign - DK3_ADPCM_PREAMBLE_SIZE) * 8 / 3; | |
5458 | 76 sh_audio->audio_in_minsize= |
5408 | 77 sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign; |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
78 return 1; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
79 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
80 |
5408 | 81 static int init(sh_audio_t *sh_audio) |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
82 { |
5408 | 83 sh_audio->channels = sh_audio->wf->nChannels; |
84 sh_audio->samplerate = sh_audio->wf->nSamplesPerSec; | |
85 sh_audio->i_bps = | |
86 (sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div; | |
13427
9d0b052c4f74
setting samplesize to 2 in decoders where neccessary.
reimar
parents:
7191
diff
changeset
|
87 sh_audio->samplesize=2; |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
88 return 1; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
89 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
90 |
5408 | 91 static void uninit(sh_audio_t *sh_audio) |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
92 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
93 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
94 |
5481 | 95 static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...) |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
96 { |
5481 | 97 if(cmd==ADCTRL_SKIP_FRAME){ |
98 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
99 return CONTROL_TRUE; | |
100 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
101 return CONTROL_UNKNOWN; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
102 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
103 |
5408 | 104 #define DK3_GET_NEXT_NIBBLE() \ |
105 if (decode_top_nibble_next) \ | |
106 { \ | |
107 nibble = (last_byte >> 4) & 0x0F; \ | |
108 decode_top_nibble_next = 0; \ | |
109 } \ | |
110 else \ | |
111 { \ | |
112 last_byte = input[in_ptr++]; \ | |
113 nibble = last_byte & 0x0F; \ | |
114 decode_top_nibble_next = 1; \ | |
115 } | |
116 | |
117 // note: This decoder assumes the format 0x62 data always comes in | |
118 // stereo flavor | |
119 static int dk3_adpcm_decode_block(unsigned short *output, unsigned char *input, | |
120 int block_size) | |
121 { | |
122 int sum_pred; | |
123 int diff_pred; | |
124 int sum_index; | |
125 int diff_index; | |
126 int diff_channel; | |
127 int in_ptr = 0x10; | |
128 int out_ptr = 0; | |
129 | |
130 unsigned char last_byte = 0; | |
131 unsigned char nibble; | |
132 int decode_top_nibble_next = 0; | |
133 | |
134 // ADPCM work variables | |
135 int sign; | |
136 int delta; | |
137 int step; | |
138 int diff; | |
139 | |
140 sum_pred = LE_16(&input[10]); | |
141 diff_pred = LE_16(&input[12]); | |
142 SE_16BIT(sum_pred); | |
143 SE_16BIT(diff_pred); | |
144 diff_channel = diff_pred; | |
145 sum_index = input[14]; | |
146 diff_index = input[15]; | |
147 | |
16965
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
148 while (in_ptr < block_size - !decode_top_nibble_next) |
5408 | 149 // while (in_ptr < 2048) |
150 { | |
151 // process the first predictor of the sum channel | |
152 DK3_GET_NEXT_NIBBLE(); | |
153 | |
154 step = adpcm_step[sum_index]; | |
155 | |
156 sign = nibble & 8; | |
157 delta = nibble & 7; | |
158 | |
159 diff = step >> 3; | |
160 if (delta & 4) diff += step; | |
161 if (delta & 2) diff += step >> 1; | |
162 if (delta & 1) diff += step >> 2; | |
163 | |
164 if (sign) | |
165 sum_pred -= diff; | |
166 else | |
167 sum_pred += diff; | |
168 | |
169 CLAMP_S16(sum_pred); | |
170 | |
171 sum_index += adpcm_index[nibble]; | |
172 CLAMP_0_TO_88(sum_index); | |
173 | |
174 // process the diff channel predictor | |
175 DK3_GET_NEXT_NIBBLE(); | |
176 | |
177 step = adpcm_step[diff_index]; | |
178 | |
179 sign = nibble & 8; | |
180 delta = nibble & 7; | |
181 | |
182 diff = step >> 3; | |
183 if (delta & 4) diff += step; | |
184 if (delta & 2) diff += step >> 1; | |
185 if (delta & 1) diff += step >> 2; | |
186 | |
187 if (sign) | |
188 diff_pred -= diff; | |
189 else | |
190 diff_pred += diff; | |
191 | |
192 CLAMP_S16(diff_pred); | |
193 | |
194 diff_index += adpcm_index[nibble]; | |
195 CLAMP_0_TO_88(diff_index); | |
196 | |
197 // output the first pair of stereo PCM samples | |
198 diff_channel = (diff_channel + diff_pred) / 2; | |
199 output[out_ptr++] = sum_pred + diff_channel; | |
200 output[out_ptr++] = sum_pred - diff_channel; | |
201 | |
202 // process the second predictor of the sum channel | |
203 DK3_GET_NEXT_NIBBLE(); | |
204 | |
205 step = adpcm_step[sum_index]; | |
206 | |
207 sign = nibble & 8; | |
208 delta = nibble & 7; | |
209 | |
210 diff = step >> 3; | |
211 if (delta & 4) diff += step; | |
212 if (delta & 2) diff += step >> 1; | |
213 if (delta & 1) diff += step >> 2; | |
214 | |
215 if (sign) | |
216 sum_pred -= diff; | |
217 else | |
218 sum_pred += diff; | |
219 | |
220 CLAMP_S16(sum_pred); | |
221 | |
222 sum_index += adpcm_index[nibble]; | |
223 CLAMP_0_TO_88(sum_index); | |
224 | |
225 // output the second pair of stereo PCM samples | |
226 output[out_ptr++] = sum_pred + diff_channel; | |
227 output[out_ptr++] = sum_pred - diff_channel; | |
228 } | |
229 | |
230 return out_ptr; | |
231 } | |
232 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
233 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
234 { |
5408 | 235 if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer, |
236 sh_audio->ds->ss_mul) != | |
237 sh_audio->ds->ss_mul) | |
238 return -1; /* EOF */ | |
239 | |
16965
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
240 if (maxlen < 2 * 4 * sh_audio->wf->nBlockAlign * 2 / 3) { |
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
241 mp_msg(MSGT_DECAUDIO, MSGL_V, "dk3adpcm: maxlen too small in decode_audio\n"); |
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
242 return -1; |
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
243 } |
5408 | 244 return 2 * dk3_adpcm_decode_block( |
245 (unsigned short*)buf, sh_audio->a_in_buffer, | |
16965
d8755974657a
attempt to fix missing and/or broken boundary checks
reimar
parents:
13427
diff
changeset
|
246 sh_audio->ds->ss_mul); |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
247 } |