Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 33468:86b2ec222a2c
Make "Invalid seek to negative position" message more useful by
printing the actual value.
author | reimar |
---|---|
date | Sat, 04 Jun 2011 09:30:42 +0000 |
parents | cc27da5d7286 |
children | a93891202051 |
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" |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
32 #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
|
33 #include "libavutil/intreadwrite.h" |
21507
fa99b3d31d13
Hack around libavutil/bswap.h compilation problems due to always_inline undefined.
reimar
parents:
21372
diff
changeset
|
34 #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
|
35 #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
|
36 |
30504
cc27da5d7286
Mark all ad_info_t/vd_info_t structure declarations as const.
diego
parents:
30421
diff
changeset
|
37 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
|
38 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
39 "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
|
40 "msadpcm", |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
41 "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
|
42 "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
|
43 "" |
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 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
|
47 |
27222 | 48 static const int ms_adapt_table[] = |
5408 | 49 { |
50 230, 230, 230, 230, 307, 409, 512, 614, | |
51 768, 614, 512, 409, 307, 230, 230, 230 | |
52 }; | |
53 | |
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
|
54 static const uint8_t ms_adapt_coeff1[] = |
5408 | 55 { |
27226 | 56 64, 128, 0, 48, 60, 115, 98 |
5408 | 57 }; |
58 | |
27226 | 59 static const int8_t ms_adapt_coeff2[] = |
5408 | 60 { |
27226 | 61 0, -64, 0, 16, 0, -52, -58 |
5408 | 62 }; |
63 | |
6609 | 64 #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
|
65 |
27225
46bcd3f1b123
Simplify ad_msadpmc.c: Use AV_RL16, merge sign extension into LE_16 read and
reimar
parents:
27224
diff
changeset
|
66 #define LE_16(x) ((int16_t)AV_RL16(x)) |
5408 | 67 |
68 // clamp a number between 0 and 88 | |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
69 #define CLAMP_0_TO_88(x) x = av_clip(x, 0, 88); |
5408 | 70 // clamp a number within a signed 16-bit range |
27224
f9b5d028f097
Copy macro simplification from imaadpcm to msadpcm
reimar
parents:
27223
diff
changeset
|
71 #define CLAMP_S16(x) x = av_clip_int16(x); |
5408 | 72 // clamp a number above 16 |
73 #define CLAMP_ABOVE_16(x) if (x < 16) x = 16; | |
74 // sign extend a 4-bit value | |
75 #define SE_4BIT(x) if (x & 0x8) x -= 0x10; | |
76 | |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
77 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
|
78 { |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
79 sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
27238
diff
changeset
|
80 sh_audio->ds->ss_div = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
81 (sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2; |
5458 | 82 sh_audio->audio_in_minsize = |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
83 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
|
84 return 1; |
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
85 } |
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 |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
87 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
|
88 { |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
89 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
|
90 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
|
91 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
|
92 (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
|
93 sh_audio->samplesize=2; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
94 |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
95 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
|
96 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
97 |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
98 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
|
99 { |
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 |
5481 | 102 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
|
103 { |
5481 | 104 if(cmd==ADCTRL_SKIP_FRAME){ |
105 demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,sh_audio->ds->ss_mul); | |
106 return CONTROL_TRUE; | |
107 } | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
108 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
|
109 } |
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
110 |
27238 | 111 static inline int check_coeff(uint8_t c) { |
112 if (c > 6) { | |
113 mp_msg(MSGT_DECAUDIO, MSGL_WARN, | |
114 "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", | |
115 c); | |
116 c = 6; | |
117 } | |
118 return c; | |
119 } | |
120 | |
5408 | 121 static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, |
122 int channels, int block_size) | |
123 { | |
124 int current_channel = 0; | |
27238 | 125 int coeff_idx; |
5408 | 126 int idelta[2]; |
127 int sample1[2]; | |
128 int sample2[2]; | |
129 int coeff1[2]; | |
130 int coeff2[2]; | |
131 int stream_ptr = 0; | |
132 int out_ptr = 0; | |
133 int upper_nibble = 1; | |
134 int nibble; | |
135 int snibble; // signed nibble | |
136 int predictor; | |
137 | |
27228 | 138 if (channels != 1) channels = 2; |
139 if (block_size < 7 * channels) | |
140 return -1; | |
141 | |
5408 | 142 // fetch the header information, in stereo if both channels are present |
27238 | 143 coeff_idx = check_coeff(input[stream_ptr]); |
144 coeff1[0] = ms_adapt_coeff1[coeff_idx]; | |
145 coeff2[0] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 146 stream_ptr++; |
147 if (channels == 2) | |
148 { | |
27238 | 149 coeff_idx = check_coeff(input[stream_ptr]); |
150 coeff1[1] = ms_adapt_coeff1[coeff_idx]; | |
151 coeff2[1] = ms_adapt_coeff2[coeff_idx]; | |
5408 | 152 stream_ptr++; |
153 } | |
154 | |
155 idelta[0] = LE_16(&input[stream_ptr]); | |
156 stream_ptr += 2; | |
157 if (channels == 2) | |
158 { | |
159 idelta[1] = LE_16(&input[stream_ptr]); | |
160 stream_ptr += 2; | |
161 } | |
162 | |
163 sample1[0] = LE_16(&input[stream_ptr]); | |
164 stream_ptr += 2; | |
165 if (channels == 2) | |
166 { | |
167 sample1[1] = LE_16(&input[stream_ptr]); | |
168 stream_ptr += 2; | |
169 } | |
170 | |
171 sample2[0] = LE_16(&input[stream_ptr]); | |
172 stream_ptr += 2; | |
173 if (channels == 2) | |
174 { | |
175 sample2[1] = LE_16(&input[stream_ptr]); | |
176 stream_ptr += 2; | |
177 } | |
178 | |
6609 | 179 if (channels == 1) |
180 { | |
181 output[out_ptr++] = sample2[0]; | |
182 output[out_ptr++] = sample1[0]; | |
183 } else { | |
184 output[out_ptr++] = sample2[0]; | |
185 output[out_ptr++] = sample2[1]; | |
186 output[out_ptr++] = sample1[0]; | |
187 output[out_ptr++] = sample1[1]; | |
188 } | |
189 | |
5408 | 190 while (stream_ptr < block_size) |
191 { | |
192 // get the next nibble | |
193 if (upper_nibble) | |
194 nibble = snibble = input[stream_ptr] >> 4; | |
195 else | |
196 nibble = snibble = input[stream_ptr++] & 0x0F; | |
197 upper_nibble ^= 1; | |
198 SE_4BIT(snibble); | |
199 | |
27227 | 200 // should this really be a division and not a shift? |
201 // coefficients were originally scaled by for, which might have | |
202 // been an optimization for 8-bit CPUs _if_ a shift is correct | |
5408 | 203 predictor = ( |
204 ((sample1[current_channel] * coeff1[current_channel]) + | |
27226 | 205 (sample2[current_channel] * coeff2[current_channel])) / 64) + |
5408 | 206 (snibble * idelta[current_channel]); |
207 CLAMP_S16(predictor); | |
208 sample2[current_channel] = sample1[current_channel]; | |
209 sample1[current_channel] = predictor; | |
210 output[out_ptr++] = predictor; | |
211 | |
212 // compute the next adaptive scale factor (a.k.a. the variable idelta) | |
213 idelta[current_channel] = | |
214 (ms_adapt_table[nibble] * idelta[current_channel]) / 256; | |
215 CLAMP_ABOVE_16(idelta[current_channel]); | |
216 | |
217 // toggle the channel | |
218 current_channel ^= channels - 1; | |
219 } | |
220 | |
221 return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; | |
222 } | |
223 | |
5340
0f12fb7c1c5d
imported from MPlayerXP, dlopen() hack removed, some bugs fixed, interface functions changed to static, info->author field added
arpi
parents:
diff
changeset
|
224 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
|
225 { |
27228 | 226 int res; |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
227 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
|
228 sh_audio->ds->ss_mul) != |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
27238
diff
changeset
|
229 sh_audio->ds->ss_mul) |
5408 | 230 return -1; /* EOF */ |
5350
d59e27f2f5be
fixed so the decoder cooperates better with the rest of the system
melanson
parents:
5340
diff
changeset
|
231 |
27228 | 232 res = ms_adpcm_decode_block( |
5408 | 233 (unsigned short*)buf, sh_audio->a_in_buffer, |
234 sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign); | |
27228 | 235 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
|
236 } |