Shaka Packager SDK
Loading...
Searching...
No Matches
mpeg1_header.cc
1// Copyright 2023 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/formats/mp2t/mpeg1_header.h>
8
9#include <cstddef>
10#include <cstdint>
11#include <iterator>
12#include <vector>
13
14#include <absl/log/check.h>
15
16#include <packager/media/base/bit_reader.h>
17#include <packager/media/base/bit_writer.h>
18#include <packager/media/formats/mp2t/mp2t_common.h>
19
20// Parsing is done according to
21// https://www.datavoyage.com/mpgscript/mpeghdr.htm
22namespace {
23const size_t kMpeg1HeaderMinSize = 4;
24
25const uint8_t kMpeg1V_INV = 0b01; /* Invalid version */
26const uint8_t kMpeg1L_INV = 0b00; /* Invalid layer */
27
28const uint8_t kMpeg1L_3 = 0b01;
29const uint8_t kMpeg1L_2 = 0b10;
30const uint8_t kMpeg1L_1 = 0b11;
31
32const size_t kMpeg1SamplesPerFrameTable[] = {
33 // L1, L2, L3
34 384, 1152, 1152};
35
36const uint32_t kMpeg1SampleRateTable[][3] = {
37 // clang-format off
38 // V1, V2, V2.5
39 {44100, 22050, 11025},
40 {48000, 24000, 12000},
41 {32000, 16000, 8000}};
42// clang-format on
43const size_t kMpeg1SampleRateTableSize = std::size(kMpeg1SampleRateTable);
44
45static inline uint32_t Mpeg1SampleRate(uint8_t sr_idx, uint8_t version) {
46 static int sr_version_indexes[] = {2, -1, 1, 0}; // {V2.5, RESERVED, V2, V1}
47 DCHECK_NE(version, 1);
48 DCHECK_LT(sr_idx, kMpeg1SampleRateTableSize);
49 return kMpeg1SampleRateTable[sr_idx][sr_version_indexes[version]];
50}
51
52const uint32_t kMpeg1BitrateTable[][5] = {
53 // clang-format off
54 // V1:L1, V1:L2, V1:L3, V2:L1, V2&V2.5:L2&L3
55 { 0, 0, 0, 0, 0},
56 { 32, 32, 32, 32, 8},
57 { 64, 48, 40, 48, 16},
58 { 96, 56, 48, 56, 24},
59 { 128, 64, 56, 64, 32},
60 { 160, 80, 64, 80, 40},
61 { 192, 96, 80, 96, 48},
62 { 224, 112, 96, 112, 56},
63 { 256, 128, 112, 128, 64},
64 { 288, 160, 128, 144, 80},
65 { 320, 192, 160, 160, 96},
66 { 352, 224, 192, 176, 112},
67 { 384, 256, 224, 192, 128},
68 { 416, 320, 256, 224, 144},
69 { 448, 384, 320, 256, 160}};
70// clang-format on
71const size_t kMpeg1BitrateTableSize = std::size(kMpeg1BitrateTable);
72
73static inline uint32_t Mpeg1BitRate(uint8_t btr_idx,
74 uint8_t version,
75 uint8_t layer) {
76 static int btr_version_indexes[] = {1, -1, 1, 0}; // {V2.5, RESERVED, V2, V1}
77 static int btr_layer_indexes[] = {-1, 2, 1, 0}; // {RESERVED, L3, L2, L1}
78
79 DCHECK_NE(version, 1);
80 DCHECK_NE(layer, 0);
81 int vidx = btr_version_indexes[version];
82 int lidx = btr_layer_indexes[layer];
83 if (vidx == 1 && lidx > 1)
84 lidx = 1;
85
86 DCHECK_LT(vidx * 3 + lidx, 5);
87 DCHECK_LT(btr_idx, kMpeg1BitrateTableSize);
88 return kMpeg1BitrateTable[btr_idx][vidx * 3 + lidx] * 1000;
89}
90
91static inline size_t Mpeg1FrameSize(uint8_t layer,
92 uint32_t bitrate,
93 uint32_t sample_rate,
94 uint8_t padded) {
95 DCHECK_GT(sample_rate, static_cast<uint32_t>(0));
96 if (layer == kMpeg1L_1)
97 return (12 * bitrate / sample_rate + padded) * 4;
98 return 144 * bitrate / sample_rate + padded;
99}
100
101} // namespace
102
103namespace shaka {
104namespace media {
105namespace mp2t {
106
107bool Mpeg1Header::IsSyncWord(const uint8_t* buf) const {
108 return (buf[0] == 0xff) &&
109 ((buf[1] & 0b11100000) == 0b11100000)
110 // Version 01 is reserved
111 && ((buf[1] & 0b00011000) != 0b00001000)
112 // Layer 00 is reserved
113 && ((buf[1] & 0b00000110) != 0b00000000);
114}
115
117 return kMpeg1HeaderMinSize + 1;
118}
119
121 static int spf_layer_indexes[] = {-1, 2, 1, 0}; // {RESERVED, L3, L2, L1}
122 DCHECK_NE(layer_, 0);
123 return kMpeg1SamplesPerFrameTable[spf_layer_indexes[layer_]];
124}
125
126bool Mpeg1Header::Parse(const uint8_t* mpeg1_frame, size_t mpeg1_frame_size) {
127 DCHECK(mpeg1_frame);
128
129 if (mpeg1_frame_size < kMpeg1HeaderMinSize)
130 return false;
131
132 BitReader frame(mpeg1_frame, mpeg1_frame_size);
133 // Verify frame starts with sync bits (0x7ff).
134 uint32_t sync;
135 RCHECK(frame.ReadBits(11, &sync));
136 RCHECK(sync == 0x7ff);
137 // MPEG version and layer.
138 RCHECK(frame.ReadBits(2, &version_));
139 RCHECK(version_ != kMpeg1V_INV);
140 RCHECK(frame.ReadBits(2, &layer_));
141 RCHECK(layer_ != kMpeg1L_INV);
142 RCHECK(frame.ReadBits(1, &protection_absent_));
143
144 uint8_t btr_idx;
145 RCHECK(frame.ReadBits(4, &btr_idx));
146 RCHECK(btr_idx > 0);
147 bitrate_ = Mpeg1BitRate(btr_idx, version_, layer_);
148
149 uint8_t sr_idx;
150 RCHECK(frame.ReadBits(2, &sr_idx));
151 RCHECK(sr_idx < 0b11);
152 sample_rate_ = Mpeg1SampleRate(sr_idx, version_);
153
154 RCHECK(frame.ReadBits(1, &padded_));
155 // Skip private stream bit.
156 RCHECK(frame.SkipBits(1));
157
158 RCHECK(frame.ReadBits(2, &channel_mode_));
159 // Skip Mode extension
160 RCHECK(frame.SkipBits(2));
161 // Skip copyright, origination and emphasis info.
162 RCHECK(frame.SkipBits(4));
163
164 return true;
165}
166
168 // Unlike ADTS, for MP3, the whole frame is included in the media sample, so
169 // return 0 header size.
170 return 0;
171}
172
174 return Mpeg1FrameSize(layer_, bitrate_, sample_rate_, padded_);
175}
176
178 size_t num_bytes) const {
179 DCHECK_GT(num_bytes, static_cast<size_t>(2));
180 uint8_t version = (data[1] & 0b00011000) >> 3;
181 uint8_t layer = (data[1] & 0b00000110) >> 1;
182 uint8_t btr_idx = (data[2] & 0b11110000) >> 4;
183 uint8_t sr_idx = (data[2] & 0b00001100) >> 2;
184 uint8_t padded = (data[2] & 0b00000010) >> 1;
185
186 if ((version == kMpeg1V_INV) || (layer == kMpeg1L_INV) || (btr_idx == 0) ||
187 (sr_idx == 0b11))
188 return 0;
189
190 uint32_t bitrate = Mpeg1BitRate(btr_idx, version, layer);
191 uint32_t samplerate = Mpeg1SampleRate(sr_idx, version);
192 return Mpeg1FrameSize(layer, bitrate, samplerate, padded);
193}
194
195void Mpeg1Header::GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const {
196 // The following conversion table is extracted from ISO 14496 Part 3 -
197 // Table 1.16 - Sampling Frequency Index.
198 static const size_t kConfigFrequencyTable[] = {
199 96000, 88200, 64000, 48000, 44100, 32000, 24000,
200 22050, 16000, 12000, 11025, 8000, 7350};
201 static const size_t kConfigFrequencyTableSize =
202 std::size(kConfigFrequencyTable);
203 uint8_t cft_idx;
204
205 for (cft_idx = 0; cft_idx < kConfigFrequencyTableSize; cft_idx++)
206 if (sample_rate_ == kConfigFrequencyTable[cft_idx])
207 break;
208
209 DCHECK(buffer);
210 buffer->clear();
211 BitWriter config(buffer);
212
213 // ISO/IEC 14496:3 Table 1.16 Syntax of GetAudioObjetType()
214 auto object_type = GetObjectType();
215 if (object_type <= 31) {
216 config.WriteBits(object_type, 5);
217 } else {
218 config.WriteBits(31, 5);
219 config.WriteBits(object_type - 32, 6);
220 }
221
222 config.WriteBits(cft_idx, 4);
223 /*
224 * NOTE: Number of channels matches channel_configuration index,
225 * since mpeg1 audio has only 1 or 2 channels
226 */
227 config.WriteBits(GetNumChannels(), 4);
228 config.Flush();
229}
230
232 /*
233 * ISO14496-3:2009 Table 1.17 - Audio Object Types
234 */
235 if (layer_ == kMpeg1L_1)
236 return 32;
237 if (layer_ == kMpeg1L_2)
238 return 33;
239
240 DCHECK_EQ(layer_, kMpeg1L_3);
241 return 34;
242}
243
245 return sample_rate_;
246}
247
249 if (channel_mode_ == 0b11)
250 return 1;
251 return 2;
252}
253
254} // namespace mp2t
255} // namespace media
256} // namespace shaka
A class to read bit streams.
Definition bit_reader.h:19
bool SkipBits(size_t num_bits)
Definition bit_reader.cc:28
bool ReadBits(size_t num_bits, T *out)
Definition bit_reader.h:37
void Flush()
Write pending bits, and align bitstream with extra zero bits.
Definition bit_writer.cc:37
void WriteBits(uint32_t bits, size_t number_of_bits)
Definition bit_writer.cc:21
size_t GetMinFrameSize() const override
size_t GetFrameSize() const override
void GetAudioSpecificConfig(std::vector< uint8_t > *buffer) const override
size_t GetFrameSizeWithoutParsing(const uint8_t *data, size_t num_bytes) const override
bool IsSyncWord(const uint8_t *buf) const override
uint8_t GetObjectType() const override
uint8_t GetNumChannels() const override
size_t GetSamplesPerFrame() const override
uint32_t GetSamplingFrequency() const override
bool Parse(const uint8_t *mpeg1_frame, size_t mpeg1_frame_size) override
size_t GetHeaderSize() const override
All the methods that are virtual are virtual for mocking.