mlp_parser.c 12.7 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/channel_layout.h"
30
#include "libavutil/crc.h"
31
#include "libavutil/internal.h"
32
#include "get_bits.h"
Ian Caulfield's avatar
Ian Caulfield committed
33 34
#include "parser.h"
#include "mlp_parser.h"
35
#include "mlp.h"
Ian Caulfield's avatar
Ian Caulfield committed
36 37 38 39 40 41 42 43 44 45 46

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,
};

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

77 78 79 80 81 82
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
83
    AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, // LRc
84 85
    AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,                       // LRrs
    AV_CH_BACK_CENTER,                                      // Cs
86
    AV_CH_TOP_CENTER,                                       // Ts
87
    AV_CH_SURROUND_DIRECT_LEFT|AV_CH_SURROUND_DIRECT_RIGHT, // LRsd
88 89
    AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT,                       // LRw
    AV_CH_TOP_FRONT_CENTER,                                 // Cvh
90
    AV_CH_LOW_FREQUENCY_2,                                  // LFE2
91 92
};

Ian Caulfield's avatar
Ian Caulfield committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
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;
}

111
static uint64_t truehd_layout(int chanmap)
112
{
113 114
    int i;
    uint64_t layout = 0;
115 116 117 118 119 120 121

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

    return layout;
}

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

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

133 134 135
    assert(get_bits_count(gb) == 0);

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

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

146
    if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */
147
        return AVERROR_INVALIDDATA;
Ian Caulfield's avatar
Ian Caulfield committed
148

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

    if (mh->stream_type == 0xbb) {
152 153
        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
154

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

159
        skip_bits(gb, 11);
Ian Caulfield's avatar
Ian Caulfield committed
160

161 162 163
        channel_arrangement    = get_bits(gb, 5);
        mh->channels_mlp       = mlp_channels[channel_arrangement];
        mh->channel_layout_mlp = mlp_layout[channel_arrangement];
Ian Caulfield's avatar
Ian Caulfield committed
164 165 166 167
    } else if (mh->stream_type == 0xba) {
        mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
        mh->group2_bits = 0;

168
        ratebits = get_bits(gb, 4);
Ian Caulfield's avatar
Ian Caulfield committed
169 170 171
        mh->group1_samplerate = mlp_samplerate(ratebits);
        mh->group2_samplerate = 0;

172 173 174 175
        skip_bits(gb, 4);

        mh->channel_modifier_thd_stream0 = get_bits(gb, 2);
        mh->channel_modifier_thd_stream1 = get_bits(gb, 2);
Ian Caulfield's avatar
Ian Caulfield committed
176

177 178 179
        channel_arrangement            = get_bits(gb, 5);
        mh->channels_thd_stream1       = truehd_channels(channel_arrangement);
        mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement);
Ian Caulfield's avatar
Ian Caulfield committed
180

181
        mh->channel_modifier_thd_stream2 = get_bits(gb, 2);
Ian Caulfield's avatar
Ian Caulfield committed
182

183 184 185
        channel_arrangement            = get_bits(gb, 13);
        mh->channels_thd_stream2       = truehd_channels(channel_arrangement);
        mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement);
Ian Caulfield's avatar
Ian Caulfield committed
186
    } else
187
        return AVERROR_INVALIDDATA;
Ian Caulfield's avatar
Ian Caulfield committed
188 189 190 191

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

192
    skip_bits_long(gb, 48);
Ian Caulfield's avatar
Ian Caulfield committed
193

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

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

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

200
    skip_bits_long(gb, 4 + 11 * 8);
Ian Caulfield's avatar
Ian Caulfield committed
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215

    return 0;
}

typedef struct MLPParseContext
{
    ParseContext pc;

    int bytes_left;

    int in_sync;

    int num_substreams;
} MLPParseContext;

216 217 218 219 220 221
static av_cold int mlp_init(AVCodecParserContext *s)
{
    ff_mlp_init_crc();
    return 0;
}

