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