mlp_parser.c 10.5 KB
Newer Older
Ian Caulfield's avatar
Ian Caulfield committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * MLP parser
 * Copyright (c) 2007 Ian Caulfield
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg 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,
 * 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
 * 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
const uint64_t ff_mlp_layout[32] = {
47 48 49
    AV_CH_LAYOUT_MONO,
    AV_CH_LAYOUT_STEREO,
    AV_CH_LAYOUT_2_1,
50
    AV_CH_LAYOUT_QUAD,
51 52
    AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY,
    AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY,
53
    AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
54 55
    AV_CH_LAYOUT_SURROUND,
    AV_CH_LAYOUT_4POINT0,
56
    AV_CH_LAYOUT_5POINT0_BACK,
57 58
    AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
    AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
59
    AV_CH_LAYOUT_5POINT1_BACK,
60
    AV_CH_LAYOUT_4POINT0,
61
    AV_CH_LAYOUT_5POINT0_BACK,
62 63
    AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
    AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
64 65 66 67
    AV_CH_LAYOUT_5POINT1_BACK,
    AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
    AV_CH_LAYOUT_5POINT0_BACK,
    AV_CH_LAYOUT_5POINT1_BACK,
68 69 70
    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
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
82
    AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, // LRc
83 84
    AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,                       // LRrs
    AV_CH_BACK_CENTER,                                      // Cs
85 86
    AV_CH_TOP_CENTER,                                       // Ts
    AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,                       // LRsd - TODO: Surround Direct
87
    AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT,                       // LRw
88
    AV_CH_TOP_FRONT_CENTER,                                 // Cvh
89 90 91
    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
uint64_t ff_truehd_layout(int chanmap)
111
{
112 113
    int i;
    uint64_t layout = 0;
114 115 116 117 118 119 120

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

    return layout;
}

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

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

132
    av_assert1(get_bits_count(gb) == 0);
133 134

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return 0;
}

typedef struct MLPParseContext
{
    ParseContext pc;

    int bytes_left;

    int in_sync;

    int num_substreams;
} MLPParseContext;

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

Ian Caulfield's avatar
Ian Caulfield committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
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];
232 233 234
            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
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
                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;
267 268 269
        if (mp->bytes_left <= 0) { // prevent infinite loop
            goto lost_sync;
        }
Ian Caulfield's avatar
Ian Caulfield committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
        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) {
285 286
        /* 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. */
287
        // Only check when this isn't a sync frame - syncs have a checksum.
Ian Caulfield's avatar
Ian Caulfield committed
288 289

        parity_bits = 0;
290
        for (i = -1; i < mp->num_substreams; i++) {
Ian Caulfield's avatar
Ian Caulfield committed
291 292 293
            parity_bits ^= buf[p++];
            parity_bits ^= buf[p++];

294
            if (i < 0 || buf[p-2] & 0x80) {
Ian Caulfield's avatar
Ian Caulfield committed
295 296 297 298 299 300
                parity_bits ^= buf[p++];
                parity_bits ^= buf[p++];
            }
        }

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

308 309
        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
310 311
            goto lost_sync;

312 313
        avctx->bits_per_raw_sample = mh.group1_bits;
        if (avctx->bits_per_raw_sample > 16)
314
            avctx->sample_fmt = AV_SAMPLE_FMT_S32;
315
        else
316
            avctx->sample_fmt = AV_SAMPLE_FMT_S16;
Ian Caulfield's avatar
Ian Caulfield committed
317
        avctx->sample_rate = mh.group1_samplerate;
318
        s->duration = mh.access_unit_size;
Ian Caulfield's avatar
Ian Caulfield committed
319 320 321 322

        if (mh.stream_type == 0xbb) {
            /* MLP stream */
            avctx->channels = mlp_channels[mh.channels_mlp];
323
            avctx->channel_layout = ff_mlp_layout[mh.channels_mlp];
Ian Caulfield's avatar
Ian Caulfield committed
324 325
        } else { /* mh.stream_type == 0xba */
            /* TrueHD stream */
326
            if (mh.channels_thd_stream2) {
Ian Caulfield's avatar
Ian Caulfield committed
327
                avctx->channels = truehd_channels(mh.channels_thd_stream2);
328
                avctx->channel_layout = ff_truehd_layout(mh.channels_thd_stream2);
329
            } else {
Ian Caulfield's avatar
Ian Caulfield committed
330
                avctx->channels = truehd_channels(mh.channels_thd_stream1);
331
                avctx->channel_layout = ff_truehd_layout(mh.channels_thd_stream1);
332
            }
Ian Caulfield's avatar
Ian Caulfield committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        }

        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;
348
    return 1;
Ian Caulfield's avatar
Ian Caulfield committed
349 350
}

351
AVCodecParser ff_mlp_parser = {
352 353 354 355 356
    .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,
Ian Caulfield's avatar
Ian Caulfield committed
357
};