mlp_parser.c 10.2 KB
Newer Older
Ian Caulfield's avatar
Ian Caulfield committed
1 2 3 4
/*
 * MLP parser
 * Copyright (c) 2007 Ian Caulfield
 *
5
 * This file is part of Libav.
Ian Caulfield's avatar
Ian Caulfield committed
6
 *
7
 * Libav is free software; you can redistribute it and/or
Ian Caulfield's avatar
Ian Caulfield committed
8 9 10 11
 * 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.
 *
12
 * Libav is distributed in the hope that it will be useful,
Ian Caulfield's avatar
Ian Caulfield committed
13 14 15 16 17
 * 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
18
 * License along with Libav; if not, write to the Free Software
Ian Caulfield's avatar
Ian Caulfield committed
19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file
Ian Caulfield's avatar
Ian Caulfield committed
24 25 26
 * MLP parser
 */

27 28
#include <stdint.h>

29
#include "libavutil/crc.h"
30
#include "libavutil/audioconvert.h"
31
#include "get_bits.h"
Ian Caulfield's avatar
Ian Caulfield committed
32 33
#include "parser.h"
#include "mlp_parser.h"
34
#include "mlp.h"
Ian Caulfield's avatar
Ian Caulfield committed
35 36 37 38 39 40 41 42 43 44 45

static const uint8_t mlp_quants[16] = {
    16, 20, 24, 0, 0, 0, 0, 0,
     0,  0,  0, 0, 0, 0, 0, 0,
};

static const uint8_t mlp_channels[32] = {
    1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
    5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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
};

Ian Caulfield's avatar
Ian Caulfield committed
71 72 73 74 75
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
};

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
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
};

Ian Caulfield's avatar
Ian Caulfield committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
static int mlp_samplerate(int in)
{
    if (in == 0xF)
        return 0;

    return (in & 8 ? 44100 : 48000) << (in & 7) ;
}

static int truehd_channels(int chanmap)
{
    int channels = 0, i;

    for (i = 0; i < 13; i++)
        channels += thd_chancount[i] * ((chanmap >> i) & 1);

    return channels;
}

110 111 112 113 114 115 116 117 118 119
static int64_t truehd_layout(int chanmap)
{
    int layout = 0, i;

    for (i = 0; i < 13; i++)
        layout |= thd_layout[i] * ((chanmap >> i) & 1);

    return layout;
}

Ian Caulfield's avatar
Ian Caulfield committed
120 121 122
/** 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.
123
 *  gb must be a freshly initialized GetBitContext with no bits read.
Ian Caulfield's avatar
Ian Caulfield committed
124 125
 */

126
int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
Ian Caulfield's avatar
Ian Caulfield committed
127 128 129 130
{
    int ratebits;
    uint16_t checksum;

131 132 133
    assert(get_bits_count(gb) == 0);

    if (gb->size_in_bits < 28 << 3) {
Diego Biurrun's avatar
Diego Biurrun committed
134
        av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n");
Ian Caulfield's avatar
Ian Caulfield committed
135 136 137
        return -1;
    }

138
    checksum = ff_mlp_checksum16(gb->buffer, 26);
139
    if (checksum != AV_RL16(gb->buffer+26)) {
Diego Biurrun's avatar
Diego Biurrun committed
140
        av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n");
Ian Caulfield's avatar
Ian Caulfield committed
141 142 143
        return -1;
    }

144
    if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */
Ian Caulfield's avatar
Ian Caulfield committed
145 146
        return -1;

147
    mh->stream_type = get_bits(gb, 8);
Ian Caulfield's avatar
Ian Caulfield committed
148 149

    if (mh->stream_type == 0xbb) {
150 151
        mh->group1_bits = mlp_quants[get_bits(gb, 4)];
        mh->group2_bits = mlp_quants[get_bits(gb, 4)];
Ian Caulfield's avatar
Ian Caulfield committed
152

153
        ratebits = get_bits(gb, 4);
Ian Caulfield's avatar
Ian Caulfield committed
154
        mh->group1_samplerate = mlp_samplerate(ratebits);
155
        mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4));
Ian Caulfield's avatar
Ian Caulfield committed
156

157
        skip_bits(gb, 11);
Ian Caulfield's avatar
Ian Caulfield committed
158

159
        mh->channels_mlp = get_bits(gb, 5);
Ian Caulfield's avatar
Ian Caulfield committed
160 161 162 163
    } else if (mh->stream_type == 0xba) {
        mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
        mh->group2_bits = 0;

164
        ratebits = get_bits(gb, 4);
Ian Caulfield's avatar
Ian Caulfield committed
165 166 167
        mh->group1_samplerate = mlp_samplerate(ratebits);
        mh->group2_samplerate = 0;

168
        skip_bits(gb, 8);
Ian Caulfield's avatar
Ian Caulfield committed
169

170
        mh->channels_thd_stream1 = get_bits(gb, 5);
Ian Caulfield's avatar
Ian Caulfield committed
171

172
        skip_bits(gb, 2);
Ian Caulfield's avatar
Ian Caulfield committed
173

174
        mh->channels_thd_stream2 = get_bits(gb, 13);
Ian Caulfield's avatar
Ian Caulfield committed
175 176 177 178 179 180
    } else
        return -1;

    mh->access_unit_size = 40 << (ratebits & 7);
    mh->access_unit_size_pow2 = 64 << (ratebits & 7);

181
    skip_bits_long(gb, 48);
Ian Caulfield's avatar
Ian Caulfield committed
182

183
    mh->is_vbr = get_bits1(gb);
Ian Caulfield's avatar
Ian Caulfield committed
184

185
    mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4;
Ian Caulfield's avatar
Ian Caulfield committed
186

187
    mh->num_substreams = get_bits(gb, 4);
