Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 29218:6414b0a2965c
Allow disabling and enabling VCD support through command line parameters.
author | diego |
---|---|
date | Tue, 05 May 2009 17:15:54 +0000 |
parents | 7aa646bb7589 |
children | 0f1b5b68af32 |
rev | line source |
---|---|
5408 | 1 /* |
2 MS ADPCM Decoder for MPlayer | |
3 by Mike Melanson | |
4 | |
5 This file is responsible for decoding Microsoft ADPCM data. | |
6 Details about the data format can be found here: | |
7 http://www.pcisys.net/~melanson/codecs/ | |
8 */ | |
9 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
10 #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
|
11 #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
|
12 #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
|
13 |
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 "config.h" |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
15 #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
|
16 #include "libavutil/intreadwrite.h" |
21507
fa99b3d31d13
Hack around libavutil/bswap.h compilation problems due to always_inline undefined.
reimar
parents:
21372
diff
changeset
|
17 #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
|
18 #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
|
19 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
20 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
|
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 "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
|
23 "msadpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
24 "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
|
25 "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
|
26 "" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
27 }; |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
28 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
29 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
|
30 |
27222 | 31 static const int ms_adapt_table[] = |
5408 | 32 { |
33 230, 230, 230, 230, 307, 409, 512, 614, | |
34 768, 614, 512, 409, 307, 230, 230, 230 | |
35 }; | |
36 | |
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
|
37 static const uint8_t ms_adapt_coeff1[] = |
5408 | 38 { |
27226 | 39 64, 128, 0, 48, 60, 115, 98 |
5408 | 40 }; |
41 | |
27226 | 42 static const int8_t ms_adapt_coeff2[] = |
5408 | 43 { |
27226 | 44 0, -64, 0, 16, 0, -52, -58 |
5408 | 45 }; |
46 | |
6609 | 47 #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
|
48 |
27225
46bcd3f1b123
Simplify ad_msadpmc.c: Use AV_RL16, merge sign extension into LE_16 read and
reimar
parents:
27224
diff
changeset
|
49 #define LE_16(x) ((int16_t)AV_RL16(x)) |
5408 | 50 |
51 // clamp a number between 0 and 88 | |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
52 #define CLAMP_0_TO_88(x) x = av_clip(x, 0, 88); |
5408 | 53 // clamp a number within a signed 16-bit range |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
54 #define CLAMP_S16(x) x = av_clip_int16(x); |
5408 | 55 // clamp a number above 16 |
56 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
57 // sign extend a 4-bit value | |
58 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
59 | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
60 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
|
61 { |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
62 sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
63 sh_audio->ds->ss_div = |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
64 (sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2; |
5458 | 65 sh_audio->audio_in_minsize = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
66 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
|
67 return 1; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
68 } |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
69 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
70 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
|
71 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
72 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
|
73 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
|
74 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
|
75 (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
|
76 sh_audio->samplesize=2; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
77 |
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 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
81 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
|
82 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
83 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
84 |
5481 | 85 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
|
86 { |
5481 | 87 if(cmd==ADCTRL_SKIP_FRAME){ |
88 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
89 return CONTROL_TRUE; | |
90 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
91 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
|
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 |
27238 | 94 static inline int check_coeff(uint8_t c) { |
95 if (c > 6) { | |
96 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
97 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
98 c); | |
99 c = 6; | |
100 } | |
101 return c; | |
102 } | |
103 | |
5408 | 104 static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, |
105 int channels, int block_size) | |
106 { | |
107 int current_channel = 0; | |
27238 | 108 int coeff_idx; |
5408 | 109 int idelta[2]; |
110 int sample1[2]; | |
111 int sample2[2]; | |
112 int coeff1[2]; | |
113 int coeff2[2]; | |
114 int stream_ptr = 0; | |
115 int out_ptr = 0; | |
116 int upper_nibble = 1; | |
117 int nibble; | |
118 int snibble; // signed nibble | |
119 int predictor; | |
120 | |
27228 | 121 if (channels != 1) channels = 2; |
122 if (block_size < 7 * channels) | |
123 return -1; | |
124 | |
5408 | 125 // fetch the header information, in stereo if both channels are present |
27238 | 126 coeff_idx = check_coeff(input[stream_ptr]); |
127 coeff1[0] = ms_adapt_coeff1[coeff_idx]; | |
128 coeff2[0] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 129 stream_ptr++; |
130 if (channels == 2) | |
131 { | |
27238 | 132 coeff_idx = check_coeff(input[stream_ptr]); |
133 coeff1[1] = ms_adapt_coeff1[coeff_idx]; | |
134 coeff2[1] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 135 stream_ptr++; |
136 } | |
137 | |
138 idelta[0] = LE_16(&input[stream_ptr]); | |
139 stream_ptr += 2; | |
140 if (channels == 2) | |
141 { | |
142 idelta[1] = LE_16(&input[stream_ptr]); | |
143 stream_ptr += 2; | |
144 } | |
145 | |
146 sample1[0] = LE_16(&input[stream_ptr]); | |
147 stream_ptr += 2; | |
148 if (channels == 2) | |
149 { | |
150 sample1[1] = LE_16(&input[stream_ptr]); | |
151 stream_ptr += 2; | |
152 } | |
153 | |
154 sample2[0] = LE_16(&input[stream_ptr]); | |
155 stream_ptr += 2; | |
156 if (channels == 2) | |
157 { | |
158 sample2[1] = LE_16(&input[stream_ptr]); | |
159 stream_ptr += 2; | |
160 } | |
161 | |
6609 | 162 if (channels == 1) |
163 { | |
164 output[out_ptr++] = sample2[0]; | |
165 output[out_ptr++] = sample1[0]; | |
166 } else { | |
167 output[out_ptr++] = sample2[0]; | |
168 output[out_ptr++] = sample2[1]; | |
169 output[out_ptr++] = sample1[0]; | |
170 output[out_ptr++] = sample1[1]; | |
171 } | |
172 | |
5408 | 173 while (stream_ptr < block_size) |
174 { | |
175 // get the next nibble | |
176 if (upper_nibble) | |
177 nibble = snibble = input[stream_ptr] >> 4; | |
178 else | |
179 nibble = snibble = input[stream_ptr++] & 0x0F; | |
180 upper_nibble ^= 1; | |
181 SE_4BIT(snibble); | |
182 | |
27227 | 183 // should this really be a division and not a shift? |
184 // coefficients were originally scaled by for, which might have | |
185 // been an optimization for 8-bit CPUs _if_ a shift is correct | |
5408 | 186 predictor = ( |
187 ((sample1[current_channel] * coeff1[current_channel]) + | |
27226 | 188 (sample2[current_channel] * coeff2[current_channel])) / 64) + |
5408 | 189 (snibble * idelta[current_channel]); |
190 CLAMP_S16(predictor); | |
191 sample2[current_channel] = sample1[current_channel]; | |
192 sample1[current_channel] = predictor; | |
193 output[out_ptr++] = predictor; | |
194 | |
195 // compute the next adaptive scale factor (a.k.a. the variable idelta) | |
196 idelta[current_channel] = | |
197 (ms_adapt_table[nibble] * idelta[current_channel]) / 256; | |
198 CLAMP_ABOVE_16(idelta[current_channel]); | |
199 | |
200 // toggle the channel | |
201 current_channel ^= channels - 1; | |
202 } | |
203 | |
204 return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; | |
205 } | |
206 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
207 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
|
208 { |
27228 | 209 int res; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
210 if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer, |
5408 | 211 sh_audio->ds->ss_mul) != |
212 sh_audio->ds->ss_mul) | |
213 return -1; /* EOF */ | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
214 |
27228 | 215 res = ms_adpcm_decode_block( |
5408 | 216 (unsigned short*)buf, sh_audio->a_in_buffer, |
217 sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign); | |
27228 | 218 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
|
219 } |