Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 34255:1802d9d74c26
Make WAV format detection more restrictive so it does not incorrectly
grab qcp files.
author | reimar |
---|---|
date | Fri, 11 Nov 2011 17:29:14 +0000 |
parents | a93891202051 |
children |
rev | line source |
---|---|
5408 | 1 /* |
30421
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
2 * MS ADPCM decoder |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
3 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
4 * This file is responsible for decoding Microsoft ADPCM data. |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
5 * Details about the data format can be found here: |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
6 * http://www.pcisys.net/~melanson/codecs/ |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
7 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
8 * Copyright (c) 2002 Mike Melanson |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
9 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
10 * This file is part of MPlayer. |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
11 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
12 * MPlayer is free software; you can redistribute it and/or modify |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
13 * it under the terms of the GNU General Public License as published by |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
14 * the Free Software Foundation; either version 2 of the License, or |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
15 * (at your option) any later version. |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
16 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
17 * MPlayer is distributed in the hope that it will be useful, |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
20 * GNU General Public License for more details. |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
21 * |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
22 * You should have received a copy of the GNU General Public License along |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
23 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
bbb6ebec87a0
Add missing license headers to all files in the libmpcodecs directory.
diego
parents:
29263
diff
changeset
|
25 */ |
5408 | 26 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
27 #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
|
28 #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
|
29 #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
|
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 #include "config.h" |
34174
a93891202051
Add missing mp_msg.h #includes, remove some unnecessary ones.
diego
parents:
30504
diff
changeset
|
32 #include "mp_msg.h" |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
33 #include "libavutil/common.h" |
27225
46bcd3f1b123
Simplify ad_msadpmc.c: Use AV_RL16, merge sign extension into LE_16 read and
reimar
parents:
27224
diff
changeset
|
34 #include "libavutil/intreadwrite.h" |
21507
fa99b3d31d13
Hack around libavutil/bswap.h compilation problems due to always_inline undefined.
reimar
parents:
21372
diff
changeset
|
35 #include "mpbswap.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
|
36 #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
|
37 |
30504
cc27da5d7286
Mark all ad_info_t/vd_info_t structure declarations as const.
diego
parents:
30421
diff
changeset
|
38 static const ad_info_t info = |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
39 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
40 "MS ADPCM audio decoder", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
41 "msadpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
42 "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
|
43 "Mike Melanson", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
44 "" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
45 }; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
46 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
47 LIBAD_EXTERN(msadpcm) |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
48 |
27222 | 49 static const int ms_adapt_table[] = |
5408 | 50 { |
51 230, 230, 230, 230, 307, 409, 512, 614, | |
52 768, 614, 512, 409, 307, 230, 230, 230 | |
53 }; | |
54 | |
27237
6a283385441b
100l, fix MS ADPCM decoding for e.g. http://samples.mplayerhq.hu/mov/qtaudio/surge-2-16-L-ms02.mov
reimar
parents:
27228
diff
changeset
|
55 static const uint8_t ms_adapt_coeff1[] = |
5408 | 56 { |
27226 | 57 64, 128, 0, 48, 60, 115, 98 |
5408 | 58 }; |
59 | |
27226 | 60 static const int8_t ms_adapt_coeff2[] = |
5408 | 61 { |
27226 | 62 0, -64, 0, 16, 0, -52, -58 |
5408 | 63 }; |
64 | |
6609 | 65 #define MS_ADPCM_PREAMBLE_SIZE 6 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
66 |
27225
46bcd3f1b123
Simplify ad_msadpmc.c: Use AV_RL16, merge sign extension into LE_16 read and
reimar
parents:
27224
diff
changeset
|
67 #define LE_16(x) ((int16_t)AV_RL16(x)) |
5408 | 68 |
69 // clamp a number between 0 and 88 | |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
70 #define CLAMP_0_TO_88(x) x = av_clip(x, 0, 88); |
5408 | 71 // clamp a number within a signed 16-bit range |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
72 #define CLAMP_S16(x) x = av_clip_int16(x); |
5408 | 73 // clamp a number above 16 |
74 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
75 // sign extend a 4-bit value | |
76 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
77 | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
78 static int preinit(sh_audio_t *sh_audio) |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
79 { |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
80 sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
27238
diff
changeset
|
81 sh_audio->ds->ss_div = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
82 (sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2; |
5458 | 83 sh_audio->audio_in_minsize = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
84 sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
85 return 1; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
86 } |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
87 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
88 static int init(sh_audio_t *sh_audio) |
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 sh_audio->channels=sh_audio->wf->nChannels; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
91 sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
92 sh_audio->i_bps = sh_audio->wf->nBlockAlign * |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
93 (sh_audio->channels*sh_audio->samplerate) / sh_audio->ds->ss_div; |
13427
9d0b052c4f74
setting samplesize to 2 in decoders where neccessary.
reimar
parents:
7893
diff
changeset
|
94 sh_audio->samplesize=2; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
95 |
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 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
|
97 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
98 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
99 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
|
100 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
101 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
102 |
5481 | 103 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
|
104 { |
5481 | 105 if(cmd==ADCTRL_SKIP_FRAME){ |
106 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
107 return CONTROL_TRUE; | |
108 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
109 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
|
110 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
111 |
27238 | 112 static inline int check_coeff(uint8_t c) { |
113 if (c > 6) { | |
114 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
115 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
116 c); | |
117 c = 6; | |
118 } | |
119 return c; | |
120 } | |
121 | |
5408 | 122 static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, |
123 int channels, int block_size) | |
124 { | |
125 int current_channel = 0; | |
27238 | 126 int coeff_idx; |
5408 | 127 int idelta[2]; |
128 int sample1[2]; | |
129 int sample2[2]; | |
130 int coeff1[2]; | |
131 int coeff2[2]; | |
132 int stream_ptr = 0; | |
133 int out_ptr = 0; | |
134 int upper_nibble = 1; | |
135 int nibble; | |
136 int snibble; // signed nibble | |
137 int predictor; | |
138 | |
27228 | 139 if (channels != 1) channels = 2; |
140 if (block_size < 7 * channels) | |
141 return -1; | |
142 | |
5408 | 143 // fetch the header information, in stereo if both channels are present |
27238 | 144 coeff_idx = check_coeff(input[stream_ptr]); |
145 coeff1[0] = ms_adapt_coeff1[coeff_idx]; | |
146 coeff2[0] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 147 stream_ptr++; |
148 if (channels == 2) | |
149 { | |
27238 | 150 coeff_idx = check_coeff(input[stream_ptr]); |
151 coeff1[1] = ms_adapt_coeff1[coeff_idx]; | |
152 coeff2[1] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 153 stream_ptr++; |
154 } | |
155 | |
156 idelta[0] = LE_16(&input[stream_ptr]); | |
157 stream_ptr += 2; | |
158 if (channels == 2) | |
159 { | |
160 idelta[1] = LE_16(&input[stream_ptr]); | |
161 stream_ptr += 2; | |
162 } | |
163 | |
164 sample1[0] = LE_16(&input[stream_ptr]); | |
165 stream_ptr += 2; | |
166 if (channels == 2) | |
167 { | |
168 sample1[1] = LE_16(&input[stream_ptr]); | |
169 stream_ptr += 2; | |
170 } | |
171 | |
172 sample2[0] = LE_16(&input[stream_ptr]); | |
173 stream_ptr += 2; | |
174 if (channels == 2) | |
175 { | |
176 sample2[1] = LE_16(&input[stream_ptr]); | |
177 stream_ptr += 2; | |
178 } | |
179 | |
6609 | 180 if (channels == 1) |
181 { | |
182 output[out_ptr++] = sample2[0]; | |
183 output[out_ptr++] = sample1[0]; | |
184 } else { | |
185 output[out_ptr++] = sample2[0]; | |
186 output[out_ptr++] = sample2[1]; | |
187 output[out_ptr++] = sample1[0]; | |
188 output[out_ptr++] = sample1[1]; | |
189 } | |
190 | |
5408 | 191 while (stream_ptr < block_size) |
192 { | |
193 // get the next nibble | |
194 if (upper_nibble) | |
195 nibble = snibble = input[stream_ptr] >> 4; | |
196 else | |
197 nibble = snibble = input[stream_ptr++] & 0x0F; | |
198 upper_nibble ^= 1; | |
199 SE_4BIT(snibble); | |
200 | |
27227 | 201 // should this really be a division and not a shift? |
202 // coefficients were originally scaled by for, which might have | |
203 // been an optimization for 8-bit CPUs _if_ a shift is correct | |
5408 | 204 predictor = ( |
205 ((sample1[current_channel] * coeff1[current_channel]) + | |
27226 | 206 (sample2[current_channel] * coeff2[current_channel])) / 64) + |
5408 | 207 (snibble * idelta[current_channel]); |
208 CLAMP_S16(predictor); | |
209 sample2[current_channel] = sample1[current_channel]; | |
210 sample1[current_channel] = predictor; | |
211 output[out_ptr++] = predictor; | |
212 | |
213 // compute the next adaptive scale factor (a.k.a. the variable idelta) | |
214 idelta[current_channel] = | |
215 (ms_adapt_table[nibble] * idelta[current_channel]) / 256; | |
216 CLAMP_ABOVE_16(idelta[current_channel]); | |
217 | |
218 // toggle the channel | |
219 current_channel ^= channels - 1; | |
220 } | |
221 | |
222 return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; | |
223 } | |
224 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
225 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
|
226 { |
27228 | 227 int res; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
228 if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer, |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
27238
diff
changeset
|
229 sh_audio->ds->ss_mul) != |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
27238
diff
changeset
|
230 sh_audio->ds->ss_mul) |
5408 | 231 return -1; /* EOF */ |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
232 |
27228 | 233 res = ms_adpcm_decode_block( |
5408 | 234 (unsigned short*)buf, sh_audio->a_in_buffer, |
235 sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign); | |
27228 | 236 return res < 0 ? res : 2 * res; |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
237 } |