Ian Caulfield's avatar
Ian Caulfield committed
188

189
    skip_bits_long(gb, 4 + 11 * 8);
Ian Caulfield's avatar
Ian Caulfield committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

    return 0;
}

typedef struct MLPParseContext
{
    ParseContext pc;

    int bytes_left;

    int in_sync;

    int num_substreams;
} MLPParseContext;

205 206 207 208 209 210
static av_cold int mlp_init(AVCodecParserContext *s)
{
    ff_mlp_init_crc();
    return 0;
}

Ian Caulfield's avatar
Ian Caulfield committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
static int mlp_parse(AVCodecParserContext *s,
                     AVCodecContext *avctx,
                     const uint8_t **poutbuf, int *poutbuf_size,
                     const uint8_t *buf, int buf_size)
{
    MLPParseContext *mp = s->priv_data;
    int sync_present;
    uint8_t parity_bits;
    int next;
    int i, p = 0;

    *poutbuf_size = 0;
    if (buf_size == 0)
        return 0;

    if (!mp->in_sync) {
        // Not in sync - find a major sync header

        for (i = 0; i < buf_size; i++) {
            mp->pc.state = (mp->pc.state << 8) | buf[i];
231 232 233
            if ((mp->pc.state & 0xfffffffe) == 0xf8726fba &&
                // ignore if we do not have the data for the start of header
                mp->pc.index + i >= 7) {
Ian Caulfield's avatar
Ian Caulfield committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
                mp->in_sync = 1;
                mp->bytes_left = 0;
                break;
            }
        }

        if (!mp->in_sync) {
            ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
            return buf_size;
        }

        ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size);

        return i - 7;
    }

    if (mp->bytes_left == 0) {
        // Find length of this packet

        /* Copy overread bytes from last frame into buffer. */
        for(; mp->pc.overread>0; mp->pc.overread--) {
            mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++];
        }

        if (mp->pc.index + buf_size < 2) {
            ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
            return buf_size;
        }

        mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8)
                       |  (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]);
        mp->bytes_left = (mp->bytes_left & 0xfff) * 2;
        mp->bytes_left -= mp->pc.index;
    }

    next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left;

    if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) {
        mp->bytes_left -= buf_size;
        return buf_size;
    }

    mp->bytes_left = 0;

    sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba;

    if (!sync_present) {
281 282
        /* 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. */
283
        // Only check when this isn't a sync frame - syncs have a checksum.
Ian Caulfield's avatar
Ian Caulfield committed
284 285

        parity_bits = 0;
286
        for (i = -1; i < mp->num_substreams; i++) {
Ian Caulfield's avatar
Ian Caulfield committed
287 288 289
            parity_bits ^= buf[p++];
            parity_bits ^= buf[p++];

290
            if (i < 0 || buf[p-2] & 0x80) {
Ian Caulfield's avatar
Ian Caulfield committed
291 292 293 294 295 296
                parity_bits ^= buf[p++];
                parity_bits ^= buf[p++];
            }
        }

        if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) {
297
            av_log(avctx, AV_LOG_INFO, "mlpparse: Parity check failed.\n");
Ian Caulfield's avatar
Ian Caulfield committed
298 299 300
            goto lost_sync;
        }
    } else {
301
        GetBitContext gb;
Ian Caulfield's avatar
Ian Caulfield committed
302 303
        MLPHeaderInfo mh;

304 305
        init_get_bits(&gb, buf + 4, (buf_size - 4) << 3);
        if (ff_mlp_read_major_sync(avctx, &mh, &gb) < 0)
Ian Caulfield's avatar
Ian Caulfield committed
306 307
            goto lost_sync;

308 309
        avctx->bits_per_raw_sample = mh.group1_bits;
        if (avctx->bits_per_raw_sample > 16)
310
            avctx->sample_fmt = AV_SAMPLE_FMT_S32;
311
        else
312
            avctx->sample_fmt = AV_SAMPLE_FMT_S16;
Ian Caulfield's avatar
Ian Caulfield committed
313 314 315 316 317 318
        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];
319
            avctx->channel_layout = mlp_layout[mh.channels_mlp];
Ian Caulfield's avatar
Ian Caulfield committed
320 321
        } else { /* mh.stream_type == 0xba */
            /* TrueHD stream */
322
            if (mh.channels_thd_stream2) {
Ian Caulfield's avatar
Ian Caulfield committed
323
                avctx->channels = truehd_channels(mh.channels_thd_stream2);
324 325
                avctx->channel_layout = truehd_layout(mh.channels_thd_stream2);
            } else {
Ian Caulfield's avatar
Ian Caulfield committed
326
                avctx->channels = truehd_channels(mh.channels_thd_stream1);
327 328
                avctx->channel_layout = truehd_layout(mh.channels_thd_stream1);
            }
Ian Caulfield's avatar
Ian Caulfield committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
        }

        if (!mh.is_vbr) /* Stream is CBR */
            avctx->bit_rate = mh.peak_bitrate;

        mp->num_substreams = mh.num_substreams;
    }

    *poutbuf = buf;
    *poutbuf_size = buf_size;

    return next;

lost_sync:
    mp->in_sync = 0;
344
    return 1;
Ian Caulfield's avatar
Ian Caulfield committed
345 346
}

347
AVCodecParser ff_mlp_parser = {
348
    { CODEC_ID_MLP, CODEC_ID_TRUEHD },
Ian Caulfield's avatar
Ian Caulfield committed
349
    sizeof(MLPParseContext),
350
    mlp_init,
Ian Caulfield's avatar
Ian Caulfield committed
351
    mlp_parse,
Jai Menon's avatar
Jai Menon committed
352
    ff_parse_close,
Ian Caulfield's avatar
Ian Caulfield committed
353
};