xref: /third_party/ffmpeg/libavcodec/mlp_parse.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2007 Ian Caulfield
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <stdint.h>
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
24cabdff1aSopenharmony_ci#include "get_bits.h"
25cabdff1aSopenharmony_ci#include "mlp_parse.h"
26cabdff1aSopenharmony_ci#include "mlp.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_cistatic const uint8_t mlp_quants[16] = {
29cabdff1aSopenharmony_ci    16, 20, 24, 0, 0, 0, 0, 0,
30cabdff1aSopenharmony_ci     0,  0,  0, 0, 0, 0, 0, 0,
31cabdff1aSopenharmony_ci};
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_cistatic const uint8_t mlp_channels[32] = {
34cabdff1aSopenharmony_ci    1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
35cabdff1aSopenharmony_ci    5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36cabdff1aSopenharmony_ci};
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_cistatic const uint64_t mlp_layout[32] = {
39cabdff1aSopenharmony_ci    AV_CH_LAYOUT_MONO,
40cabdff1aSopenharmony_ci    AV_CH_LAYOUT_STEREO,
41cabdff1aSopenharmony_ci    AV_CH_LAYOUT_2_1,
42cabdff1aSopenharmony_ci    AV_CH_LAYOUT_QUAD,
43cabdff1aSopenharmony_ci    AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY,
44cabdff1aSopenharmony_ci    AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY,
45cabdff1aSopenharmony_ci    AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
46cabdff1aSopenharmony_ci    AV_CH_LAYOUT_SURROUND,
47cabdff1aSopenharmony_ci    AV_CH_LAYOUT_4POINT0,
48cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT0_BACK,
49cabdff1aSopenharmony_ci    AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
50cabdff1aSopenharmony_ci    AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
51cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT1_BACK,
52cabdff1aSopenharmony_ci    AV_CH_LAYOUT_4POINT0,
53cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT0_BACK,
54cabdff1aSopenharmony_ci    AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
55cabdff1aSopenharmony_ci    AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
56cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT1_BACK,
57cabdff1aSopenharmony_ci    AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
58cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT0_BACK,
59cabdff1aSopenharmony_ci    AV_CH_LAYOUT_5POINT1_BACK,
60cabdff1aSopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
61cabdff1aSopenharmony_ci};
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_cistatic int mlp_get_major_sync_size(const uint8_t * buf, int bufsize)
64cabdff1aSopenharmony_ci{
65cabdff1aSopenharmony_ci    int has_extension, extensions = 0;
66cabdff1aSopenharmony_ci    int size = 28;
67cabdff1aSopenharmony_ci    if (bufsize < 28)
68cabdff1aSopenharmony_ci        return -1;
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    if (AV_RB32(buf) == 0xf8726fba) {
71cabdff1aSopenharmony_ci        has_extension = buf[25] & 1;
72cabdff1aSopenharmony_ci        if (has_extension) {
73cabdff1aSopenharmony_ci            extensions = buf[26] >> 4;
74cabdff1aSopenharmony_ci            size += 2 + extensions * 2;
75cabdff1aSopenharmony_ci        }
76cabdff1aSopenharmony_ci    }
77cabdff1aSopenharmony_ci    return size;
78cabdff1aSopenharmony_ci}
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_ci/** Read a major sync info header - contains high level information about
81cabdff1aSopenharmony_ci *  the stream - sample rate, channel arrangement etc. Most of this
82cabdff1aSopenharmony_ci *  information is not actually necessary for decoding, only for playback.
83cabdff1aSopenharmony_ci *  gb must be a freshly initialized GetBitContext with no bits read.
84cabdff1aSopenharmony_ci */
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_ciint ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
87cabdff1aSopenharmony_ci{
88cabdff1aSopenharmony_ci    int ratebits, channel_arrangement, header_size;
89cabdff1aSopenharmony_ci    uint16_t checksum;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    av_assert1(get_bits_count(gb) == 0);
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_ci    header_size = mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3);
94cabdff1aSopenharmony_ci    if (header_size < 0 || gb->size_in_bits < header_size << 3) {
95cabdff1aSopenharmony_ci        av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n");
96cabdff1aSopenharmony_ci        return -1;
97cabdff1aSopenharmony_ci    }
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_ci    checksum = ff_mlp_checksum16(gb->buffer, header_size - 2);
100cabdff1aSopenharmony_ci    if (checksum != AV_RL16(gb->buffer+header_size-2)) {
101cabdff1aSopenharmony_ci        av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n");
102cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    if (get_bits(gb, 24) != 0xf8726f) /* Sync words */
106cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    mh->stream_type = get_bits(gb, 8);
109cabdff1aSopenharmony_ci    mh->header_size = header_size;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    if (mh->stream_type == 0xbb) {
112cabdff1aSopenharmony_ci        mh->group1_bits = mlp_quants[get_bits(gb, 4)];
113cabdff1aSopenharmony_ci        mh->group2_bits = mlp_quants[get_bits(gb, 4)];
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci        ratebits = get_bits(gb, 4);
116cabdff1aSopenharmony_ci        mh->group1_samplerate = mlp_samplerate(ratebits);
117cabdff1aSopenharmony_ci        mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4));
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci        skip_bits(gb, 11);
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci        mh->channel_arrangement=
122cabdff1aSopenharmony_ci        channel_arrangement    = get_bits(gb, 5);
123cabdff1aSopenharmony_ci        mh->channels_mlp       = mlp_channels[channel_arrangement];
124cabdff1aSopenharmony_ci        mh->channel_layout_mlp = mlp_layout[channel_arrangement];
125cabdff1aSopenharmony_ci    } else if (mh->stream_type == 0xba) {
126cabdff1aSopenharmony_ci        mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
127cabdff1aSopenharmony_ci        mh->group2_bits = 0;
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci        ratebits = get_bits(gb, 4);
130cabdff1aSopenharmony_ci        mh->group1_samplerate = mlp_samplerate(ratebits);
131cabdff1aSopenharmony_ci        mh->group2_samplerate = 0;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci        skip_bits(gb, 4);
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci        mh->channel_modifier_thd_stream0 = get_bits(gb, 2);
136cabdff1aSopenharmony_ci        mh->channel_modifier_thd_stream1 = get_bits(gb, 2);
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci        mh->channel_arrangement=
139cabdff1aSopenharmony_ci        channel_arrangement            = get_bits(gb, 5);
140cabdff1aSopenharmony_ci        mh->channels_thd_stream1       = truehd_channels(channel_arrangement);
141cabdff1aSopenharmony_ci        mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement);
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci        mh->channel_modifier_thd_stream2 = get_bits(gb, 2);
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci        channel_arrangement            = get_bits(gb, 13);
146cabdff1aSopenharmony_ci        mh->channels_thd_stream2       = truehd_channels(channel_arrangement);
147cabdff1aSopenharmony_ci        mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement);
148cabdff1aSopenharmony_ci    } else
149cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    mh->access_unit_size = 40 << (ratebits & 7);
152cabdff1aSopenharmony_ci    mh->access_unit_size_pow2 = 64 << (ratebits & 7);
153cabdff1aSopenharmony_ci
154cabdff1aSopenharmony_ci    skip_bits_long(gb, 48);
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci    mh->is_vbr = get_bits1(gb);
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4;
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_ci    mh->num_substreams = get_bits(gb, 4);
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    skip_bits_long(gb, 4 + (header_size - 17) * 8);
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    return 0;
165cabdff1aSopenharmony_ci}
166