Mercurial > libavcodec.hg
annotate mlp_parser.c @ 8228:416ffc3907bf libavcodec
Remove ineffectual hack that attempts to build ppc/check_altivec.o without
AltiVec flags. The flags are set by configure and used to compile all files
anyway. Setting extra AltiVec options here just duplicates them for the files
for which they are set.
| author | diego |
|---|---|
| date | Sun, 30 Nov 2008 16:57:28 +0000 |
| parents | fd24c8628221 |
| children | 45cfe1d44e86 |
| 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" | |
|
7559
fd24c8628221
mlp: Split common code from parser and decoder to be used by encoder.
ramiro
parents:
7557
diff
changeset
|
33 #include "mlp.h" |
| 5954 | 34 |
| 35 static const uint8_t mlp_quants[16] = { | |
| 36 16, 20, 24, 0, 0, 0, 0, 0, | |
| 37 0, 0, 0, 0, 0, 0, 0, 0, | |
| 38 }; | |
| 39 | |
| 40 static const uint8_t mlp_channels[32] = { | |
| 41 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4, | |
| 42 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 43 }; | |
| 44 | |
| 45 static const uint8_t thd_chancount[13] = { | |
| 46 // LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2 | |
| 47 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1 | |
| 48 }; | |
| 49 | |
| 50 static int mlp_samplerate(int in) | |
| 51 { | |
| 52 if (in == 0xF) | |
| 53 return 0; | |
| 54 | |
| 55 return (in & 8 ? 44100 : 48000) << (in & 7) ; | |
| 56 } | |
| 57 | |
| 58 static int truehd_channels(int chanmap) | |
| 59 { | |
| 60 int channels = 0, i; | |
| 61 | |
| 62 for (i = 0; i < 13; i++) | |
| 63 channels += thd_chancount[i] * ((chanmap >> i) & 1); | |
| 64 | |
| 65 return channels; | |
| 66 } | |
| 67 | |
| 68 /** Read a major sync info header - contains high level information about | |
| 69 * the stream - sample rate, channel arrangement etc. Most of this | |
| 70 * 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
|
71 * gb must be a freshly initialized GetBitContext with no bits read. |
| 5954 | 72 */ |
| 73 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
74 int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) |
| 5954 | 75 { |
| 76 int ratebits; | |
| 77 uint16_t checksum; | |
| 78 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
79 assert(get_bits_count(gb) == 0); |
|
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
80 |
|
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
81 if (gb->size_in_bits < 28 << 3) { |
| 7198 | 82 av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); |
| 5954 | 83 return -1; |
| 84 } | |
| 85 | |
|
7559
fd24c8628221
mlp: Split common code from parser and decoder to be used by encoder.
ramiro
parents:
7557
diff
changeset
|
86 checksum = ff_mlp_checksum16(gb->buffer, 26); |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
87 if (checksum != AV_RL16(gb->buffer+26)) { |
| 7198 | 88 av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); |
| 5954 | 89 return -1; |
| 90 } | |
| 91 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
92 if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */ |
| 5954 | 93 return -1; |
| 94 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
95 mh->stream_type = get_bits(gb, 8); |
| 5954 | 96 |
| 97 if (mh->stream_type == 0xbb) { | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
98 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
|
99 mh->group2_bits = mlp_quants[get_bits(gb, 4)]; |
| 5954 | 100 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
101 ratebits = get_bits(gb, 4); |
| 5954 | 102 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
|
103 mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4)); |
| 5954 | 104 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
105 skip_bits(gb, 11); |
| 5954 | 106 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
107 mh->channels_mlp = get_bits(gb, 5); |
| 5954 | 108 } else if (mh->stream_type == 0xba) { |
| 109 mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? | |
| 110 mh->group2_bits = 0; | |
| 111 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
112 ratebits = get_bits(gb, 4); |
| 5954 | 113 mh->group1_samplerate = mlp_samplerate(ratebits); |
| 114 mh->group2_samplerate = 0; | |
| 115 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
116 skip_bits(gb, 8); |
| 5954 | 117 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
118 mh->channels_thd_stream1 = get_bits(gb, 5); |
| 5954 | 119 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
120 skip_bits(gb, 2); |
| 5954 | 121 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
122 mh->channels_thd_stream2 = get_bits(gb, 13); |
| 5954 | 123 } else |
| 124 return -1; | |
| 125 | |
| 126 mh->access_unit_size = 40 << (ratebits & 7); | |
| 127 mh->access_unit_size_pow2 = 64 << (ratebits & 7); | |
| 128 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
129 skip_bits_long(gb, 48); |
| 5954 | 130 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
131 mh->is_vbr = get_bits1(gb); |
| 5954 | 132 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
133 mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4; |
| 5954 | 134 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
135 mh->num_substreams = get_bits(gb, 4); |
| 5954 | 136 |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
137 skip_bits_long(gb, 4 + 11 * 8); |
| 5954 | 138 |
| 139 return 0; | |
| 140 } | |
| 141 | |
| 142 typedef struct MLPParseContext | |
| 143 { | |
| 144 ParseContext pc; | |
| 145 | |
| 146 int bytes_left; | |
| 147 | |
| 148 int in_sync; | |
| 149 | |
| 150 int num_substreams; | |
| 151 } MLPParseContext; | |
| 152 | |
| 153 static int mlp_parse(AVCodecParserContext *s, | |
| 154 AVCodecContext *avctx, | |
| 155 const uint8_t **poutbuf, int *poutbuf_size, | |
| 156 const uint8_t *buf, int buf_size) | |
| 157 { | |
| 158 MLPParseContext *mp = s->priv_data; | |
| 159 int sync_present; | |
| 160 uint8_t parity_bits; | |
| 161 int next; | |
| 162 int i, p = 0; | |
| 163 | |
| 164 *poutbuf_size = 0; | |
| 165 if (buf_size == 0) | |
| 166 return 0; | |
| 167 | |
| 168 if (!mp->in_sync) { | |
| 169 // Not in sync - find a major sync header | |
| 170 | |
| 171 for (i = 0; i < buf_size; i++) { | |
| 172 mp->pc.state = (mp->pc.state << 8) | buf[i]; | |
| 173 if ((mp->pc.state & 0xfffffffe) == 0xf8726fba) { | |
| 174 mp->in_sync = 1; | |
| 175 mp->bytes_left = 0; | |
| 176 break; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 if (!mp->in_sync) { | |
| 181 ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size); | |
| 182 return buf_size; | |
| 183 } | |
| 184 | |
| 185 ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size); | |
| 186 | |
| 187 return i - 7; | |
| 188 } | |
| 189 | |
| 190 if (mp->bytes_left == 0) { | |
| 191 // Find length of this packet | |
| 192 | |
| 193 /* Copy overread bytes from last frame into buffer. */ | |
| 194 for(; mp->pc.overread>0; mp->pc.overread--) { | |
| 195 mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++]; | |
| 196 } | |
| 197 | |
| 198 if (mp->pc.index + buf_size < 2) { | |
| 199 ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size); | |
| 200 return buf_size; | |
| 201 } | |
| 202 | |
| 203 mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8) | |
| 204 | (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]); | |
| 205 mp->bytes_left = (mp->bytes_left & 0xfff) * 2; | |
| 206 mp->bytes_left -= mp->pc.index; | |
| 207 } | |
| 208 | |
| 209 next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left; | |
| 210 | |
| 211 if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) { | |
| 212 mp->bytes_left -= buf_size; | |
| 213 return buf_size; | |
| 214 } | |
| 215 | |
| 216 mp->bytes_left = 0; | |
| 217 | |
| 218 sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba; | |
| 219 | |
| 220 if (!sync_present) { | |
| 7177 | 221 /* The first nibble of a frame is a parity check of the 4-byte |
| 222 * access unit header and all the 2- or 4-byte substream headers. */ | |
| 5980 | 223 // Only check when this isn't a sync frame - syncs have a checksum. |
| 5954 | 224 |
| 225 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
|
226 for (i = -1; i < mp->num_substreams; i++) { |
| 5954 | 227 parity_bits ^= buf[p++]; |
| 228 parity_bits ^= buf[p++]; | |
| 229 | |
|
7137
186eb61a9860
Make it a little easier to spot that the code is not dealing only with
ramiro
parents:
6763
diff
changeset
|
230 if (i < 0 || buf[p-2] & 0x80) { |
| 5954 | 231 parity_bits ^= buf[p++]; |
| 232 parity_bits ^= buf[p++]; | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) { | |
| 5980 | 237 av_log(avctx, AV_LOG_INFO, "mlpparse: Parity check failed.\n"); |
| 5954 | 238 goto lost_sync; |
| 239 } | |
| 240 } else { | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
241 GetBitContext gb; |
| 5954 | 242 MLPHeaderInfo mh; |
| 243 | |
|
7176
ae78650d4ac8
Make ff_mlp_read_major_sync() take a GetBitContext instead of buffers.
ramiro
parents:
7154
diff
changeset
|
244 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
|
245 if (ff_mlp_read_major_sync(avctx, &mh, &gb) < 0) |
| 5954 | 246 goto lost_sync; |
| 247 | |
| 248 #ifdef CONFIG_AUDIO_NONSHORT | |
| 249 avctx->bits_per_sample = mh.group1_bits; | |
| 250 if (avctx->bits_per_sample > 16) | |
| 251 avctx->sample_fmt = SAMPLE_FMT_S32; | |
| 252 #endif | |
| 253 avctx->sample_rate = mh.group1_samplerate; | |
| 254 avctx->frame_size = mh.access_unit_size; | |
| 255 | |
| 256 if (mh.stream_type == 0xbb) { | |
| 257 /* MLP stream */ | |
| 258 avctx->channels = mlp_channels[mh.channels_mlp]; | |
| 259 } else { /* mh.stream_type == 0xba */ | |
| 260 /* TrueHD stream */ | |
| 261 if (mh.channels_thd_stream2) | |
| 262 avctx->channels = truehd_channels(mh.channels_thd_stream2); | |
| 263 else | |
| 264 avctx->channels = truehd_channels(mh.channels_thd_stream1); | |
| 265 } | |
| 266 | |
| 267 if (!mh.is_vbr) /* Stream is CBR */ | |
| 268 avctx->bit_rate = mh.peak_bitrate; | |
| 269 | |
| 270 mp->num_substreams = mh.num_substreams; | |
| 271 } | |
| 272 | |
| 273 *poutbuf = buf; | |
| 274 *poutbuf_size = buf_size; | |
| 275 | |
| 276 return next; | |
| 277 | |
| 278 lost_sync: | |
| 279 mp->in_sync = 0; | |
|
7154
a9ed669e8cd1
Seek the file forwards instead of backwards when sync is lost.
ramiro
parents:
7137
diff
changeset
|
280 return 1; |
| 5954 | 281 } |
| 282 | |
| 283 AVCodecParser mlp_parser = { | |
| 284 { CODEC_ID_MLP }, | |
| 285 sizeof(MLPParseContext), | |
|
7559
fd24c8628221
mlp: Split common code from parser and decoder to be used by encoder.
ramiro
parents:
7557
diff
changeset
|
286 ff_mlp_init_crc2D, |
| 5954 | 287 mlp_parse, |
| 288 NULL, | |
| 289 }; |
