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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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 "ADTSDemuxer.h"
       8             : 
       9             : #include "TimeUnits.h"
      10             : #include "VideoUtils.h"
      11             : #include "mozilla/SizePrintfMacros.h"
      12             : #include "mozilla/UniquePtr.h"
      13             : #include <inttypes.h>
      14             : 
      15             : extern mozilla::LazyLogModule gMediaDemuxerLog;
      16             : #define ADTSLOG(msg, ...) \
      17             :   MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("ADTSDemuxer " msg, ##__VA_ARGS__))
      18             : #define ADTSLOGV(msg, ...) \
      19             :   MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("ADTSDemuxer " msg, ##__VA_ARGS__))
      20             : 
      21             : namespace mozilla {
      22             : namespace adts {
      23             : 
      24             : // adts::FrameHeader - Holds the ADTS frame header and its parsing
      25             : // state.
      26             : //
      27             : // ADTS Frame Structure
      28             : //
      29             : // 11111111 1111BCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP(QQQQQQQQ QQQQQQQQ)
      30             : //
      31             : // Header consists of 7 or 9 bytes(without or with CRC).
      32             : // Letter   Length(bits)  Description
      33             : // { sync } 12            syncword 0xFFF, all bits must be 1
      34             : // B        1             MPEG Version: 0 for MPEG-4, 1 for MPEG-2
      35             : // C        2             Layer: always 0
      36             : // D        1             protection absent, Warning, set to 1 if there is no
      37             : //                        CRC and 0 if there is CRC
      38             : // E        2             profile, the MPEG-4 Audio Object Type minus 1
      39             : // F        4             MPEG-4 Sampling Frequency Index (15 is forbidden)
      40             : // H        3             MPEG-4 Channel Configuration (in the case of 0, the
      41             : //                        channel configuration is sent via an in-band PCE)
      42             : // M        13            frame length, this value must include 7 or 9 bytes of
      43             : //                        header length: FrameLength =
      44             : //                          (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
      45             : // O        11            Buffer fullness
      46             : // P        2             Number of AAC frames(RDBs) in ADTS frame minus 1, for
      47             : //                        maximum compatibility always use 1 AAC frame per ADTS
      48             : //                        frame
      49             : // Q        16            CRC if protection absent is 0
      50             : class FrameHeader
      51             : {
      52             : public:
      53             :   uint32_t mFrameLength;
      54             :   uint32_t mSampleRate;
      55             :   uint32_t mSamples;
      56             :   uint32_t mChannels;
      57             :   uint8_t  mObjectType;
      58             :   uint8_t  mSamplingIndex;
      59             :   uint8_t  mChannelConfig;
      60             :   uint8_t  mNumAACFrames;
      61             :   bool     mHaveCrc;
      62             : 
      63             :   // Returns whether aPtr matches a valid ADTS header sync marker
      64           0 :   static bool MatchesSync(const uint8_t* aPtr)
      65             :   {
      66           0 :     return aPtr[0] == 0xFF && (aPtr[1] & 0xF6) == 0xF0;
      67             :   }
      68             : 
      69           0 :   FrameHeader() { Reset(); }
      70             : 
      71             :   // Header size
      72           0 :   size_t HeaderSize() const { return (mHaveCrc) ? 9 : 7; }
      73             : 
      74           0 :   bool IsValid() const { return mFrameLength > 0; }
      75             : 
      76             :   // Resets the state to allow for a new parsing session.
      77           0 :   void Reset() { PodZero(this); }
      78             : 
      79             :   // Returns whether the byte creates a valid sequence up to this point.
      80           0 :   bool Parse(const uint8_t* aPtr)
      81             :   {
      82           0 :     const uint8_t* p = aPtr;
      83             : 
      84           0 :     if (!MatchesSync(p)) {
      85           0 :       return false;
      86             :     }
      87             : 
      88             :     // AAC has 1024 samples per frame per channel.
      89           0 :     mSamples = 1024;
      90             : 
      91           0 :     mHaveCrc = !(p[1] & 0x01);
      92           0 :     mObjectType = ((p[2] & 0xC0) >> 6) + 1;
      93           0 :     mSamplingIndex = (p[2] & 0x3C) >> 2;
      94           0 :     mChannelConfig = (p[2] & 0x01) << 2 | (p[3] & 0xC0) >> 6;
      95           0 :     mFrameLength =
      96           0 :       (p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5;
      97           0 :     mNumAACFrames = (p[6] & 0x03) + 1;
      98             : 
      99             :     static const int32_t SAMPLE_RATES[16] = {
     100             :       96000, 88200, 64000, 48000,
     101             :       44100, 32000, 24000, 22050,
     102             :       16000, 12000, 11025,  8000,
     103             :       7350
     104             :     };
     105           0 :     mSampleRate = SAMPLE_RATES[mSamplingIndex];
     106             : 
     107           0 :     MOZ_ASSERT(mChannelConfig < 8);
     108           0 :     mChannels = (mChannelConfig == 7) ? 8 : mChannelConfig;
     109             : 
     110           0 :     return true;
     111             :   }
     112             : };
     113             : 
     114             : 
     115             : // adts::Frame - Frame meta container used to parse and hold a frame
     116             : // header and side info.
     117             : class Frame
     118             : {
     119             : public:
     120           0 :   Frame() : mOffset(0), mHeader() { }
     121             : 
     122           0 :   int64_t Offset() const { return mOffset; }
     123           0 :   size_t Length() const
     124             :   {
     125             :     // TODO: If fields are zero'd when invalid, this check wouldn't be
     126             :     // necessary.
     127           0 :     if (!mHeader.IsValid()) {
     128           0 :       return 0;
     129             :     }
     130             : 
     131           0 :     return mHeader.mFrameLength;
     132             :   }
     133             : 
     134             :   // Returns the offset to the start of frame's raw data.
     135           0 :   int64_t PayloadOffset() const { return mOffset + mHeader.HeaderSize(); }
     136             : 
     137             :   // Returns the length of the frame's raw data (excluding the header) in bytes.
     138           0 :   size_t PayloadLength() const
     139             :   {
     140             :     // TODO: If fields are zero'd when invalid, this check wouldn't be
     141             :     // necessary.
     142           0 :     if (!mHeader.IsValid()) {
     143           0 :       return 0;
     144             :     }
     145             : 
     146           0 :     return mHeader.mFrameLength - mHeader.HeaderSize();
     147             :   }
     148             : 
     149             :   // Returns the parsed frame header.
     150           0 :   const FrameHeader& Header() const { return mHeader; }
     151             : 
     152           0 :   bool IsValid() const { return mHeader.IsValid(); }
     153             : 
     154             :   // Resets the frame header and data.
     155           0 :   void Reset()
     156             :   {
     157           0 :     mHeader.Reset();
     158           0 :     mOffset = 0;
     159           0 :   }
     160             : 
     161             :   // Returns whether the valid
     162           0 :   bool Parse(int64_t aOffset, const uint8_t* aStart, const uint8_t* aEnd)
     163             :   {
     164           0 :     MOZ_ASSERT(aStart && aEnd);
     165             : 
     166           0 :     bool found = false;
     167           0 :     const uint8_t* ptr = aStart;
     168             :     // Require at least 7 bytes of data at the end of the buffer for the minimum
     169             :     // ADTS frame header.
     170           0 :     while (ptr < aEnd - 7 && !found) {
     171           0 :       found = mHeader.Parse(ptr);
     172           0 :       ptr++;
     173             :     }
     174             : 
     175           0 :     mOffset = aOffset + (ptr - aStart) - 1;
     176             : 
     177           0 :     return found;
     178             :   }
     179             : 
     180             : private:
     181             :   // The offset to the start of the header.
     182             :   int64_t mOffset;
     183             : 
     184             :   // The currently parsed frame header.
     185             :   FrameHeader mHeader;
     186             : };
     187             : 
     188             : 
     189           0 : class FrameParser
     190             : {
     191             : public:
     192             : 
     193             :   // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
     194           0 :   const Frame& CurrentFrame() const { return mFrame; }
     195             : 
     196             : 
     197             :   // Returns the first parsed frame. Reset via Reset.
     198           0 :   const Frame& FirstFrame() const { return mFirstFrame; }
     199             : 
     200             :   // Resets the parser. Don't use between frames as first frame data is reset.
     201           0 :   void Reset()
     202             :   {
     203           0 :     EndFrameSession();
     204           0 :     mFirstFrame.Reset();
     205           0 :   }
     206             : 
     207             :   // Clear the last parsed frame to allow for next frame parsing, i.e.:
     208             :   // - sets PrevFrame to CurrentFrame
     209             :   // - resets the CurrentFrame
     210             :   // - resets ID3Header if no valid header was parsed yet
     211           0 :   void EndFrameSession()
     212             :   {
     213           0 :     mFrame.Reset();
     214           0 :   }
     215             : 
     216             :   // Parses contents of given ByteReader for a valid frame header and returns
     217             :   // true if one was found. After returning, the variable passed to
     218             :   // 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
     219             :   // jump across a large ID3v2 tag spanning multiple buffers.
     220           0 :   bool Parse(int64_t aOffset, const uint8_t* aStart, const uint8_t* aEnd)
     221             :   {
     222           0 :     const bool found = mFrame.Parse(aOffset, aStart, aEnd);
     223             : 
     224           0 :     if (mFrame.Length() && !mFirstFrame.Length()) {
     225           0 :       mFirstFrame = mFrame;
     226             :     }
     227             : 
     228           0 :     return found;
     229             :   }
     230             : 
     231             : private:
     232             :   // We keep the first parsed frame around for static info access, the
     233             :   // previously parsed frame for debugging and the currently parsed frame.
     234             :   Frame mFirstFrame;
     235             :   Frame mFrame;
     236             : };
     237             : 
     238             : 
     239             : // Return the AAC Profile Level Indication based upon sample rate and channels
     240             : // Information based upon table 1.10 from ISO/IEC 14496-3:2005(E)
     241             : static int8_t
     242           0 : ProfileLevelIndication(const Frame& frame)
     243             : {
     244           0 :   const FrameHeader& header = frame.Header();
     245           0 :   MOZ_ASSERT(header.IsValid());
     246             : 
     247           0 :   if (!header.IsValid()) {
     248           0 :     return 0;
     249             :   }
     250             : 
     251           0 :   const int channels = header.mChannels;
     252           0 :   const int sampleRate = header.mSampleRate;
     253             : 
     254           0 :   if (channels <= 2) {
     255           0 :     if (sampleRate <= 24000) {
     256             :       // AAC Profile  L1
     257           0 :       return 0x28;
     258             :     }
     259           0 :     else if (sampleRate <= 48000) {
     260             :       // AAC Profile  L2
     261           0 :       return 0x29;
     262             :     }
     263             :   }
     264           0 :   else if (channels <= 5) {
     265           0 :     if (sampleRate <= 48000) {
     266             :       // AAC Profile  L4
     267           0 :       return 0x2A;
     268             :     }
     269           0 :     else if (sampleRate <= 96000) {
     270             :       // AAC Profile  L5
     271           0 :       return 0x2B;
     272             :     }
     273             :   }
     274             : 
     275             :   // TODO: Should this be 0xFE for 'no audio profile specified'?
     276           0 :   return 0;
     277             : }
     278             : 
     279             : 
     280             : // Initialize the AAC AudioSpecificConfig.
     281             : // Only handles two-byte version for AAC-LC.
     282             : static void
     283           0 : InitAudioSpecificConfig(const Frame& frame,
     284             :                         MediaByteBuffer* aBuffer)
     285             : {
     286           0 :   const FrameHeader& header = frame.Header();
     287           0 :   MOZ_ASSERT(header.IsValid());
     288             : 
     289           0 :   int audioObjectType = header.mObjectType;
     290           0 :   int samplingFrequencyIndex = header.mSamplingIndex;
     291           0 :   int channelConfig = header.mChannelConfig;
     292             : 
     293             :   uint8_t asc[2];
     294           0 :   asc[0] = (audioObjectType & 0x1F) << 3 | (samplingFrequencyIndex & 0x0E) >> 1;
     295           0 :   asc[1] = (samplingFrequencyIndex & 0x01) << 7 | (channelConfig & 0x0F) << 3;
     296             : 
     297           0 :   aBuffer->AppendElements(asc, 2);
     298           0 : }
     299             : 
     300             : } // namespace adts
     301             : 
     302             : using media::TimeUnit;
     303             : 
     304             : // ADTSDemuxer
     305             : 
     306           0 : ADTSDemuxer::ADTSDemuxer(MediaResource* aSource)
     307           0 :   : mSource(aSource)
     308             : {
     309           0 : }
     310             : 
     311             : bool
     312           0 : ADTSDemuxer::InitInternal()
     313             : {
     314           0 :   if (!mTrackDemuxer) {
     315           0 :     mTrackDemuxer = new ADTSTrackDemuxer(mSource);
     316             :   }
     317           0 :   return mTrackDemuxer->Init();
     318             : }
     319             : 
     320             : RefPtr<ADTSDemuxer::InitPromise>
     321           0 : ADTSDemuxer::Init()
     322             : {
     323           0 :   if (!InitInternal()) {
     324           0 :     ADTSLOG("Init() failure: waiting for data");
     325             : 
     326             :     return InitPromise::CreateAndReject(
     327           0 :       NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
     328             :   }
     329             : 
     330           0 :   ADTSLOG("Init() successful");
     331           0 :   return InitPromise::CreateAndResolve(NS_OK, __func__);
     332             : }
     333             : 
     334             : bool
     335           0 : ADTSDemuxer::HasTrackType(TrackInfo::TrackType aType) const
     336             : {
     337           0 :   return aType == TrackInfo::kAudioTrack;
     338             : }
     339             : 
     340             : uint32_t
     341           0 : ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
     342             : {
     343           0 :   return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
     344             : }
     345             : 
     346             : already_AddRefed<MediaTrackDemuxer>
     347           0 : ADTSDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
     348             : {
     349           0 :   if (!mTrackDemuxer) {
     350           0 :     return nullptr;
     351             :   }
     352             : 
     353           0 :   return RefPtr<ADTSTrackDemuxer>(mTrackDemuxer).forget();
     354             : }
     355             : 
     356             : bool
     357           0 : ADTSDemuxer::IsSeekable() const
     358             : {
     359           0 :   int64_t length = mSource->GetLength();
     360           0 :   if (length > -1)
     361           0 :     return true;
     362           0 :   return false;
     363             : }
     364             : 
     365             : 
     366             : // ADTSTrackDemuxer
     367           0 : ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
     368             :   : mSource(aSource)
     369           0 :   , mParser(new adts::FrameParser())
     370             :   , mOffset(0)
     371             :   , mNumParsedFrames(0)
     372             :   , mFrameIndex(0)
     373             :   , mTotalFrameLen(0)
     374             :   , mSamplesPerFrame(0)
     375             :   , mSamplesPerSecond(0)
     376           0 :   , mChannels(0)
     377             : {
     378           0 :   Reset();
     379           0 : }
     380             : 
     381           0 : ADTSTrackDemuxer::~ADTSTrackDemuxer()
     382             : {
     383           0 :   delete mParser;
     384           0 : }
     385             : 
     386             : bool
     387           0 : ADTSTrackDemuxer::Init()
     388             : {
     389           0 :   FastSeek(TimeUnit::Zero());
     390             :   // Read the first frame to fetch sample rate and other meta data.
     391           0 :   RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame(true)));
     392             : 
     393           0 :   ADTSLOG("Init StreamLength()=%" PRId64 " first-frame-found=%d",
     394             :           StreamLength(), !!frame);
     395             : 
     396           0 :   if (!frame) {
     397           0 :     return false;
     398             :   }
     399             : 
     400             :   // Rewind back to the stream begin to avoid dropping the first frame.
     401           0 :   FastSeek(TimeUnit::Zero());
     402             : 
     403           0 :   if (!mInfo) {
     404           0 :     mInfo = MakeUnique<AudioInfo>();
     405             :   }
     406             : 
     407           0 :   mInfo->mRate = mSamplesPerSecond;
     408           0 :   mInfo->mChannels = mChannels;
     409           0 :   mInfo->mBitDepth = 16;
     410           0 :   mInfo->mDuration = Duration();
     411             : 
     412             :   // AAC Specific information
     413           0 :   mInfo->mMimeType = "audio/mp4a-latm";
     414             : 
     415             :   // Configure AAC codec-specific values.
     416             : 
     417             :   // According to
     418             :   // https://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx,
     419             :   // wAudioProfileLevelIndication, which is passed mInfo->mProfile, is
     420             :   // a value from Table 1.12 -- audioProfileLevelIndication values, ISO/IEC 14496-3.
     421           0 :   mInfo->mProfile = ProfileLevelIndication(mParser->FirstFrame());
     422             :   // For AAC, mExtendedProfile contains the audioObjectType from Table
     423             :   // 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
     424           0 :   mInfo->mExtendedProfile = mParser->FirstFrame().Header().mObjectType;
     425           0 :   InitAudioSpecificConfig(mParser->FirstFrame(), mInfo->mCodecSpecificConfig);
     426             : 
     427           0 :   ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
     428             :           "}",
     429             :           mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth,
     430             :           mInfo->mDuration.ToMicroseconds());
     431             : 
     432           0 :   return mSamplesPerSecond && mChannels;
     433             : }
     434             : 
     435             : UniquePtr<TrackInfo>
     436           0 : ADTSTrackDemuxer::GetInfo() const
     437             : {
     438           0 :   return mInfo->Clone();
     439             : }
     440             : 
     441             : RefPtr<ADTSTrackDemuxer::SeekPromise>
     442           0 : ADTSTrackDemuxer::Seek(const TimeUnit& aTime)
     443             : {
     444             :   // Efficiently seek to the position.
     445           0 :   FastSeek(aTime);
     446             :   // Correct seek position by scanning the next frames.
     447           0 :   const TimeUnit seekTime = ScanUntil(aTime);
     448             : 
     449           0 :   return SeekPromise::CreateAndResolve(seekTime, __func__);
     450             : }
     451             : 
     452             : TimeUnit
     453           0 : ADTSTrackDemuxer::FastSeek(const TimeUnit& aTime)
     454             : {
     455           0 :   ADTSLOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
     456             :          " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
     457             :          aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
     458             :          mFrameIndex, mOffset);
     459             : 
     460           0 :   const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
     461           0 :   if (!aTime.ToMicroseconds()) {
     462             :     // Quick seek to the beginning of the stream.
     463           0 :     mOffset = firstFrameOffset;
     464           0 :   } else if (AverageFrameLength() > 0) {
     465           0 :     mOffset = firstFrameOffset + FrameIndexFromTime(aTime) *
     466           0 :       AverageFrameLength();
     467             :   }
     468             : 
     469           0 :   if (mOffset > firstFrameOffset && StreamLength() > 0) {
     470           0 :     mOffset = std::min(StreamLength() - 1, mOffset);
     471             :   }
     472             : 
     473           0 :   mFrameIndex = FrameIndexFromOffset(mOffset);
     474           0 :   mParser->EndFrameSession();
     475             : 
     476           0 :   ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
     477             :           " mFrameIndex=%" PRId64 " mFirstFrameOffset=%" PRIu64 " mOffset=%" PRIu64
     478             :           " SL=%" PRIu64 "",
     479             :           AverageFrameLength(), mNumParsedFrames, mFrameIndex,
     480             :           firstFrameOffset, mOffset, StreamLength());
     481             : 
     482           0 :   return Duration(mFrameIndex);
     483             : }
     484             : 
     485             : TimeUnit
     486           0 : ADTSTrackDemuxer::ScanUntil(const TimeUnit& aTime)
     487             : {
     488           0 :   ADTSLOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
     489             :           " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
     490             :           aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
     491             :           mFrameIndex, mOffset);
     492             : 
     493           0 :   if (!aTime.ToMicroseconds()) {
     494           0 :     return FastSeek(aTime);
     495             :   }
     496             : 
     497           0 :   if (Duration(mFrameIndex) > aTime) {
     498           0 :     FastSeek(aTime);
     499             :   }
     500             : 
     501           0 :   while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex + 1) < aTime) {
     502           0 :     ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
     503             :              " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64,
     504             :              AverageFrameLength(), mNumParsedFrames, mFrameIndex,
     505             :              mOffset, Duration(mFrameIndex + 1).ToMicroseconds());
     506             :   }
     507             : 
     508           0 :   ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
     509             :           " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
     510             :           AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset);
     511             : 
     512           0 :   return Duration(mFrameIndex);
     513             : }
     514             : 
     515             : RefPtr<ADTSTrackDemuxer::SamplesPromise>
     516           0 : ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
     517             : {
     518           0 :   ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
     519             :            " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
     520             :            " mSamplesPerFrame=%d "
     521             :            "mSamplesPerSecond=%d mChannels=%d",
     522             :            aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
     523             :            mSamplesPerFrame, mSamplesPerSecond, mChannels);
     524             : 
     525           0 :   MOZ_ASSERT(aNumSamples);
     526             : 
     527           0 :   RefPtr<SamplesHolder> frames = new SamplesHolder();
     528             : 
     529           0 :   while (aNumSamples--) {
     530           0 :     RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
     531           0 :     if (!frame)
     532           0 :       break;
     533             : 
     534           0 :     frames->mSamples.AppendElement(frame);
     535             :   }
     536             : 
     537           0 :   ADTSLOGV("GetSamples() End mSamples.Size()=%" PRIuSIZE " aNumSamples=%d mOffset=%" PRIu64
     538             :            " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
     539             :            " mTotalFrameLen=%" PRIu64
     540             :            " mSamplesPerFrame=%d mSamplesPerSecond=%d "
     541             :            "mChannels=%d",
     542             :            frames->mSamples.Length(), aNumSamples, mOffset, mNumParsedFrames,
     543             :            mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
     544             :            mChannels);
     545             : 
     546           0 :   if (frames->mSamples.IsEmpty()) {
     547             :     return SamplesPromise::CreateAndReject(
     548           0 :       NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     549             :   }
     550             : 
     551           0 :   return SamplesPromise::CreateAndResolve(frames, __func__);
     552             : }
     553             : 
     554             : void
     555           0 : ADTSTrackDemuxer::Reset()
     556             : {
     557           0 :   ADTSLOG("Reset()");
     558           0 :   MOZ_ASSERT(mParser);
     559           0 :   if (mParser) {
     560           0 :     mParser->Reset();
     561             :   }
     562           0 :   FastSeek(TimeUnit::Zero());
     563           0 : }
     564             : 
     565             : RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
     566           0 : ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold)
     567             : {
     568             :   // Will not be called for audio-only resources.
     569             :   return SkipAccessPointPromise::CreateAndReject(
     570           0 :     SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
     571             : }
     572             : 
     573             : int64_t
     574           0 : ADTSTrackDemuxer::GetResourceOffset() const
     575             : {
     576           0 :   return mOffset;
     577             : }
     578             : 
     579             : media::TimeIntervals
     580           0 : ADTSTrackDemuxer::GetBuffered()
     581             : {
     582           0 :   auto duration = Duration();
     583             : 
     584           0 :   if (!duration.IsPositive()) {
     585           0 :     return media::TimeIntervals();
     586             :   }
     587             : 
     588           0 :   AutoPinned<MediaResource> stream(mSource.GetResource());
     589           0 :   return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
     590             : }
     591             : 
     592             : int64_t
     593           0 : ADTSTrackDemuxer::StreamLength() const
     594             : {
     595           0 :   return mSource.GetLength();
     596             : }
     597             : 
     598             : TimeUnit
     599           0 : ADTSTrackDemuxer::Duration() const
     600             : {
     601           0 :   if (!mNumParsedFrames) {
     602           0 :     return TimeUnit::FromMicroseconds(-1);
     603             :   }
     604             : 
     605           0 :   const int64_t streamLen = StreamLength();
     606           0 :   if (streamLen < 0) {
     607             :     // Unknown length, we can't estimate duration.
     608           0 :     return TimeUnit::FromMicroseconds(-1);
     609             :   }
     610           0 :   const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
     611           0 :   int64_t numFrames = (streamLen - firstFrameOffset) / AverageFrameLength();
     612           0 :   return Duration(numFrames);
     613             : }
     614             : 
     615             : TimeUnit
     616           0 : ADTSTrackDemuxer::Duration(int64_t aNumFrames) const
     617             : {
     618           0 :   if (!mSamplesPerSecond) {
     619           0 :     return TimeUnit::FromMicroseconds(-1);
     620             :   }
     621             : 
     622           0 :   return FramesToTimeUnit(aNumFrames * mSamplesPerFrame, mSamplesPerSecond);
     623             : }
     624             : 
     625             : const adts::Frame&
     626           0 : ADTSTrackDemuxer::FindNextFrame(bool findFirstFrame /*= false*/)
     627             : {
     628             :   static const int BUFFER_SIZE = 4096;
     629             :   static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE;
     630             : 
     631           0 :   ADTSLOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
     632             :           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
     633             :           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
     634             :           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
     635             :           mSamplesPerFrame, mSamplesPerSecond, mChannels);
     636             : 
     637             :   uint8_t buffer[BUFFER_SIZE];
     638           0 :   int32_t read = 0;
     639             : 
     640           0 :   bool foundFrame = false;
     641           0 :   int64_t frameHeaderOffset = mOffset;
     642             : 
     643             :   // Prepare the parser for the next frame parsing session.
     644           0 :   mParser->EndFrameSession();
     645             : 
     646             :   // Check whether we've found a valid ADTS frame.
     647           0 :   while (!foundFrame) {
     648           0 :     if ((read = Read(buffer, frameHeaderOffset, BUFFER_SIZE)) == 0) {
     649           0 :       ADTSLOG("FindNext() EOS without a frame");
     650           0 :       break;
     651             :     }
     652             : 
     653           0 :     if (frameHeaderOffset - mOffset > MAX_SKIPPED_BYTES) {
     654           0 :       ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
     655           0 :       break;
     656             :     }
     657             : 
     658           0 :     const adts::Frame& currentFrame = mParser->CurrentFrame();
     659           0 :     foundFrame = mParser->Parse(frameHeaderOffset, buffer, buffer + read);
     660           0 :     if (findFirstFrame && foundFrame) {
     661             :       // Check for sync marker after the found frame, since it's
     662             :       // possible to find sync marker in AAC data. If sync marker
     663             :       // exists after the current frame then we've found a frame
     664             :       // header.
     665             :       int64_t nextFrameHeaderOffset =
     666           0 :         currentFrame.Offset() + currentFrame.Length();
     667           0 :       int32_t read = Read(buffer, nextFrameHeaderOffset, 2);
     668           0 :       if (read != 2 || !adts::FrameHeader::MatchesSync(buffer)) {
     669           0 :         frameHeaderOffset = currentFrame.Offset() + 1;
     670           0 :         mParser->Reset();
     671           0 :         foundFrame = false;
     672           0 :         continue;
     673             :       }
     674             :     }
     675             : 
     676           0 :     if (foundFrame) {
     677           0 :       break;
     678             :     }
     679             : 
     680             :     // Minimum header size is 7 bytes.
     681           0 :     int64_t advance = read - 7;
     682             : 
     683             :     // Check for offset overflow.
     684           0 :     if (frameHeaderOffset + advance <= frameHeaderOffset) {
     685           0 :       break;
     686             :     }
     687             : 
     688           0 :     frameHeaderOffset += advance;
     689             :   }
     690             : 
     691           0 :   if (!foundFrame || !mParser->CurrentFrame().Length()) {
     692           0 :     ADTSLOG("FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%" PRIuSIZE " ",
     693             :            foundFrame, mParser->CurrentFrame().Length());
     694           0 :     mParser->Reset();
     695           0 :     return mParser->CurrentFrame();
     696             :   }
     697             : 
     698           0 :   ADTSLOGV("FindNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
     699             :           " mFrameIndex=%" PRId64 " frameHeaderOffset=%" PRId64
     700             :           " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
     701             :           " mChannels=%d",
     702             :           mOffset, mNumParsedFrames, mFrameIndex, frameHeaderOffset,
     703             :           mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond, mChannels);
     704             : 
     705           0 :   return mParser->CurrentFrame();
     706             : }
     707             : 
     708             : bool
     709           0 : ADTSTrackDemuxer::SkipNextFrame(const adts::Frame& aFrame)
     710             : {
     711           0 :   if (!mNumParsedFrames || !aFrame.Length()) {
     712           0 :     RefPtr<MediaRawData> frame(GetNextFrame(aFrame));
     713           0 :     return frame;
     714             :   }
     715             : 
     716           0 :   UpdateState(aFrame);
     717             : 
     718           0 :   ADTSLOGV("SkipNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
     719             :           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
     720             :           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
     721             :           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
     722             :           mSamplesPerFrame, mSamplesPerSecond, mChannels);
     723             : 
     724           0 :   return true;
     725             : }
     726             : 
     727             : already_AddRefed<MediaRawData>
     728           0 : ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame)
     729             : {
     730           0 :   ADTSLOG("GetNext() Begin({mOffset=%" PRId64 " HeaderSize()=%" PRIuSIZE
     731             :           " Length()=%" PRIuSIZE "})",
     732             :          aFrame.Offset(), aFrame.Header().HeaderSize(), aFrame.PayloadLength());
     733           0 :   if (!aFrame.IsValid())
     734           0 :     return nullptr;
     735             : 
     736           0 :   const int64_t offset = aFrame.PayloadOffset();
     737           0 :   const uint32_t length = aFrame.PayloadLength();
     738             : 
     739           0 :   RefPtr<MediaRawData> frame = new MediaRawData();
     740           0 :   frame->mOffset = offset;
     741             : 
     742           0 :   UniquePtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
     743           0 :   if (!frameWriter->SetSize(length)) {
     744           0 :     ADTSLOG("GetNext() Exit failed to allocated media buffer");
     745           0 :     return nullptr;
     746             :   }
     747             : 
     748           0 :   const uint32_t read = Read(frameWriter->Data(), offset, length);
     749           0 :   if (read != length) {
     750           0 :     ADTSLOG("GetNext() Exit read=%u frame->Size()=%" PRIuSIZE, read, frame->Size());
     751           0 :     return nullptr;
     752             :   }
     753             : 
     754           0 :   UpdateState(aFrame);
     755             : 
     756           0 :   frame->mTime = Duration(mFrameIndex - 1);
     757           0 :   frame->mDuration = Duration(1);
     758           0 :   frame->mTimecode = frame->mTime;
     759           0 :   frame->mKeyframe = true;
     760             : 
     761           0 :   MOZ_ASSERT(!frame->mTime.IsNegative());
     762           0 :   MOZ_ASSERT(frame->mDuration.IsPositive());
     763             : 
     764           0 :   ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
     765             :            " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
     766             :            " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
     767             :            mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
     768             :            mSamplesPerFrame, mSamplesPerSecond, mChannels);
     769             : 
     770           0 :   return frame.forget();
     771             : }
     772             : 
     773             : int64_t
     774           0 : ADTSTrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const
     775             : {
     776           0 :   int64_t frameIndex = 0;
     777             : 
     778           0 :   if (AverageFrameLength() > 0) {
     779           0 :     frameIndex =
     780           0 :       (aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
     781             :   }
     782             : 
     783           0 :   ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset, frameIndex);
     784           0 :   return std::max<int64_t>(0, frameIndex);
     785             : }
     786             : 
     787             : int64_t
     788           0 : ADTSTrackDemuxer::FrameIndexFromTime(const TimeUnit& aTime) const
     789             : {
     790           0 :   int64_t frameIndex = 0;
     791           0 :   if (mSamplesPerSecond > 0 && mSamplesPerFrame > 0) {
     792           0 :     frameIndex = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame - 1;
     793             :   }
     794             : 
     795           0 :   ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64,
     796             :            aTime.ToSeconds(), frameIndex);
     797           0 :   return std::max<int64_t>(0, frameIndex);
     798             : }
     799             : 
     800             : void
     801           0 : ADTSTrackDemuxer::UpdateState(const adts::Frame& aFrame)
     802             : {
     803           0 :   int32_t frameLength = aFrame.Length();
     804             :   // Prevent overflow.
     805           0 :   if (mTotalFrameLen + frameLength < mTotalFrameLen) {
     806             :     // These variables have a linear dependency and are only used to derive the
     807             :     // average frame length.
     808           0 :     mTotalFrameLen /= 2;
     809           0 :     mNumParsedFrames /= 2;
     810             :   }
     811             : 
     812             :   // Full frame parsed, move offset to its end.
     813           0 :   mOffset = aFrame.Offset() + frameLength;
     814           0 :   mTotalFrameLen += frameLength;
     815             : 
     816           0 :   if (!mSamplesPerFrame) {
     817           0 :     const adts::FrameHeader& header = aFrame.Header();
     818           0 :     mSamplesPerFrame = header.mSamples;
     819           0 :     mSamplesPerSecond = header.mSampleRate;
     820           0 :     mChannels = header.mChannels;
     821             :   }
     822             : 
     823           0 :   ++mNumParsedFrames;
     824           0 :   ++mFrameIndex;
     825           0 :   MOZ_ASSERT(mFrameIndex > 0);
     826           0 : }
     827             : 
     828             : int32_t
     829           0 : ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
     830             : {
     831           0 :   ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)",
     832             :            aBuffer, aOffset, aSize);
     833             : 
     834           0 :   const int64_t streamLen = StreamLength();
     835           0 :   if (mInfo && streamLen > 0) {
     836             :     // Prevent blocking reads after successful initialization.
     837           0 :     aSize = std::min<int64_t>(aSize, streamLen - aOffset);
     838             :   }
     839             : 
     840           0 :   uint32_t read = 0;
     841           0 :   ADTSLOGV("ADTSTrackDemuxer::Read        -> ReadAt(%d)", aSize);
     842           0 :   const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
     843           0 :                                      static_cast<uint32_t>(aSize), &read);
     844           0 :   NS_ENSURE_SUCCESS(rv, 0);
     845           0 :   return static_cast<int32_t>(read);
     846             : }
     847             : 
     848             : double
     849           0 : ADTSTrackDemuxer::AverageFrameLength() const
     850             : {
     851           0 :   if (mNumParsedFrames) {
     852           0 :     return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
     853             :   }
     854             : 
     855           0 :   return 0.0;
     856             : }
     857             : 
     858             : /* static */ bool
     859           0 : ADTSDemuxer::ADTSSniffer(const uint8_t* aData, const uint32_t aLength)
     860             : {
     861           0 :   if (aLength < 7) {
     862           0 :     return false;
     863             :   }
     864           0 :   if (!adts::FrameHeader::MatchesSync(aData)) {
     865           0 :     return false;
     866             :   }
     867           0 :   auto parser = MakeUnique<adts::FrameParser>();
     868             : 
     869           0 :   if (!parser->Parse(0, aData, aData + aLength)) {
     870           0 :     return false;
     871             :   }
     872           0 :   const adts::Frame& currentFrame = parser->CurrentFrame();
     873             :   // Check for sync marker after the found frame, since it's
     874             :   // possible to find sync marker in AAC data. If sync marker
     875             :   // exists after the current frame then we've found a frame
     876             :   // header.
     877           0 :   int64_t nextFrameHeaderOffset = currentFrame.Offset() + currentFrame.Length();
     878           0 :   return int64_t(aLength) > nextFrameHeaderOffset &&
     879           0 :          aLength - nextFrameHeaderOffset >= 2 &&
     880           0 :          adts::FrameHeader::MatchesSync(aData + nextFrameHeaderOffset);
     881             : }
     882             : 
     883             : } // namespace mozilla

Generated by: LCOV version 1.13