Mercurial > libavcodec.hg
annotate mlp_parser.c @ 7352:c2318e551ff5 libavcodec
When picking a "high utility centroid" do not pick one
that has no corresponding points. Not only it is the
worst possible pick, but also the code was written
without this case in mind.
author | vitor |
---|---|
date | Wed, 23 Jul 2008 03:55:37 +0000 |
parents | ae8c047d6be5 |
children | 8813c715eb9d |
rev | line source |
---|---|
5954 | 1 /* |
2 * MLP parser | |
3 * Copyright (c) 2007 Ian Caulfield | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 /** | |
23 * @file mlp_parser.c | |
24 * MLP parser | |
25 */ | |
26 | |
7199 | 27 #include <stdint.h> |
28 | |
6763 | 29 #include "libavutil/crc.h" |
5954 | 30 #include "bitstream.h" |
31 #include "parser.h" | |
32 #include "mlp_parser.h" | |
33 | |
34 static const uint8_t mlp_quants[16] = { | |
35 16, 20, 24, 0, 0, 0, 0, 0, | |
36 0, 0, 0, 0, 0, 0, 0, 0, | |
37 }; | |
38 | |
39 static const uint8_t mlp_channels[32] = { | |
40 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4, | |
41 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
42 }; | |
43 | |
44 static const uint8_t thd_chancount[13] = { | |
45 // LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2 | |
46 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1 | |
47 }; | |
48 | |
49 static int mlp_samplerate(int in) | |
50 { | |
51 if (in == 0xF) | |
52 return 0; | |
53 | |
54 return (in & 8 ? 44100 : 48000) << (in & 7) ; | |
55 } | |
56 | |
57 static int truehd_channels(int chanmap) | |
58 { | |
59 int channels = 0, i; | |
60 | |
61 for (i = 0; i < 13; i++) | |
62 channels += thd_chancount[i] * ((chanmap >> i) & 1); | |
63 | |
64 return channels; | |
65 } | |
66 | |
67 static int crc_init = 0; | |
68 static AVCRC crc_2D[1024]; | |
69 | |
7198 | 70 /** MLP uses checksums that seem to be based on the standard CRC algorithm, but |
71 * are not (in implementation terms, the table lookup and XOR are reversed). | |
5980 | 72 * We can implement this behavior using a standard av_crc on all but the |
5954 | 73 * last element, then XOR that with the last element. |
74 */ | |
75 | |
76 static uint16_t mlp_checksum16(const uint8_t *buf, unsigned int buf_size) | |
77 { | |
78 uint16_t crc; | |
79 | |
80 if (!crc_init) { | |
81 av_crc_init(crc_2D, 0, 16, 0x002D, sizeof(crc_2D)); | |
82 crc_init = 1; | |
83 } | |
84 | |
85 crc = av_crc(crc_2D, 0, buf, buf_size - 2); | |
86 crc ^= AV_RL16(buf + buf_size - 2); | |
87 return crc; | |
88 } | |
89 | |
90 /** Read a major sync info header - contains high level information about | |
91 * the stream - sample rate, channel arrangement etc. Most of this | |
92 * information is not actually necessary for decoding, only for playback. | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
93 * gb must be a freshly initialized GetBitContext with no bits read. |
5954 | 94 */ |
95 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
96 int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) |
5954 | 97 { |
98 int ratebits; | |
99 uint16_t checksum; | |
100 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
101 assert(get_bits_count(gb) == 0); |
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
102 |
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
103 if (gb->size_in_bits < 28 << 3) { |
7198 | 104 av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); |
5954 | 105 return -1; |
106 } | |
107 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
108 checksum = mlp_checksum16(gb->buffer, 26); |
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
109 if (checksum != AV_RL16(gb->buffer+26)) { |
7198 | 110 av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); |
5954 | 111 return -1; |
112 } | |
113 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
114 if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */ |
5954 | 115 return -1; |
116 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
117 mh->stream_type = get_bits(gb, 8); |
5954 | 118 |
119 if (mh->stream_type == 0xbb) { | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
120 mh->group1_bits = mlp_quants[get_bits(gb, 4)]; |
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
121 mh->group2_bits = mlp_quants[get_bits(gb, 4)]; |
5954 | 122 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
123 ratebits = get_bits(gb, 4); |
5954 | 124 mh->group1_samplerate = mlp_samplerate(ratebits); |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
125 mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4)); |
5954 | 126 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
127 skip_bits(gb, 11); |
5954 | 128 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
129 mh->channels_mlp = get_bits(gb, 5); |
5954 | 130 } else if (mh->stream_type == 0xba) { |
131 mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? | |
132 mh->group2_bits = 0; | |
133 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
134 ratebits = get_bits(gb, 4); |
5954 | 135 mh->group1_samplerate = mlp_samplerate(ratebits); |
136 mh->group2_samplerate = 0; | |
137 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
138 skip_bits(gb, 8); |
5954 | 139 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
140 mh->channels_thd_stream1 = get_bits(gb, 5); |
5954 | 141 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
142 skip_bits(gb, 2); |
5954 | 143 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
144 mh->channels_thd_stream2 = get_bits(gb, 13); |
5954 | 145 } else |
146 return -1; | |
147 | |
148 mh->access_unit_size = 40 << (ratebits & 7); | |
149 mh->access_unit_size_pow2 = 64 << (ratebits & 7); | |
150 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
151 skip_bits_long(gb, 48); |
5954 | 152 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
153 mh->is_vbr = get_bits1(gb); |
5954 | 154 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
155 mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4; |
5954 | 156 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
157 mh->num_substreams = get_bits(gb, 4); |
5954 | 158 |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
159 skip_bits_long(gb, 4 + 11 * 8); |
5954 | 160 |
161 return 0; | |
162 } | |
163 | |
164 typedef struct MLPParseContext | |
165 { | |
166 ParseContext pc; | |
167 | |
168 int bytes_left; | |
169 | |
170 int in_sync; | |
171 | |
172 int num_substreams; | |
173 } MLPParseContext; | |
174 | |
175 static int mlp_parse(AVCodecParserContext *s, | |
176 AVCodecContext *avctx, | |
177 const uint8_t **poutbuf, int *poutbuf_size, | |
178 const uint8_t *buf, int buf_size) | |
179 { | |
180 MLPParseContext *mp = s->priv_data; | |
181 int sync_present; | |
182 uint8_t parity_bits; | |
183 int next; | |
184 int i, p = 0; | |
185 | |
186 *poutbuf_size = 0; | |
187 if (buf_size == 0) | |
188 return 0; | |
189 | |
190 if (!mp->in_sync) { | |
191 // Not in sync - find a major sync header | |
192 | |
193 for (i = 0; i < buf_size; i++) { | |
194 mp->pc.state = (mp->pc.state << 8) | buf[i]; | |
195 if ((mp->pc.state & 0xfffffffe) == 0xf8726fba) { | |
196 mp->in_sync = 1; | |
197 mp->bytes_left = 0; | |
198 break; | |
199 } | |
200 } | |
201 | |
202 if (!mp->in_sync) { | |
203 ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size); | |
204 return buf_size; | |
205 } | |
206 | |
207 ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size); | |
208 | |
209 return i - 7; | |
210 } | |
211 | |
212 if (mp->bytes_left == 0) { | |
213 // Find length of this packet | |
214 | |
215 /* Copy overread bytes from last frame into buffer. */ | |
216 for(; mp->pc.overread>0; mp->pc.overread--) { | |
217 mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++]; | |
218 } | |
219 | |
220 if (mp->pc.index + buf_size < 2) { | |
221 ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size); | |
222 return buf_size; | |
223 } | |
224 | |
225 mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8) | |
226 | (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]); | |
227 mp->bytes_left = (mp->bytes_left & 0xfff) * 2; | |
228 mp->bytes_left -= mp->pc.index; | |
229 } | |
230 | |
231 next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left; | |
232 | |
233 if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) { | |
234 mp->bytes_left -= buf_size; | |
235 return buf_size; | |
236 } | |
237 | |
238 mp->bytes_left = 0; | |
239 | |
240 sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba; | |
241 | |
242 if (!sync_present) { | |
7177 | 243 /* The first nibble of a frame is a parity check of the 4-byte |
244 * access unit header and all the 2- or 4-byte substream headers. */ | |
5980 | 245 // Only check when this isn't a sync frame - syncs have a checksum. |
5954 | 246 |
247 parity_bits = 0; | |
7137
186eb61a9860
Make it a little easier to spot that the code is not dealing only with
ramiro
parents:
6763
diff
changeset
|
248 for (i = -1; i < mp->num_substreams; i++) { |
5954 | 249 parity_bits ^= buf[p++]; |
250 parity_bits ^= buf[p++]; | |
251 | |
7137
186eb61a9860
Make it a little easier to spot that the code is not dealing only with
ramiro
parents:
6763
diff
changeset
|
252 if (i < 0 || buf[p-2] & 0x80) { |
5954 | 253 parity_bits ^= buf[p++]; |
254 parity_bits ^= buf[p++]; | |
255 } | |
256 } | |
257 | |
258 if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) { | |
5980 | 259 av_log(avctx, AV_LOG_INFO, "mlpparse: Parity check failed.\n"); |
5954 | 260 goto lost_sync; |
261 } | |
262 } else { | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
263 GetBitContext gb; |
5954 | 264 MLPHeaderInfo mh; |
265 | |
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
266 init_get_bits(&gb, buf + 4, (buf_size - 4) << 3); |
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
267 if (ff_mlp_read_major_sync(avctx, &mh, &gb) < 0) |
5954 | 268 goto lost_sync; |
269 | |
270 #ifdef CONFIG_AUDIO_NONSHORT | |
271 avctx->bits_per_sample = mh.group1_bits; | |
272 if (avctx->bits_per_sample > 16) | |
273 avctx->sample_fmt = SAMPLE_FMT_S32; | |
274 #endif | |
275 avctx->sample_rate = mh.group1_samplerate; | |
276 avctx->frame_size = mh.access_unit_size; | |
277 | |
278 if (mh.stream_type == 0xbb) { | |
279 /* MLP stream */ | |
280 avctx->channels = mlp_channels[mh.channels_mlp]; | |
281 } else { /* mh.stream_type == 0xba */ | |
282 /* TrueHD stream */ | |
283 if (mh.channels_thd_stream2) | |
284 avctx->channels = truehd_channels(mh.channels_thd_stream2); | |
285 else | |
286 avctx->channels = truehd_channels(mh.channels_thd_stream1); | |
287 } | |
288 | |
289 if (!mh.is_vbr) /* Stream is CBR */ | |
290 avctx->bit_rate = mh.peak_bitrate; | |
291 | |
292 mp->num_substreams = mh.num_substreams; | |
293 } | |
294 | |
295 *poutbuf = buf; | |
296 *poutbuf_size = buf_size; | |
297 | |
298 return next; | |
299 | |
300 lost_sync: | |
301 mp->in_sync = 0; | |
7154
a9ed669e8cd1
Seek the file forwards instead of backwards when sync is lost.
ramiro
parents:
7137
diff
changeset
|
302 return 1; |
5954 | 303 } |
304 | |
305 AVCodecParser mlp_parser = { | |
306 { CODEC_ID_MLP }, | |
307 sizeof(MLPParseContext), | |
308 NULL, | |
309 mlp_parse, | |
310 NULL, | |
311 }; |