Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 7732:328bbac6224c
Fixes:
- missing check in init
- missing brackets causing failure
- nas_aformat_to_auformat not working properly
- fix hang that was finally reproducible with high disk activity
- don't cut of audio on uninit(), wait for buffer to empty
It also simplifies the event_handler, making it more readable and
implements Sidik Isani's suggestion to make the buffer size dependent on
bytes per second. I've been using it for two days and found no further
problems.
patch by Tobias Diedrich <td@sim.uni-hannover.de>
author | arpi |
---|---|
date | Sun, 13 Oct 2002 22:00:15 +0000 |
parents | 28677d779205 |
children | 5abf74c67ace |
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" |
5408 | 15 #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
|
16 #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
|
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 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
|
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 "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
|
21 "msadpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
22 "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
|
23 "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
|
24 "" |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
25 }; |
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 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
|
28 |
5408 | 29 static int ms_adapt_table[] = |
30 { | |
31 230, 230, 230, 230, 307, 409, 512, 614, | |
32 768, 614, 512, 409, 307, 230, 230, 230 | |
33 }; | |
34 | |
35 static int ms_adapt_coeff1[] = | |
36 { | |
37 256, 512, 0, 192, 240, 460, 392 | |
38 }; | |
39 | |
40 static int ms_adapt_coeff2[] = | |
41 { | |
42 0, -256, 0, 64, 0, -208, -232 | |
43 }; | |
44 | |
6609 | 45 #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
|
46 |
5408 | 47 #define LE_16(x) (le2me_16(*(unsigned short *)(x))) |
48 #define LE_32(x) (le2me_32(*(unsigned int *)(x))) | |
49 | |
50 // useful macros | |
51 // clamp a number between 0 and 88 | |
52 #define CLAMP_0_TO_88(x) if (x < 0) x = 0; else if (x > 88) x = 88; | |
53 // clamp a number within a signed 16-bit range | |
54 #define CLAMP_S16(x) if (x < -32768) x = -32768; \ | |
55 else if (x > 32767) x = 32767; | |
56 // clamp a number above 16 | |
57 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
58 // sign extend a 16-bit value | |
59 #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; | |
60 // sign extend a 4-bit value | |
61 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
62 | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
63 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
|
64 { |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
65 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
|
66 sh_audio->ds->ss_div = |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
67 (sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2; |
5458 | 68 sh_audio->audio_in_minsize = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
69 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
|
70 return 1; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
71 } |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
72 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
73 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
|
74 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
75 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
|
76 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
|
77 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
|
78 (sh_audio->channels*sh_audio->samplerate) / sh_audio->ds->ss_div; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
79 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
80 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
|
81 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
82 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
83 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
|
84 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
85 } |
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 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
|
88 { |
5481 | 89 if(cmd==ADCTRL_SKIP_FRAME){ |
90 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
91 return CONTROL_TRUE; | |
92 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
93 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
|
94 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
95 |
5408 | 96 static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, |
97 int channels, int block_size) | |
98 { | |
99 int current_channel = 0; | |
100 int idelta[2]; | |
101 int sample1[2]; | |
102 int sample2[2]; | |
103 int coeff1[2]; | |
104 int coeff2[2]; | |
105 int stream_ptr = 0; | |
106 int out_ptr = 0; | |
107 int upper_nibble = 1; | |
108 int nibble; | |
109 int snibble; // signed nibble | |
110 int predictor; | |
111 | |
112 // fetch the header information, in stereo if both channels are present | |
113 if (input[stream_ptr] > 6) | |
114 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
115 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
116 input[stream_ptr]); | |
117 coeff1[0] = ms_adapt_coeff1[input[stream_ptr]]; | |
118 coeff2[0] = ms_adapt_coeff2[input[stream_ptr]]; | |
119 stream_ptr++; | |
120 if (channels == 2) | |
121 { | |
122 if (input[stream_ptr] > 6) | |
123 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
124 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
125 input[stream_ptr]); | |
126 coeff1[1] = ms_adapt_coeff1[input[stream_ptr]]; | |
127 coeff2[1] = ms_adapt_coeff2[input[stream_ptr]]; | |
128 stream_ptr++; | |
129 } | |
130 | |
131 idelta[0] = LE_16(&input[stream_ptr]); | |
132 stream_ptr += 2; | |
133 SE_16BIT(idelta[0]); | |
134 if (channels == 2) | |
135 { | |
136 idelta[1] = LE_16(&input[stream_ptr]); | |
137 stream_ptr += 2; | |
138 SE_16BIT(idelta[1]); | |
139 } | |
140 | |
141 sample1[0] = LE_16(&input[stream_ptr]); | |
142 stream_ptr += 2; | |
143 SE_16BIT(sample1[0]); | |
144 if (channels == 2) | |
145 { | |
146 sample1[1] = LE_16(&input[stream_ptr]); | |
147 stream_ptr += 2; | |
148 SE_16BIT(sample1[1]); | |
149 } | |
150 | |
151 sample2[0] = LE_16(&input[stream_ptr]); | |
152 stream_ptr += 2; | |
153 SE_16BIT(sample2[0]); | |
154 if (channels == 2) | |
155 { | |
156 sample2[1] = LE_16(&input[stream_ptr]); | |
157 stream_ptr += 2; | |
158 SE_16BIT(sample2[1]); | |
159 } | |
160 | |
6609 | 161 if (channels == 1) |
162 { | |
163 output[out_ptr++] = sample2[0]; | |
164 output[out_ptr++] = sample1[0]; | |
165 } else { | |
166 output[out_ptr++] = sample2[0]; | |
167 output[out_ptr++] = sample2[1]; | |
168 output[out_ptr++] = sample1[0]; | |
169 output[out_ptr++] = sample1[1]; | |
170 } | |
171 | |
5408 | 172 while (stream_ptr < block_size) |
173 { | |
174 // get the next nibble | |
175 if (upper_nibble) | |
176 nibble = snibble = input[stream_ptr] >> 4; | |
177 else | |
178 nibble = snibble = input[stream_ptr++] & 0x0F; | |
179 upper_nibble ^= 1; | |
180 SE_4BIT(snibble); | |
181 | |
182 predictor = ( | |
183 ((sample1[current_channel] * coeff1[current_channel]) + | |
184 (sample2[current_channel] * coeff2[current_channel])) / 256) + | |
185 (snibble * idelta[current_channel]); | |
186 CLAMP_S16(predictor); | |
187 sample2[current_channel] = sample1[current_channel]; | |
188 sample1[current_channel] = predictor; | |
189 output[out_ptr++] = predictor; | |
190 | |
191 // compute the next adaptive scale factor (a.k.a. the variable idelta) | |
192 idelta[current_channel] = | |
193 (ms_adapt_table[nibble] * idelta[current_channel]) / 256; | |
194 CLAMP_ABOVE_16(idelta[current_channel]); | |
195 | |
196 // toggle the channel | |
197 current_channel ^= channels - 1; | |
198 } | |
199 | |
200 return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; | |
201 } | |
202 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
203 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
|
204 { |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
205 if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer, |
5408 | 206 sh_audio->ds->ss_mul) != |
207 sh_audio->ds->ss_mul) | |
208 return -1; /* EOF */ | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
209 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
210 return 2 * ms_adpcm_decode_block( |
5408 | 211 (unsigned short*)buf, sh_audio->a_in_buffer, |
212 sh_audio->wf->nChannels, 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
|
213 } |