Mercurial > mplayer.hg
annotate libmpcodecs/ad_msadpcm.c @ 32777:9cc2689e5cd1
Fix r32587: the previous approach to return subtitles in time broke
DVB subtitles due to returning incomplete packets and even for
PGS subtitles resulted in incorrect pts values for the sub packets.
author | reimar |
---|---|
date | Sun, 06 Feb 2011 13:52:05 +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 } |