Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef MP3_FRAME_PARSER_H_
6 : #define MP3_FRAME_PARSER_H_
7 :
8 : #include <vector>
9 :
10 : #include "mozilla/Maybe.h"
11 : #include "mp4_demuxer/ByteReader.h"
12 :
13 : namespace mozilla {
14 :
15 : // ID3 header parser state machine used by FrameParser.
16 : // The header contains the following format (one byte per term):
17 : // 'I' 'D' '3' MajorVersion MinorVersion Flags Size1 Size2 Size3 Size4
18 : // For more details see http://id3.org/id3v2.3.0.
19 0 : class ID3Parser
20 : {
21 : public:
22 : // Holds the ID3 header and its parsing state.
23 : class ID3Header
24 : {
25 : public:
26 : // The header size is static, see class comment.
27 : static const int SIZE = 10;
28 :
29 : // Constructor.
30 : ID3Header();
31 :
32 : // Resets the state to allow for a new parsing session.
33 : void Reset();
34 :
35 : // The ID3 tags are versioned like this: ID3vMajorVersion.MinorVersion.
36 : uint8_t MajorVersion() const;
37 : uint8_t MinorVersion() const;
38 :
39 : // The ID3 flags field.
40 : uint8_t Flags() const;
41 :
42 : // The derived size based on the provided size fields.
43 : uint32_t Size() const;
44 :
45 : // Returns the size of an ID3v2.4 footer if present and zero otherwise.
46 : uint8_t FooterSize() const;
47 :
48 : // The total size of the ID3 tag including header/footer, or zero if
49 : // none has been found.
50 : uint32_t TotalTagSize() const;
51 :
52 : // Returns whether the parsed data is a valid ID3 header up to the given
53 : // byte position.
54 : bool IsValid(int aPos) const;
55 :
56 : // Returns whether the parsed data is a complete and valid ID3 header.
57 : bool IsValid() const;
58 :
59 : // Parses the next provided byte.
60 : // Returns whether the byte creates a valid sequence up to this point.
61 : bool ParseNext(uint8_t c);
62 :
63 : private:
64 : // Updates the parser state machine with the provided next byte.
65 : // Returns whether the provided byte is a valid next byte in the sequence.
66 : bool Update(uint8_t c);
67 :
68 : // The currently parsed byte sequence.
69 : uint8_t mRaw[SIZE];
70 :
71 : // The derived size as provided by the size fields.
72 : // The header size fields holds a 4 byte sequence with each MSB set to 0,
73 : // this bits need to be ignored when deriving the actual size.
74 : uint32_t mSize;
75 :
76 : // The current byte position in the parsed sequence. Reset via Reset and
77 : // incremented via Update.
78 : int mPos;
79 : };
80 :
81 : // Returns the parsed ID3 header. Note: check for validity.
82 : const ID3Header& Header() const;
83 :
84 : // Parses contents of given ByteReader for a valid ID3v2 header.
85 : // Returns the total ID3v2 tag size if successful and zero otherwise.
86 : uint32_t Parse(mp4_demuxer::ByteReader* aReader);
87 :
88 : // Resets the state to allow for a new parsing session.
89 : void Reset();
90 :
91 : private:
92 : // The currently parsed ID3 header. Reset via Reset, updated via Parse.
93 : ID3Header mHeader;
94 : };
95 :
96 : // MPEG audio frame parser.
97 : // The MPEG frame header has the following format (one bit per character):
98 : // 11111111 111VVLLC BBBBSSPR MMEETOHH
99 : // { sync } - 11 sync bits
100 : // VV - MPEG audio version ID (0->2.5, 1->reserved, 2->2, 3->1)
101 : // LL - Layer description (0->reserved, 1->III, 2->II, 3->I)
102 : // C - CRC protection bit (0->protected, 1->not protected)
103 : // BBBB - Bitrate index (see table in implementation)
104 : // SS - Sampling rate index (see table in implementation)
105 : // P - Padding bit (0->not padded, 1->padded by 1 slot size)
106 : // R - Private bit (ignored)
107 : // MM - Channel mode (0->stereo, 1->joint stereo, 2->dual channel,
108 : // 3->single channel)
109 : // EE - Mode extension for joint stereo (ignored)
110 : // T - Copyright (0->disabled, 1->enabled)
111 : // O - Original (0->copy, 1->original)
112 : // HH - Emphasis (0->none, 1->50/15 ms, 2->reserved, 3->CCIT J.17)
113 0 : class FrameParser
114 : {
115 : public:
116 : // Holds the frame header and its parsing state.
117 : class FrameHeader
118 : {
119 : public:
120 : // The header size is static, see class comments.
121 : static const int SIZE = 4;
122 :
123 : // Constructor.
124 : FrameHeader();
125 :
126 : // Raw field access, see class comments for details.
127 : uint8_t Sync1() const;
128 : uint8_t Sync2() const;
129 : uint8_t RawVersion() const;
130 : uint8_t RawLayer() const;
131 : uint8_t RawProtection() const;
132 : uint8_t RawBitrate() const;
133 : uint8_t RawSampleRate() const;
134 : uint8_t Padding() const;
135 : uint8_t Private() const;
136 : uint8_t RawChannelMode() const;
137 :
138 : // Sampling rate frequency in Hz.
139 : int32_t SampleRate() const;
140 :
141 : // Number of audio channels.
142 : int32_t Channels() const;
143 :
144 : // Samples per frames, static depending on MPEG version and layer.
145 : int32_t SamplesPerFrame() const;
146 :
147 : // Slot size used for padding, static depending on MPEG layer.
148 : int32_t SlotSize() const;
149 :
150 : // Bitrate in kbps, can vary between frames.
151 : int32_t Bitrate() const;
152 :
153 : // MPEG layer (0->invalid, 1->I, 2->II, 3->III).
154 : int32_t Layer() const;
155 :
156 : // Returns whether the parsed data is a valid frame header up to the given
157 : // byte position.
158 : bool IsValid(const int aPos) const;
159 :
160 : // Returns whether the parsed data is a complete and valid frame header.
161 : bool IsValid() const;
162 :
163 : // Resets the state to allow for a new parsing session.
164 : void Reset();
165 :
166 : // Parses the next provided byte.
167 : // Returns whether the byte creates a valid sequence up to this point.
168 : bool ParseNext(const uint8_t c);
169 :
170 : private:
171 : // Updates the parser state machine with the provided next byte.
172 : // Returns whether the provided byte is a valid next byte in the sequence.
173 : bool Update(const uint8_t c);
174 :
175 : // The currently parsed byte sequence.
176 : uint8_t mRaw[SIZE];
177 :
178 : // The current byte position in the parsed sequence. Reset via Reset and
179 : // incremented via Update.
180 : int mPos;
181 : };
182 :
183 : // VBR frames may contain Xing or VBRI headers for additional info, we use
184 : // this class to parse them and access this info.
185 0 : class VBRHeader
186 : {
187 : public:
188 : // Synchronize with vbr_header TYPE_STR on change.
189 : enum VBRHeaderType
190 : {
191 : NONE = 0,
192 : XING,
193 : VBRI
194 : };
195 :
196 : // Constructor.
197 : VBRHeader();
198 :
199 : // Returns the parsed VBR header type, or NONE if no valid header found.
200 : VBRHeaderType Type() const;
201 :
202 : // Returns the total number of audio frames (excluding the VBR header frame)
203 : // expected in the stream/file.
204 : const Maybe<uint32_t>& NumAudioFrames() const;
205 :
206 : // Returns the expected size of the stream.
207 : const Maybe<uint32_t>& NumBytes() const;
208 :
209 : // Returns the VBR scale factor (0: best quality, 100: lowest quality).
210 : const Maybe<uint32_t>& Scale() const;
211 :
212 : // Returns true iff Xing/Info TOC (table of contents) is present.
213 : bool IsTOCPresent() const;
214 :
215 : // Returns whether the header is valid (type XING or VBRI).
216 : bool IsValid() const;
217 :
218 : // Returns whether the header is valid and contains reasonable non-zero
219 : // field values.
220 : bool IsComplete() const;
221 :
222 : // Returns the byte offset for the given duration percentage as a factor
223 : // (0: begin, 1.0: end).
224 : int64_t Offset(float aDurationFac) const;
225 :
226 : // Parses contents of given ByteReader for a valid VBR header.
227 : // The offset of the passed ByteReader needs to point to an MPEG frame
228 : // begin, as a VBRI-style header is searched at a fixed offset relative to
229 : // frame begin. Returns whether a valid VBR header was found in the range.
230 : bool Parse(mp4_demuxer::ByteReader* aReader);
231 :
232 : private:
233 : // Parses contents of given ByteReader for a valid Xing header.
234 : // The initial ByteReader offset will be preserved.
235 : // Returns whether a valid Xing header was found in the range.
236 : bool ParseXing(mp4_demuxer::ByteReader* aReader);
237 :
238 : // Parses contents of given ByteReader for a valid VBRI header.
239 : // The initial ByteReader offset will be preserved. It also needs to point
240 : // to the beginning of a valid MPEG frame, as VBRI headers are searched
241 : // at a fixed offset relative to frame begin.
242 : // Returns whether a valid VBRI header was found in the range.
243 : bool ParseVBRI(mp4_demuxer::ByteReader* aReader);
244 :
245 : // The total number of frames expected as parsed from a VBR header.
246 : Maybe<uint32_t> mNumAudioFrames;
247 :
248 : // The total number of bytes expected in the stream.
249 : Maybe<uint32_t> mNumBytes;
250 :
251 : // The VBR scale factor.
252 : Maybe<uint32_t> mScale;
253 :
254 : // The TOC table mapping duration percentage to byte offset.
255 : std::vector<int64_t> mTOC;
256 :
257 : // The detected VBR header type.
258 : VBRHeaderType mType;
259 : };
260 :
261 : // Frame meta container used to parse and hold a frame header and side info.
262 0 : class Frame
263 : {
264 : public:
265 : // Returns the length of the frame excluding the header in bytes.
266 : int32_t Length() const;
267 :
268 : // Returns the parsed frame header.
269 : const FrameHeader& Header() const;
270 :
271 : // Resets the frame header and data.
272 : void Reset();
273 :
274 : // Parses the next provided byte.
275 : // Returns whether the byte creates a valid sequence up to this point.
276 : bool ParseNext(uint8_t c);
277 :
278 : private:
279 : // The currently parsed frame header.
280 : FrameHeader mHeader;
281 : };
282 :
283 : // Constructor.
284 : FrameParser();
285 :
286 : // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
287 : const Frame& CurrentFrame() const;
288 :
289 : // Returns the previously parsed frame. Reset via Reset.
290 : const Frame& PrevFrame() const;
291 :
292 : // Returns the first parsed frame. Reset via Reset.
293 : const Frame& FirstFrame() const;
294 :
295 : // Returns the parsed ID3 header. Note: check for validity.
296 : const ID3Parser::ID3Header& ID3Header() const;
297 :
298 : // Returns the parsed VBR header info. Note: check for validity by type.
299 : const VBRHeader& VBRInfo() const;
300 :
301 : // Resets the parser.
302 : void Reset();
303 :
304 : // Resets all frame data, but not the ID3Header.
305 : // Don't use between frames as first frame data is reset.
306 : void ResetFrameData();
307 :
308 : // Clear the last parsed frame to allow for next frame parsing, i.e.:
309 : // - sets PrevFrame to CurrentFrame
310 : // - resets the CurrentFrame
311 : // - resets ID3Header if no valid header was parsed yet
312 : void EndFrameSession();
313 :
314 : // Parses contents of given ByteReader for a valid frame header and returns
315 : // true if one was found. After returning, the variable passed to
316 : // 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
317 : // jump across a large ID3v2 tag spanning multiple buffers.
318 : bool Parse(mp4_demuxer::ByteReader* aReader, uint32_t* aBytesToSkip);
319 :
320 : // Parses contents of given ByteReader for a valid VBR header.
321 : // The offset of the passed ByteReader needs to point to an MPEG frame begin,
322 : // as a VBRI-style header is searched at a fixed offset relative to frame
323 : // begin. Returns whether a valid VBR header was found.
324 : bool ParseVBRHeader(mp4_demuxer::ByteReader* aReader);
325 :
326 : private:
327 : // ID3 header parser.
328 : ID3Parser mID3Parser;
329 :
330 : // VBR header parser.
331 : VBRHeader mVBRHeader;
332 :
333 : // We keep the first parsed frame around for static info access, the
334 : // previously parsed frame for debugging and the currently parsed frame.
335 : Frame mFirstFrame;
336 : Frame mFrame;
337 : Frame mPrevFrame;
338 : };
339 :
340 : } // namespace mozilla
341 :
342 : #endif
|