X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmlp_parser.c;h=e0fedeb7e9503deed154724fd99f1d864d4d56da;hb=467879eb54526d187847bbbd32723500ab0ab330;hp=a2cd6469e66b799f65cd9f7dadee433c4a162d8c;hpb=245976da2a7f9a4a03dfb6903e9437b7cf2967f4;p=ffmpeg diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index a2cd6469e66..e0fedeb7e95 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -2,32 +2,36 @@ * MLP parser * Copyright (c) 2007 Ian Caulfield * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** - * @file mlp_parser.c + * @file * MLP parser */ +#include + #include "libavutil/crc.h" -#include "bitstream.h" +#include "libavutil/audioconvert.h" +#include "get_bits.h" #include "parser.h" #include "mlp_parser.h" +#include "mlp.h" static const uint8_t mlp_quants[16] = { 16, 20, 24, 0, 0, 0, 0, 0, @@ -39,11 +43,52 @@ static const uint8_t mlp_channels[32] = { 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +static const uint64_t mlp_layout[32] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_2_1, + AV_CH_LAYOUT_2_2, + AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0, + AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0, + AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT0, + AV_CH_LAYOUT_5POINT1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + static const uint8_t thd_chancount[13] = { // LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1 }; +static const uint64_t thd_layout[13] = { + AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT, // LR + AV_CH_FRONT_CENTER, // C + AV_CH_LOW_FREQUENCY, // LFE + AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRs + AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT, // LRvh + AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRc + AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT, // LRrs + AV_CH_BACK_CENTER, // Cs + AV_CH_TOP_BACK_CENTER, // Ts + AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRsd + AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, // LRw + AV_CH_TOP_BACK_CENTER, // Cvh + AV_CH_LOW_FREQUENCY // LFE2 +}; + static int mlp_samplerate(int in) { if (in == 0xF) @@ -62,100 +107,86 @@ static int truehd_channels(int chanmap) return channels; } -static int crc_init = 0; -static AVCRC crc_2D[1024]; - -/** MLP uses checksums that seem to be based on the standard CRC algorithm, - * but not (in implementation terms, the table lookup and XOR are reversed). - * We can implement this behavior using a standard av_crc on all but the - * last element, then XOR that with the last element. - */ - -static uint16_t mlp_checksum16(const uint8_t *buf, unsigned int buf_size) +static uint64_t truehd_layout(int chanmap) { - uint16_t crc; + int layout = 0, i; - if (!crc_init) { - av_crc_init(crc_2D, 0, 16, 0x002D, sizeof(crc_2D)); - crc_init = 1; - } + for (i = 0; i < 13; i++) + layout |= thd_layout[i] * ((chanmap >> i) & 1); - crc = av_crc(crc_2D, 0, buf, buf_size - 2); - crc ^= AV_RL16(buf + buf_size - 2); - return crc; + return layout; } /** Read a major sync info header - contains high level information about * the stream - sample rate, channel arrangement etc. Most of this * information is not actually necessary for decoding, only for playback. + * gb must be a freshly initialized GetBitContext with no bits read. */ -int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, const uint8_t *buf, - unsigned int buf_size) +int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) { - GetBitContext gb; int ratebits; uint16_t checksum; - if (buf_size < 28) { - av_log(log, AV_LOG_ERROR, "Packet too short, unable to read major sync\n"); + assert(get_bits_count(gb) == 0); + + if (gb->size_in_bits < 28 << 3) { + av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); return -1; } - checksum = mlp_checksum16(buf, 26); - if (checksum != AV_RL16(buf+26)) { - av_log(log, AV_LOG_ERROR, "Major sync info header checksum error\n"); - return -1; + checksum = ff_mlp_checksum16(gb->buffer, 26); + if (checksum != AV_RL16(gb->buffer+26)) { + av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); + return AVERROR_INVALIDDATA; } - init_get_bits(&gb, buf, buf_size * 8); + if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */ + return AVERROR_INVALIDDATA; - if (get_bits_long(&gb, 24) != 0xf8726f) /* Sync words */ - return -1; - - mh->stream_type = get_bits(&gb, 8); + mh->stream_type = get_bits(gb, 8); if (mh->stream_type == 0xbb) { - mh->group1_bits = mlp_quants[get_bits(&gb, 4)]; - mh->group2_bits = mlp_quants[get_bits(&gb, 4)]; + mh->group1_bits = mlp_quants[get_bits(gb, 4)]; + mh->group2_bits = mlp_quants[get_bits(gb, 4)]; - ratebits = get_bits(&gb, 4); + ratebits = get_bits(gb, 4); mh->group1_samplerate = mlp_samplerate(ratebits); - mh->group2_samplerate = mlp_samplerate(get_bits(&gb, 4)); + mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4)); - skip_bits(&gb, 11); + skip_bits(gb, 11); - mh->channels_mlp = get_bits(&gb, 5); + mh->channels_mlp = get_bits(gb, 5); } else if (mh->stream_type == 0xba) { mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? mh->group2_bits = 0; - ratebits = get_bits(&gb, 4); + ratebits = get_bits(gb, 4); mh->group1_samplerate = mlp_samplerate(ratebits); mh->group2_samplerate = 0; - skip_bits(&gb, 8); + skip_bits(gb, 8); - mh->channels_thd_stream1 = get_bits(&gb, 5); + mh->channels_thd_stream1 = get_bits(gb, 5); - skip_bits(&gb, 2); + skip_bits(gb, 2); - mh->channels_thd_stream2 = get_bits(&gb, 13); + mh->channels_thd_stream2 = get_bits(gb, 13); } else - return -1; + return AVERROR_INVALIDDATA; mh->access_unit_size = 40 << (ratebits & 7); mh->access_unit_size_pow2 = 64 << (ratebits & 7); - skip_bits_long(&gb, 48); + skip_bits_long(gb, 48); - mh->is_vbr = get_bits1(&gb); + mh->is_vbr = get_bits1(gb); - mh->peak_bitrate = (get_bits(&gb, 15) * mh->group1_samplerate + 8) >> 4; + mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4; - mh->num_substreams = get_bits(&gb, 4); + mh->num_substreams = get_bits(gb, 4); - skip_bits_long(&gb, 4 + 11 * 8); + skip_bits_long(gb, 4 + 11 * 8); return 0; } @@ -171,6 +202,12 @@ typedef struct MLPParseContext int num_substreams; } MLPParseContext; +static av_cold int mlp_init(AVCodecParserContext *s) +{ + ff_mlp_init_crc(); + return 0; +} + static int mlp_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, @@ -191,7 +228,9 @@ static int mlp_parse(AVCodecParserContext *s, for (i = 0; i < buf_size; i++) { mp->pc.state = (mp->pc.state << 8) | buf[i]; - if ((mp->pc.state & 0xfffffffe) == 0xf8726fba) { + if ((mp->pc.state & 0xfffffffe) == 0xf8726fba && + // ignore if we do not have the data for the start of header + mp->pc.index + i >= 7) { mp->in_sync = 1; mp->bytes_left = 0; break; @@ -239,15 +278,16 @@ static int mlp_parse(AVCodecParserContext *s, sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba; if (!sync_present) { - // First nibble of a frame is a parity check of the first few nibbles. + /* The first nibble of a frame is a parity check of the 4-byte + * access unit header and all the 2- or 4-byte substream headers. */ // Only check when this isn't a sync frame - syncs have a checksum. parity_bits = 0; - for (i = 0; i <= mp->num_substreams; i++) { + for (i = -1; i < mp->num_substreams; i++) { parity_bits ^= buf[p++]; parity_bits ^= buf[p++]; - if (i == 0 || buf[p-2] & 0x80) { + if (i < 0 || buf[p-2] & 0x80) { parity_bits ^= buf[p++]; parity_bits ^= buf[p++]; } @@ -258,28 +298,34 @@ static int mlp_parse(AVCodecParserContext *s, goto lost_sync; } } else { + GetBitContext gb; MLPHeaderInfo mh; - if (ff_mlp_read_major_sync(avctx, &mh, buf + 4, buf_size - 4) < 0) + init_get_bits(&gb, buf + 4, (buf_size - 4) << 3); + if (ff_mlp_read_major_sync(avctx, &mh, &gb) < 0) goto lost_sync; -#ifdef CONFIG_AUDIO_NONSHORT - avctx->bits_per_sample = mh.group1_bits; - if (avctx->bits_per_sample > 16) - avctx->sample_fmt = SAMPLE_FMT_S32; -#endif + avctx->bits_per_raw_sample = mh.group1_bits; + if (avctx->bits_per_raw_sample > 16) + avctx->sample_fmt = AV_SAMPLE_FMT_S32; + else + avctx->sample_fmt = AV_SAMPLE_FMT_S16; avctx->sample_rate = mh.group1_samplerate; avctx->frame_size = mh.access_unit_size; if (mh.stream_type == 0xbb) { /* MLP stream */ avctx->channels = mlp_channels[mh.channels_mlp]; + avctx->channel_layout = mlp_layout[mh.channels_mlp]; } else { /* mh.stream_type == 0xba */ /* TrueHD stream */ - if (mh.channels_thd_stream2) + if (mh.channels_thd_stream2) { avctx->channels = truehd_channels(mh.channels_thd_stream2); - else + avctx->channel_layout = truehd_layout(mh.channels_thd_stream2); + } else { avctx->channels = truehd_channels(mh.channels_thd_stream1); + avctx->channel_layout = truehd_layout(mh.channels_thd_stream1); + } } if (!mh.is_vbr) /* Stream is CBR */ @@ -295,13 +341,13 @@ static int mlp_parse(AVCodecParserContext *s, lost_sync: mp->in_sync = 0; - return -1; + return 1; } -AVCodecParser mlp_parser = { - { CODEC_ID_MLP }, - sizeof(MLPParseContext), - NULL, - mlp_parse, - NULL, +AVCodecParser ff_mlp_parser = { + .codec_ids = { CODEC_ID_MLP, CODEC_ID_TRUEHD }, + .priv_data_size = sizeof(MLPParseContext), + .parser_init = mlp_init, + .parser_parse = mlp_parse, + .parser_close = ff_parse_close, };