Ian Caulfield's avatar
Ian Caulfield committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
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];
242 243 244
            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
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 281 282 283 284 285 286 287 288 289 290 291
                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) {
292 293
        /* 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. */
294
        // Only check when this isn't a sync frame - syncs have a checksum.
Ian Caulfield's avatar
Ian Caulfield committed
295 296

        parity_bits = 0;
297
        for (i = -1; i < mp->num_substreams; i++) {
Ian Caulfield's avatar
Ian Caulfield committed
298 299 300
            parity_bits ^= buf[p++];
            parity_bits ^= buf[p++];

301
            if (i < 0 || buf[p-2] & 0x80) {
Ian Caulfield's avatar
Ian Caulfield committed
302 303 304 305 306 307
                parity_bits ^= buf[p++];
                parity_bits ^= buf[p++];
            }
        }

        if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) {
308
            av_log(avctx, AV_LOG_INFO, "mlpparse: Parity check failed.\n");
Ian Caulfield's avatar
Ian Caulfield committed
309 310 311
            goto lost_sync;
        }
    } else {
312
        GetBitContext gb;
Ian Caulfield's avatar
Ian Caulfield committed
313 314
        MLPHeaderInfo mh;

315 316
        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
317 318
            goto lost_sync;

319 320
        avctx->bits_per_raw_sample = mh.group1_bits;
        if (avctx->bits_per_raw_sample > 16)
321
            avctx->sample_fmt = AV_SAMPLE_FMT_S32;
322
        else
323
            avctx->sample_fmt = AV_SAMPLE_FMT_S16;
Ian Caulfield's avatar
Ian Caulfield committed
324
        avctx->sample_rate = mh.group1_samplerate;
325
        s->duration = mh.access_unit_size;
Ian Caulfield's avatar
Ian Caulfield committed
326 327 328

        if (mh.stream_type == 0xbb) {
            /* MLP stream */
329
#if FF_API_REQUEST_CHANNELS
330
FF_DISABLE_DEPRECATION_WARNINGS
331 332 333 334
            if (avctx->request_channels > 0 && avctx->request_channels <= 2 &&
                mh.num_substreams > 1) {
                avctx->channels       = 2;
                avctx->channel_layout = AV_CH_LAYOUT_STEREO;
335
            } else
336
FF_ENABLE_DEPRECATION_WARNINGS
337
#endif
338 339 340
            if (avctx->request_channel_layout &&
                (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) ==
                avctx->request_channel_layout &&
341 342 343
                mh.num_substreams > 1) {
                avctx->channels       = 2;
                avctx->channel_layout = AV_CH_LAYOUT_STEREO;
344 345 346 347
            } else {
                avctx->channels       = mh.channels_mlp;
                avctx->channel_layout = mh.channel_layout_mlp;
            }
Ian Caulfield's avatar
Ian Caulfield committed
348 349
        } else { /* mh.stream_type == 0xba */
            /* TrueHD stream */
350
#if FF_API_REQUEST_CHANNELS
351
FF_DISABLE_DEPRECATION_WARNINGS
352 353 354 355
            if (avctx->request_channels > 0 && avctx->request_channels <= 2 &&
                mh.num_substreams > 1) {
                avctx->channels       = 2;
                avctx->channel_layout = AV_CH_LAYOUT_STEREO;
356 357 358 359 360
            } else if (avctx->request_channels > 0 &&
                       avctx->request_channels <= mh.channels_thd_stream1) {
                avctx->channels       = mh.channels_thd_stream1;
                avctx->channel_layout = mh.channel_layout_thd_stream1;
            } else
361
FF_ENABLE_DEPRECATION_WARNINGS
362
#endif
363 364 365 366
                if (avctx->request_channel_layout &&
                    (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) ==
                    avctx->request_channel_layout &&
                    mh.num_substreams > 1) {
367 368
                avctx->channels       = 2;
                avctx->channel_layout = AV_CH_LAYOUT_STEREO;
369
            } else if (!mh.channels_thd_stream2 ||
370 371 372
                       (avctx->request_channel_layout &&
                        (avctx->request_channel_layout & mh.channel_layout_thd_stream1) ==
                        avctx->request_channel_layout)) {
373 374
                avctx->channels       = mh.channels_thd_stream1;
                avctx->channel_layout = mh.channel_layout_thd_stream1;
375 376 377
            } else {
                avctx->channels       = mh.channels_thd_stream2;
                avctx->channel_layout = mh.channel_layout_thd_stream2;
378
            }
Ian Caulfield's avatar
Ian Caulfield committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
        }

        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;
394
    return 1;
Ian Caulfield's avatar
Ian Caulfield committed
395 396
}

397
AVCodecParser ff_mlp_parser = {
398
    .codec_ids      = { AV_CODEC_ID_MLP, AV_CODEC_ID_TRUEHD },
399 400 401 402
    .priv_data_size = sizeof(MLPParseContext),
    .parser_init    = mlp_init,
    .parser_parse   = mlp_parse,
    .parser_close   = ff_parse_close,
Ian Caulfield's avatar
Ian Caulfield committed
403
};