LCOV - code coverage report
Current view: top level - dom/media/mp3 - MP3FrameParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 270 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 64 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "MP3FrameParser.h"
       8             : 
       9             : #include <algorithm>
      10             : #include <inttypes.h>
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/EndianUtils.h"
      14             : #include "mozilla/SizePrintfMacros.h"
      15             : #include "VideoUtils.h"
      16             : 
      17             : extern mozilla::LazyLogModule gMediaDemuxerLog;
      18             : #define MP3LOG(msg, ...) \
      19             :   MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("MP3Demuxer " msg, ##__VA_ARGS__))
      20             : #define MP3LOGV(msg, ...) \
      21             :   MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("MP3Demuxer " msg, ##__VA_ARGS__))
      22             : 
      23             : using mp4_demuxer::ByteReader;
      24             : 
      25             : namespace mozilla {
      26             : 
      27             : // FrameParser
      28             : 
      29             : namespace frame_header {
      30             : // FrameHeader mRaw byte offsets.
      31             : static const int SYNC1 = 0;
      32             : static const int SYNC2_VERSION_LAYER_PROTECTION = 1;
      33             : static const int BITRATE_SAMPLERATE_PADDING_PRIVATE = 2;
      34             : static const int CHANNELMODE_MODEEXT_COPY_ORIG_EMPH = 3;
      35             : } // namespace frame_header
      36             : 
      37           0 : FrameParser::FrameParser()
      38             : {
      39           0 : }
      40             : 
      41             : void
      42           0 : FrameParser::Reset()
      43             : {
      44           0 :   mID3Parser.Reset();
      45           0 :   mFrame.Reset();
      46           0 : }
      47             : 
      48             : void
      49           0 : FrameParser::ResetFrameData()
      50             : {
      51           0 :   mFrame.Reset();
      52           0 :   mFirstFrame.Reset();
      53           0 :   mPrevFrame.Reset();
      54           0 : }
      55             : 
      56             : void
      57           0 : FrameParser::EndFrameSession()
      58             : {
      59           0 :   if (!mID3Parser.Header().IsValid()) {
      60             :     // Reset ID3 tags only if we have not parsed a valid ID3 header yet.
      61           0 :     mID3Parser.Reset();
      62             :   }
      63           0 :   mPrevFrame = mFrame;
      64           0 :   mFrame.Reset();
      65           0 : }
      66             : 
      67             : const FrameParser::Frame&
      68           0 : FrameParser::CurrentFrame() const
      69             : {
      70           0 :   return mFrame;
      71             : }
      72             : 
      73             : const FrameParser::Frame&
      74           0 : FrameParser::PrevFrame() const
      75             : {
      76           0 :   return mPrevFrame;
      77             : }
      78             : 
      79             : const FrameParser::Frame&
      80           0 : FrameParser::FirstFrame() const
      81             : {
      82           0 :   return mFirstFrame;
      83             : }
      84             : 
      85             : const ID3Parser::ID3Header&
      86           0 : FrameParser::ID3Header() const
      87             : {
      88           0 :   return mID3Parser.Header();
      89             : }
      90             : 
      91             : const FrameParser::VBRHeader&
      92           0 : FrameParser::VBRInfo() const
      93             : {
      94           0 :   return mVBRHeader;
      95             : }
      96             : 
      97             : bool
      98           0 : FrameParser::Parse(ByteReader* aReader, uint32_t* aBytesToSkip)
      99             : {
     100           0 :   MOZ_ASSERT(aReader && aBytesToSkip);
     101           0 :   *aBytesToSkip = 0;
     102             : 
     103           0 :   if (!mID3Parser.Header().Size() && !mFirstFrame.Length()) {
     104             :     // No MP3 frames have been parsed yet, look for ID3v2 headers at file begin.
     105             :     // ID3v1 tags may only be at file end.
     106             :     // TODO: should we try to read ID3 tags at end of file/mid-stream, too?
     107           0 :     const size_t prevReaderOffset = aReader->Offset();
     108           0 :     const uint32_t tagSize = mID3Parser.Parse(aReader);
     109           0 :     if (tagSize) {
     110             :       // ID3 tag found, skip past it.
     111           0 :       const uint32_t skipSize = tagSize - ID3Parser::ID3Header::SIZE;
     112             : 
     113           0 :       if (skipSize > aReader->Remaining()) {
     114             :         // Skipping across the ID3v2 tag would take us past the end of the
     115             :         // buffer, therefore we return immediately and let the calling function
     116             :         // handle skipping the rest of the tag.
     117           0 :         MP3LOGV("ID3v2 tag detected, size=%d,"
     118             :                 " needing to skip %" PRIuSIZE " bytes past the current buffer",
     119             :                 tagSize, skipSize - aReader->Remaining());
     120           0 :         *aBytesToSkip = skipSize - aReader->Remaining();
     121           0 :         return false;
     122             :       }
     123           0 :       MP3LOGV("ID3v2 tag detected, size=%d", tagSize);
     124           0 :       aReader->Read(skipSize);
     125             :     } else {
     126             :       // No ID3v2 tag found, rewinding reader in order to search for a MPEG
     127             :       // frame header.
     128           0 :       aReader->Seek(prevReaderOffset);
     129             :     }
     130             :   }
     131             : 
     132           0 :   while (aReader->CanRead8() && !mFrame.ParseNext(aReader->ReadU8())) { }
     133             : 
     134           0 :   if (mFrame.Length()) {
     135             :     // MP3 frame found.
     136           0 :     if (!mFirstFrame.Length()) {
     137           0 :       mFirstFrame = mFrame;
     138             :     }
     139             :     // Indicate success.
     140           0 :     return true;
     141             :   }
     142           0 :   return false;
     143             : }
     144             : 
     145             : // FrameParser::Header
     146             : 
     147           0 : FrameParser::FrameHeader::FrameHeader()
     148             : {
     149           0 :   Reset();
     150           0 : }
     151             : 
     152             : uint8_t
     153           0 : FrameParser::FrameHeader::Sync1() const
     154             : {
     155           0 :   return mRaw[frame_header::SYNC1];
     156             : }
     157             : 
     158             : uint8_t
     159           0 : FrameParser::FrameHeader::Sync2() const
     160             : {
     161           0 :   return 0x7 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 5;
     162             : }
     163             : 
     164             : uint8_t
     165           0 : FrameParser::FrameHeader::RawVersion() const
     166             : {
     167           0 :   return 0x3 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 3;
     168             : }
     169             : 
     170             : uint8_t
     171           0 : FrameParser::FrameHeader::RawLayer() const
     172             : {
     173           0 :   return 0x3 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 1;
     174             : }
     175             : 
     176             : uint8_t
     177           0 : FrameParser::FrameHeader::RawProtection() const
     178             : {
     179           0 :   return 0x1 & mRaw[frame_header::SYNC2_VERSION_LAYER_PROTECTION] >> 6;
     180             : }
     181             : 
     182             : uint8_t
     183           0 : FrameParser::FrameHeader::RawBitrate() const
     184             : {
     185           0 :   return 0xF & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 4;
     186             : }
     187             : 
     188             : uint8_t
     189           0 : FrameParser::FrameHeader::RawSampleRate() const
     190             : {
     191           0 :   return 0x3 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 2;
     192             : }
     193             : 
     194             : uint8_t
     195           0 : FrameParser::FrameHeader::Padding() const
     196             : {
     197           0 :   return 0x1 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE] >> 1;
     198             : }
     199             : 
     200             : uint8_t
     201           0 : FrameParser::FrameHeader::Private() const
     202             : {
     203           0 :   return 0x1 & mRaw[frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE];
     204             : }
     205             : 
     206             : uint8_t
     207           0 : FrameParser::FrameHeader::RawChannelMode() const
     208             : {
     209           0 :   return 0x3 & mRaw[frame_header::CHANNELMODE_MODEEXT_COPY_ORIG_EMPH] >> 6;
     210             : }
     211             : 
     212             : int32_t
     213           0 : FrameParser::FrameHeader::Layer() const
     214             : {
     215             :   static const uint8_t LAYERS[4] = { 0, 3, 2, 1 };
     216             : 
     217           0 :   return LAYERS[RawLayer()];
     218             : }
     219             : 
     220             : int32_t
     221           0 : FrameParser::FrameHeader::SampleRate() const
     222             : {
     223             :   // Sample rates - use [version][srate]
     224             :   static const uint16_t SAMPLE_RATE[4][4] = {
     225             :     { 11025, 12000,  8000, 0 }, // MPEG 2.5
     226             :     {     0,     0,     0, 0 }, // Reserved
     227             :     { 22050, 24000, 16000, 0 }, // MPEG 2
     228             :     { 44100, 48000, 32000, 0 }  // MPEG 1
     229             :   };
     230             : 
     231           0 :   return SAMPLE_RATE[RawVersion()][RawSampleRate()];
     232             : }
     233             : 
     234             : int32_t
     235           0 : FrameParser::FrameHeader::Channels() const
     236             : {
     237             :   // 3 is single channel (mono), any other value is some variant of dual
     238             :   // channel.
     239           0 :   return RawChannelMode() == 3 ? 1 : 2;
     240             : }
     241             : 
     242             : int32_t
     243           0 : FrameParser::FrameHeader::SamplesPerFrame() const
     244             : {
     245             :   // Samples per frame - use [version][layer]
     246             :   static const uint16_t FRAME_SAMPLE[4][4] = {
     247             :     // Layer     3     2     1       Version
     248             :     {      0,  576, 1152,  384 }, // 2.5
     249             :     {      0,    0,    0,    0 }, // Reserved
     250             :     {      0,  576, 1152,  384 }, // 2
     251             :     {      0, 1152, 1152,  384 }  // 1
     252             :   };
     253             : 
     254           0 :   return FRAME_SAMPLE[RawVersion()][RawLayer()];
     255             : }
     256             : 
     257             : int32_t
     258           0 : FrameParser::FrameHeader::Bitrate() const
     259             : {
     260             :   // Bitrates - use [version][layer][bitrate]
     261             :   static const uint16_t BITRATE[4][4][16] = {
     262             :     { // Version 2.5
     263             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Reserved
     264             :       { 0,   8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, // Layer 3
     265             :       { 0,   8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, // Layer 2
     266             :       { 0,  32,  48,  56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }  // Layer 1
     267             :     },
     268             :     { // Reserved
     269             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Invalid
     270             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Invalid
     271             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Invalid
     272             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }  // Invalid
     273             :     },
     274             :     { // Version 2
     275             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Reserved
     276             :       { 0,   8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, // Layer 3
     277             :       { 0,   8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, // Layer 2
     278             :       { 0,  32,  48,  56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }  // Layer 1
     279             :     },
     280             :     { // Version 1
     281             :       { 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 }, // Reserved
     282             :       { 0,  32,  40,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0 }, // Layer 3
     283             :       { 0,  32,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // Layer 2
     284             :       { 0,  32,  64,  96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // Layer 1
     285             :     }
     286             :   };
     287             : 
     288           0 :   return 1000 * BITRATE[RawVersion()][RawLayer()][RawBitrate()];
     289             : }
     290             : 
     291             : int32_t
     292           0 : FrameParser::FrameHeader::SlotSize() const
     293             : {
     294             :   // Slot size (MPEG unit of measurement) - use [layer]
     295             :   static const uint8_t SLOT_SIZE[4] = { 0, 1, 1, 4 }; // Rsvd, 3, 2, 1
     296             : 
     297           0 :   return SLOT_SIZE[RawLayer()];
     298             : }
     299             : 
     300             : bool
     301           0 : FrameParser::FrameHeader::ParseNext(uint8_t c)
     302             : {
     303           0 :   if (!Update(c)) {
     304           0 :     Reset();
     305           0 :     if (!Update(c)) {
     306           0 :       Reset();
     307             :     }
     308             :   }
     309           0 :   return IsValid();
     310             : }
     311             : 
     312             : bool
     313           0 : FrameParser::FrameHeader::IsValid(int aPos) const
     314             : {
     315           0 :   if (aPos >= SIZE) {
     316           0 :     return true;
     317             :   }
     318           0 :   if (aPos == frame_header::SYNC1) {
     319           0 :     return Sync1() == 0xFF;
     320             :   }
     321           0 :   if (aPos == frame_header::SYNC2_VERSION_LAYER_PROTECTION) {
     322           0 :     return Sync2() == 7 &&
     323           0 :            RawVersion() != 1 &&
     324           0 :            Layer() == 3;
     325             :   }
     326           0 :   if (aPos == frame_header::BITRATE_SAMPLERATE_PADDING_PRIVATE) {
     327           0 :     return RawBitrate() != 0xF && RawBitrate() != 0 &&
     328           0 :            RawSampleRate() != 3;
     329             :   }
     330           0 :   return true;
     331             : }
     332             : 
     333             : bool
     334           0 : FrameParser::FrameHeader::IsValid() const
     335             : {
     336           0 :   return mPos >= SIZE;
     337             : }
     338             : 
     339             : void
     340           0 : FrameParser::FrameHeader::Reset()
     341             : {
     342           0 :   mPos = 0;
     343           0 : }
     344             : 
     345             : bool
     346           0 : FrameParser::FrameHeader::Update(uint8_t c)
     347             : {
     348           0 :   if (mPos < SIZE) {
     349           0 :     mRaw[mPos] = c;
     350             :   }
     351           0 :   return IsValid(mPos++);
     352             : }
     353             : 
     354             : // FrameParser::VBRHeader
     355             : 
     356             : namespace vbr_header {
     357             : static const char* TYPE_STR[3] = {"NONE", "XING", "VBRI"};
     358             : static const uint32_t TOC_SIZE = 100;
     359             : } // namespace vbr_header
     360             : 
     361           0 : FrameParser::VBRHeader::VBRHeader()
     362           0 :   : mType(NONE)
     363             : {
     364           0 : }
     365             : 
     366             : FrameParser::VBRHeader::VBRHeaderType
     367           0 : FrameParser::VBRHeader::Type() const
     368             : {
     369           0 :   return mType;
     370             : }
     371             : 
     372             : const Maybe<uint32_t>&
     373           0 : FrameParser::VBRHeader::NumAudioFrames() const
     374             : {
     375           0 :   return mNumAudioFrames;
     376             : }
     377             : 
     378             : const Maybe<uint32_t>&
     379           0 : FrameParser::VBRHeader::NumBytes() const
     380             : {
     381           0 :   return mNumBytes;
     382             : }
     383             : 
     384             : const Maybe<uint32_t>&
     385           0 : FrameParser::VBRHeader::Scale() const
     386             : {
     387           0 :   return mScale;
     388             : }
     389             : 
     390             : bool
     391           0 : FrameParser::VBRHeader::IsTOCPresent() const
     392             : {
     393           0 :   return mTOC.size() == vbr_header::TOC_SIZE;
     394             : }
     395             : 
     396             : bool
     397           0 : FrameParser::VBRHeader::IsValid() const
     398             : {
     399           0 :   return mType != NONE;
     400             : }
     401             : 
     402             : bool
     403           0 : FrameParser::VBRHeader::IsComplete() const
     404             : {
     405           0 :   return IsValid()
     406           0 :          && mNumAudioFrames.valueOr(0) > 0
     407           0 :          && mNumBytes.valueOr(0) > 0
     408             :          // We don't care about the scale for any computations here.
     409             :          // && mScale < 101
     410           0 :          && true;
     411             : }
     412             : 
     413             : int64_t
     414           0 : FrameParser::VBRHeader::Offset(float aDurationFac) const
     415             : {
     416           0 :   if (!IsTOCPresent()) {
     417           0 :     return -1;
     418             :   }
     419             : 
     420             :   // Constrain the duration percentage to [0, 99].
     421             :   const float durationPer =
     422           0 :     100.0f * std::min(0.99f, std::max(0.0f, aDurationFac));
     423           0 :   const size_t fullPer = durationPer;
     424           0 :   const float rest = durationPer - fullPer;
     425             : 
     426           0 :   MOZ_ASSERT(fullPer < mTOC.size());
     427           0 :   int64_t offset = mTOC.at(fullPer);
     428             : 
     429           0 :   if (rest > 0.0 && fullPer + 1 < mTOC.size()) {
     430           0 :     offset += rest * (mTOC.at(fullPer + 1) - offset);
     431             :   }
     432             : 
     433           0 :   return offset;
     434             : }
     435             : 
     436             : bool
     437           0 : FrameParser::VBRHeader::ParseXing(ByteReader* aReader)
     438             : {
     439           0 :   static const uint32_t XING_TAG = BigEndian::readUint32("Xing");
     440           0 :   static const uint32_t INFO_TAG = BigEndian::readUint32("Info");
     441             : 
     442             :   enum Flags
     443             :   {
     444             :     NUM_FRAMES = 0x01,
     445             :     NUM_BYTES = 0x02,
     446             :     TOC = 0x04,
     447             :     VBR_SCALE = 0x08
     448             :   };
     449             : 
     450           0 :   MOZ_ASSERT(aReader);
     451           0 :   const size_t prevReaderOffset = aReader->Offset();
     452             : 
     453             :   // We have to search for the Xing header as its position can change.
     454           0 :   while (aReader->CanRead32() &&
     455           0 :          aReader->PeekU32() != XING_TAG && aReader->PeekU32() != INFO_TAG) {
     456           0 :     aReader->Read(1);
     457             :   }
     458             : 
     459           0 :   if (aReader->CanRead32()) {
     460             :     // Skip across the VBR header ID tag.
     461           0 :     aReader->ReadU32();
     462           0 :     mType = XING;
     463             :   }
     464           0 :   uint32_t flags = 0;
     465           0 :   if (aReader->CanRead32()) {
     466           0 :     flags = aReader->ReadU32();
     467             :   }
     468           0 :   if (flags & NUM_FRAMES && aReader->CanRead32()) {
     469           0 :     mNumAudioFrames = Some(aReader->ReadU32());
     470             :   }
     471           0 :   if (flags & NUM_BYTES && aReader->CanRead32()) {
     472           0 :     mNumBytes = Some(aReader->ReadU32());
     473             :   }
     474           0 :   if (flags & TOC && aReader->Remaining() >= vbr_header::TOC_SIZE) {
     475           0 :     if (!mNumBytes) {
     476             :       // We don't have the stream size to calculate offsets, skip the TOC.
     477           0 :       aReader->Read(vbr_header::TOC_SIZE);
     478             :     } else {
     479           0 :       mTOC.clear();
     480           0 :       mTOC.reserve(vbr_header::TOC_SIZE);
     481           0 :       for (size_t i = 0; i < vbr_header::TOC_SIZE; ++i) {
     482           0 :         mTOC.push_back(1.0f / 256.0f * aReader->ReadU8() * mNumBytes.value());
     483             :       }
     484             :     }
     485             :   }
     486           0 :   if (flags & VBR_SCALE && aReader->CanRead32()) {
     487           0 :     mScale = Some(aReader->ReadU32());
     488             :   }
     489             : 
     490           0 :   aReader->Seek(prevReaderOffset);
     491           0 :   return mType == XING;
     492             : }
     493             : 
     494             : bool
     495           0 : FrameParser::VBRHeader::ParseVBRI(ByteReader* aReader)
     496             : {
     497           0 :   static const uint32_t TAG = BigEndian::readUint32("VBRI");
     498             :   static const uint32_t OFFSET = 32 + FrameParser::FrameHeader::SIZE;
     499             :   static const uint32_t FRAME_COUNT_OFFSET = OFFSET + 14;
     500             :   static const uint32_t MIN_FRAME_SIZE = OFFSET + 26;
     501             : 
     502           0 :   MOZ_ASSERT(aReader);
     503             :   // ParseVBRI assumes that the ByteReader offset points to the beginning of a
     504             :   // frame, therefore as a simple check, we look for the presence of a frame
     505             :   // sync at that position.
     506           0 :   MOZ_ASSERT((aReader->PeekU16() & 0xFFE0) == 0xFFE0);
     507           0 :   const size_t prevReaderOffset = aReader->Offset();
     508             : 
     509             :   // VBRI have a fixed relative position, so let's check for it there.
     510           0 :   if (aReader->Remaining() > MIN_FRAME_SIZE) {
     511           0 :     aReader->Seek(prevReaderOffset + OFFSET);
     512           0 :     if (aReader->ReadU32() == TAG) {
     513           0 :       aReader->Seek(prevReaderOffset + FRAME_COUNT_OFFSET);
     514           0 :       mNumAudioFrames = Some(aReader->ReadU32());
     515           0 :       mType = VBRI;
     516           0 :       aReader->Seek(prevReaderOffset);
     517           0 :       return true;
     518             :     }
     519             :   }
     520           0 :   aReader->Seek(prevReaderOffset);
     521           0 :   return false;
     522             : }
     523             : 
     524             : bool
     525           0 : FrameParser::VBRHeader::Parse(ByteReader* aReader)
     526             : {
     527           0 :   const bool rv = ParseVBRI(aReader) || ParseXing(aReader);
     528           0 :   if (rv) {
     529           0 :     MP3LOG("VBRHeader::Parse found valid VBR/CBR header: type=%s"
     530             :            " NumAudioFrames=%u NumBytes=%u Scale=%u TOC-size=%" PRIuSIZE,
     531             :            vbr_header::TYPE_STR[Type()], NumAudioFrames().valueOr(0),
     532             :            NumBytes().valueOr(0), Scale().valueOr(0), mTOC.size());
     533             :   }
     534           0 :   return rv;
     535             : }
     536             : 
     537             : // FrameParser::Frame
     538             : 
     539             : void
     540           0 : FrameParser::Frame::Reset()
     541             : {
     542           0 :   mHeader.Reset();
     543           0 : }
     544             : 
     545             : int32_t
     546           0 : FrameParser::Frame::Length() const
     547             : {
     548           0 :   if (!mHeader.IsValid() || !mHeader.SampleRate()) {
     549           0 :     return 0;
     550             :   }
     551             : 
     552           0 :   const float bitsPerSample = mHeader.SamplesPerFrame() / 8.0f;
     553           0 :   const int32_t frameLen = bitsPerSample * mHeader.Bitrate()
     554           0 :                            / mHeader.SampleRate()
     555           0 :                            + mHeader.Padding() * mHeader.SlotSize();
     556           0 :   return frameLen;
     557             : }
     558             : 
     559             : bool
     560           0 : FrameParser::Frame::ParseNext(uint8_t c)
     561             : {
     562           0 :   return mHeader.ParseNext(c);
     563             : }
     564             : 
     565             : const FrameParser::FrameHeader&
     566           0 : FrameParser::Frame::Header() const
     567             : {
     568           0 :   return mHeader;
     569             : }
     570             : 
     571             : bool
     572           0 : FrameParser::ParseVBRHeader(ByteReader* aReader)
     573             : {
     574           0 :   return mVBRHeader.Parse(aReader);
     575             : }
     576             : 
     577             : // ID3Parser
     578             : 
     579             : // Constants
     580             : namespace id3_header {
     581             : static const int ID_LEN = 3;
     582             : static const int VERSION_LEN = 2;
     583             : static const int FLAGS_LEN = 1;
     584             : static const int SIZE_LEN = 4;
     585             : 
     586             : static const int ID_END = ID_LEN;
     587             : static const int VERSION_END = ID_END + VERSION_LEN;
     588             : static const int FLAGS_END = VERSION_END + FLAGS_LEN;
     589             : static const int SIZE_END = FLAGS_END + SIZE_LEN;
     590             : 
     591             : static const uint8_t ID[ID_LEN] = {'I', 'D', '3'};
     592             : 
     593             : static const uint8_t MIN_MAJOR_VER = 2;
     594             : static const uint8_t MAX_MAJOR_VER = 4;
     595             : } // namespace id3_header
     596             : 
     597             : uint32_t
     598           0 : ID3Parser::Parse(ByteReader* aReader)
     599             : {
     600           0 :   MOZ_ASSERT(aReader);
     601             : 
     602           0 :   while (aReader->CanRead8() && !mHeader.ParseNext(aReader->ReadU8())) { }
     603             : 
     604           0 :   return mHeader.TotalTagSize();
     605             : }
     606             : 
     607             : void
     608           0 : ID3Parser::Reset()
     609             : {
     610           0 :   mHeader.Reset();
     611           0 : }
     612             : 
     613             : const ID3Parser::ID3Header&
     614           0 : ID3Parser::Header() const
     615             : {
     616           0 :   return mHeader;
     617             : }
     618             : 
     619             : // ID3Parser::Header
     620             : 
     621           0 : ID3Parser::ID3Header::ID3Header()
     622             : {
     623           0 :   Reset();
     624           0 : }
     625             : 
     626             : void
     627           0 : ID3Parser::ID3Header::Reset()
     628             : {
     629           0 :   mSize = 0;
     630           0 :   mPos = 0;
     631           0 : }
     632             : 
     633             : uint8_t
     634           0 : ID3Parser::ID3Header::MajorVersion() const
     635             : {
     636           0 :   return mRaw[id3_header::ID_END];
     637             : }
     638             : 
     639             : uint8_t
     640           0 : ID3Parser::ID3Header::MinorVersion() const
     641             : {
     642           0 :   return mRaw[id3_header::ID_END + 1];
     643             : }
     644             : 
     645             : uint8_t
     646           0 : ID3Parser::ID3Header::Flags() const
     647             : {
     648           0 :   return mRaw[id3_header::FLAGS_END - id3_header::FLAGS_LEN];
     649             : }
     650             : 
     651             : uint32_t
     652           0 : ID3Parser::ID3Header::Size() const
     653             : {
     654           0 :   if (!IsValid()) {
     655           0 :     return 0;
     656             :   }
     657           0 :   return mSize;
     658             : }
     659             : 
     660             : uint8_t
     661           0 : ID3Parser::ID3Header::FooterSize() const
     662             : {
     663           0 :   if (Flags() & (1 << 4)) {
     664           0 :     return SIZE;
     665             :   }
     666           0 :   return 0;
     667             : }
     668             : 
     669             : uint32_t
     670           0 : ID3Parser::ID3Header::TotalTagSize() const
     671             : {
     672           0 :   if (IsValid()) {
     673             :     // Header found, return total tag size.
     674           0 :     return ID3Header::SIZE + Size() + FooterSize();
     675             :   }
     676           0 :   return 0;
     677             : }
     678             : 
     679             : bool
     680           0 : ID3Parser::ID3Header::ParseNext(uint8_t c)
     681             : {
     682           0 :   if (!Update(c)) {
     683           0 :     Reset();
     684           0 :     if (!Update(c)) {
     685           0 :       Reset();
     686             :     }
     687             :   }
     688           0 :   return IsValid();
     689             : }
     690             : 
     691             : bool
     692           0 : ID3Parser::ID3Header::IsValid(int aPos) const
     693             : {
     694           0 :   if (aPos >= SIZE) {
     695           0 :     return true;
     696             :   }
     697           0 :   const uint8_t c = mRaw[aPos];
     698           0 :   switch (aPos) {
     699             :     case 0: case 1: case 2:
     700             :       // Expecting "ID3".
     701           0 :       return id3_header::ID[aPos] == c;
     702             :     case 3:
     703           0 :       return MajorVersion() >= id3_header::MIN_MAJOR_VER
     704           0 :              && MajorVersion() <= id3_header::MAX_MAJOR_VER;
     705             :     case 4:
     706           0 :       return MinorVersion() < 0xFF;
     707             :     case 5:
     708             :       // Validate flags for supported versions, see bug 949036.
     709           0 :       return ((0xFF >> MajorVersion()) & c) == 0;
     710             :     case 6: case 7: case 8: case 9:
     711           0 :       return c < 0x80;
     712             :   }
     713           0 :   return true;
     714             : }
     715             : 
     716             : bool
     717           0 : ID3Parser::ID3Header::IsValid() const
     718             : {
     719           0 :   return mPos >= SIZE;
     720             : }
     721             : 
     722             : bool
     723           0 : ID3Parser::ID3Header::Update(uint8_t c)
     724             : {
     725           0 :   if (mPos >= id3_header::SIZE_END - id3_header::SIZE_LEN
     726           0 :       && mPos < id3_header::SIZE_END) {
     727           0 :     mSize <<= 7;
     728           0 :     mSize |= c;
     729             :   }
     730           0 :   if (mPos < SIZE) {
     731           0 :     mRaw[mPos] = c;
     732             :   }
     733           0 :   return IsValid(mPos++);
     734             : }
     735             : 
     736             : } // namespace mozilla

Generated by: LCOV version 1.13