LCOV - code coverage report
Current view: top level - dom/media/wave - WaveDemuxer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 417 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 78 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 "WaveDemuxer.h"
       8             : 
       9             : #include <inttypes.h>
      10             : #include <algorithm>
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/EndianUtils.h"
      14             : #include "nsAutoPtr.h"
      15             : #include "VideoUtils.h"
      16             : #include "TimeUnits.h"
      17             : #include "prenv.h"
      18             : 
      19             : using mozilla::media::TimeUnit;
      20             : using mozilla::media::TimeIntervals;
      21             : using mp4_demuxer::ByteReader;
      22             : 
      23             : namespace mozilla {
      24             : 
      25             : // WAVDemuxer
      26             : 
      27           0 : WAVDemuxer::WAVDemuxer(MediaResource* aSource)
      28           0 :   : mSource(aSource)
      29             : {
      30           0 : }
      31             : 
      32             : bool
      33           0 : WAVDemuxer::InitInternal()
      34             : {
      35           0 :   if (!mTrackDemuxer) {
      36           0 :     mTrackDemuxer = new WAVTrackDemuxer(mSource.GetResource());
      37             :   }
      38           0 :   return mTrackDemuxer->Init();
      39             : }
      40             : 
      41             : RefPtr<WAVDemuxer::InitPromise>
      42           0 : WAVDemuxer::Init()
      43             : {
      44           0 :   if (!InitInternal()) {
      45             :     return InitPromise::CreateAndReject(
      46           0 :       NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
      47             :   }
      48           0 :   return InitPromise::CreateAndResolve(NS_OK, __func__);
      49             : }
      50             : 
      51             : bool
      52           0 : WAVDemuxer::HasTrackType(TrackInfo::TrackType aType) const
      53             : {
      54           0 :   return aType == TrackInfo::kAudioTrack;
      55             : }
      56             : 
      57             : uint32_t
      58           0 : WAVDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
      59             : {
      60           0 :   return aType == TrackInfo::kAudioTrack ? 1u : 0u;
      61             : }
      62             : 
      63             : already_AddRefed<MediaTrackDemuxer>
      64           0 : WAVDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
      65             : {
      66           0 :   if (!mTrackDemuxer) {
      67           0 :     return nullptr;
      68             :   }
      69           0 :   return RefPtr<WAVTrackDemuxer>(mTrackDemuxer).forget();
      70             : }
      71             : 
      72             : bool
      73           0 : WAVDemuxer::IsSeekable() const
      74             : {
      75           0 :   return true;
      76             : }
      77             : 
      78             : // WAVTrackDemuxer
      79             : 
      80           0 : WAVTrackDemuxer::WAVTrackDemuxer(MediaResource* aSource)
      81             :   : mSource(aSource)
      82             :   , mOffset(0)
      83             :   , mFirstChunkOffset(0)
      84             :   , mNumParsedChunks(0)
      85             :   , mChunkIndex(0)
      86             :   , mTotalChunkLen(0)
      87             :   , mSamplesPerChunk(0)
      88             :   , mSamplesPerSecond(0)
      89           0 :   , mChannels(0)
      90             : {
      91           0 :   Reset();
      92           0 : }
      93             : 
      94             : bool
      95           0 : WAVTrackDemuxer::Init()
      96             : {
      97           0 :   Reset();
      98           0 :   FastSeek(TimeUnit());
      99             : 
     100           0 :   if (!mInfo) {
     101           0 :     mInfo = MakeUnique<AudioInfo>();
     102             :   }
     103             : 
     104           0 :   if (!RIFFParserInit()) {
     105           0 :     return false;
     106             :   }
     107             : 
     108             :   while (true) {
     109           0 :     if (!HeaderParserInit()) {
     110           0 :       return false;
     111             :     }
     112             : 
     113           0 :     uint32_t aChunkName = mHeaderParser.GiveHeader().ChunkName();
     114           0 :     uint32_t aChunkSize = mHeaderParser.GiveHeader().ChunkSize();
     115             : 
     116           0 :     if (aChunkName == FRMT_CODE) {
     117           0 :       if (!FmtChunkParserInit()) {
     118           0 :         return false;
     119             :       }
     120           0 :     } else if (aChunkName == LIST_CODE) {
     121           0 :       mHeaderParser.Reset();
     122           0 :       uint64_t endOfListChunk = static_cast<uint64_t>(mOffset) + aChunkSize;
     123           0 :       if (endOfListChunk > UINT32_MAX) {
     124           0 :         return false;
     125             :       }
     126           0 :       if (!ListChunkParserInit(aChunkSize)) {
     127           0 :         mOffset = endOfListChunk;
     128             :       }
     129           0 :     } else if (aChunkName == DATA_CODE) {
     130           0 :       mDataLength = aChunkSize;
     131           0 :       if (mFirstChunkOffset != mOffset) {
     132           0 :         mFirstChunkOffset = mOffset;
     133             :       }
     134           0 :       break;
     135             :     } else {
     136           0 :       mOffset += aChunkSize; // Skip other irrelevant chunks.
     137             :     }
     138           0 :     if (mOffset & 1) {
     139             :       // Wave files are 2-byte aligned so we need to round up
     140           0 :       mOffset += 1;
     141             :     }
     142           0 :     mHeaderParser.Reset();
     143           0 :   }
     144             : 
     145           0 :   if (mDataLength > StreamLength() - mFirstChunkOffset) {
     146           0 :     mDataLength = StreamLength() - mFirstChunkOffset;
     147             :   }
     148             : 
     149           0 :   mSamplesPerSecond = mFmtParser.FmtChunk().SampleRate();
     150           0 :   mChannels = mFmtParser.FmtChunk().Channels();
     151           0 :   mSampleFormat = mFmtParser.FmtChunk().SampleFormat();
     152           0 :   if (!mSamplesPerSecond || !mChannels || !mSampleFormat) {
     153           0 :     return false;
     154             :   }
     155           0 :   mSamplesPerChunk = DATA_CHUNK_SIZE * 8 / mChannels / mSampleFormat;
     156             : 
     157           0 :   mInfo->mRate = mSamplesPerSecond;
     158           0 :   mInfo->mChannels = mChannels;
     159           0 :   mInfo->mBitDepth = mSampleFormat;
     160           0 :   mInfo->mProfile = mFmtParser.FmtChunk().WaveFormat() & 0x00FF;
     161           0 :   mInfo->mExtendedProfile = (mFmtParser.FmtChunk().WaveFormat() & 0xFF00) >> 8;
     162           0 :   mInfo->mMimeType = "audio/wave; codecs=";
     163           0 :   mInfo->mMimeType.AppendInt(mFmtParser.FmtChunk().WaveFormat());
     164           0 :   mInfo->mDuration = Duration();
     165             : 
     166           0 :   return mInfo->mDuration.IsPositive();
     167             : }
     168             : 
     169             : bool
     170           0 : WAVTrackDemuxer::RIFFParserInit()
     171             : {
     172           0 :   RefPtr<MediaRawData> riffHeader = GetFileHeader(FindRIFFHeader());
     173           0 :   if (!riffHeader) {
     174           0 :     return false;
     175             :   }
     176           0 :   ByteReader RIFFReader(riffHeader->Data(), 12);
     177           0 :   mRIFFParser.Parse(RIFFReader);
     178           0 :   return mRIFFParser.RiffHeader().IsValid(11);
     179             : }
     180             : 
     181             : bool
     182           0 : WAVTrackDemuxer::HeaderParserInit()
     183             : {
     184           0 :   RefPtr<MediaRawData> header = GetFileHeader(FindChunkHeader());
     185           0 :   if (!header) {
     186           0 :     return false;
     187             :   }
     188           0 :   ByteReader HeaderReader(header->Data(), 8);
     189           0 :   mHeaderParser.Parse(HeaderReader);
     190           0 :   return true;
     191             : }
     192             : 
     193             : bool
     194           0 : WAVTrackDemuxer::FmtChunkParserInit()
     195             : {
     196           0 :   RefPtr<MediaRawData> fmtChunk = GetFileHeader(FindFmtChunk());
     197           0 :   if (!fmtChunk) {
     198           0 :     return false;
     199             :   }
     200             :   ByteReader fmtReader(fmtChunk->Data(),
     201           0 :                        mHeaderParser.GiveHeader().ChunkSize());
     202           0 :   mFmtParser.Parse(fmtReader);
     203           0 :   return true;
     204             : }
     205             : 
     206             : bool
     207           0 : WAVTrackDemuxer::ListChunkParserInit(uint32_t aChunkSize)
     208             : {
     209           0 :   uint32_t bytesRead = 0;
     210             : 
     211           0 :   RefPtr<MediaRawData> infoTag = GetFileHeader(FindInfoTag());
     212           0 :   if (!infoTag) {
     213           0 :     return false;
     214             :   }
     215           0 :   ByteReader infoTagReader(infoTag->Data(), 4);
     216           0 :   if (!infoTagReader.CanRead32() || infoTagReader.ReadU32() != INFO_CODE) {
     217           0 :     return false;
     218             :   }
     219             : 
     220           0 :   bytesRead += 4;
     221             : 
     222           0 :   while (bytesRead < aChunkSize) {
     223           0 :     if (!HeaderParserInit()) {
     224           0 :       return false;
     225             :     }
     226             : 
     227           0 :     bytesRead += 8;
     228             : 
     229           0 :     uint32_t id = mHeaderParser.GiveHeader().ChunkName();
     230           0 :     uint32_t length = mHeaderParser.GiveHeader().ChunkSize();
     231             : 
     232             :     // SubChunk Length Cannot Exceed List Chunk length.
     233           0 :     if (length > aChunkSize - bytesRead) {
     234           0 :       length = aChunkSize - bytesRead;
     235             :     }
     236             : 
     237           0 :     MediaByteRange mRange = { mOffset, mOffset + length };
     238           0 :     RefPtr<MediaRawData> mChunkData = GetFileHeader(mRange);
     239           0 :     if (!mChunkData) {
     240           0 :       return false;
     241             :     }
     242             : 
     243           0 :     const char* rawData = reinterpret_cast<const char*>(mChunkData->Data());
     244             : 
     245           0 :     nsCString val(rawData, length);
     246           0 :     if (length > 0 && val[length - 1] == '\0') {
     247           0 :       val.SetLength(length - 1);
     248             :     }
     249             : 
     250           0 :     if (length % 2) {
     251           0 :       mOffset += 1;
     252           0 :       length += length % 2;
     253             :     }
     254             : 
     255           0 :     bytesRead += length;
     256             : 
     257           0 :     if (!IsUTF8(val)) {
     258           0 :       mHeaderParser.Reset();
     259           0 :       continue;
     260             :     }
     261             : 
     262           0 :     switch (id) {
     263             :       case 0x49415254:                // IART
     264           0 :         mInfo->mTags.AppendElement(
     265           0 :           MetadataTag(NS_LITERAL_CSTRING("artist"), val));
     266           0 :         break;
     267             :       case 0x49434d54:                // ICMT
     268           0 :         mInfo->mTags.AppendElement(
     269           0 :           MetadataTag(NS_LITERAL_CSTRING("comments"), val));
     270           0 :         break;
     271             :       case 0x49474e52:                // IGNR
     272           0 :         mInfo->mTags.AppendElement(
     273           0 :           MetadataTag(NS_LITERAL_CSTRING("genre"), val));
     274           0 :         break;
     275             :       case 0x494e414d:                // INAM
     276           0 :         mInfo->mTags.AppendElement(
     277           0 :           MetadataTag(NS_LITERAL_CSTRING("name"), val));
     278           0 :         break;
     279             :     }
     280             : 
     281           0 :     mHeaderParser.Reset();
     282             :   }
     283           0 :   return true;
     284             : }
     285             : 
     286             : media::TimeUnit
     287           0 : WAVTrackDemuxer::SeekPosition() const
     288             : {
     289           0 :   TimeUnit pos = Duration(mChunkIndex);
     290           0 :   if (Duration() > TimeUnit()) {
     291           0 :     pos = std::min(Duration(), pos);
     292             :   }
     293           0 :   return pos;
     294             : }
     295             : 
     296             : RefPtr<MediaRawData>
     297           0 : WAVTrackDemuxer::DemuxSample()
     298             : {
     299           0 :   return GetNextChunk(FindNextChunk());
     300             : }
     301             : 
     302             : UniquePtr<TrackInfo>
     303           0 : WAVTrackDemuxer::GetInfo() const
     304             : {
     305           0 :   return mInfo->Clone();
     306             : }
     307             : 
     308             : RefPtr<WAVTrackDemuxer::SeekPromise>
     309           0 : WAVTrackDemuxer::Seek(const TimeUnit& aTime)
     310             : {
     311           0 :   FastSeek(aTime);
     312           0 :   const TimeUnit seekTime = ScanUntil(aTime);
     313           0 :   return SeekPromise::CreateAndResolve(seekTime, __func__);
     314             : }
     315             : 
     316             : TimeUnit
     317           0 : WAVTrackDemuxer::FastSeek(const TimeUnit& aTime)
     318             : {
     319           0 :   if (aTime.ToMicroseconds()) {
     320           0 :     mChunkIndex = ChunkIndexFromTime(aTime);
     321             :   } else {
     322           0 :     mChunkIndex = 0;
     323             :   }
     324             : 
     325           0 :   mOffset = OffsetFromChunkIndex(mChunkIndex);
     326             : 
     327           0 :   if (mOffset > mFirstChunkOffset && StreamLength() > 0) {
     328           0 :     mOffset = std::min(StreamLength() - 1, mOffset);
     329             :   }
     330             : 
     331           0 :   return Duration(mChunkIndex);
     332             : }
     333             : 
     334             : TimeUnit
     335           0 : WAVTrackDemuxer::ScanUntil(const TimeUnit& aTime)
     336             : {
     337           0 :   if (!aTime.ToMicroseconds()) {
     338           0 :     return FastSeek(aTime);
     339             :   }
     340             : 
     341           0 :   if (Duration(mChunkIndex) > aTime) {
     342           0 :     FastSeek(aTime);
     343             :   }
     344             : 
     345           0 :   return SeekPosition();
     346             : }
     347             : 
     348             : RefPtr<WAVTrackDemuxer::SamplesPromise>
     349           0 : WAVTrackDemuxer::GetSamples(int32_t aNumSamples)
     350             : {
     351           0 :   MOZ_ASSERT(aNumSamples);
     352             : 
     353           0 :   RefPtr<SamplesHolder> datachunks = new SamplesHolder();
     354             : 
     355           0 :   while (aNumSamples--) {
     356           0 :     RefPtr<MediaRawData> datachunk = GetNextChunk(FindNextChunk());
     357           0 :     if (!datachunk) {
     358           0 :       break;
     359             :     }
     360           0 :     datachunks->mSamples.AppendElement(datachunk);
     361             :   }
     362             : 
     363           0 :   if (datachunks->mSamples.IsEmpty()) {
     364             :     return SamplesPromise::CreateAndReject(
     365           0 :       NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     366             :   }
     367             : 
     368           0 :   return SamplesPromise::CreateAndResolve(datachunks, __func__);
     369             : }
     370             : 
     371             : void
     372           0 : WAVTrackDemuxer::Reset()
     373             : {
     374           0 :   FastSeek(TimeUnit());
     375           0 :   mParser.Reset();
     376           0 :   mHeaderParser.Reset();
     377           0 :   mRIFFParser.Reset();
     378           0 :   mFmtParser.Reset();
     379           0 : }
     380             : 
     381             : RefPtr<WAVTrackDemuxer::SkipAccessPointPromise>
     382           0 : WAVTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold)
     383             : {
     384             :   return SkipAccessPointPromise::CreateAndReject(
     385           0 :     SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
     386             : }
     387             : 
     388             : int64_t
     389           0 : WAVTrackDemuxer::GetResourceOffset() const
     390             : {
     391           0 :   return mOffset;
     392             : }
     393             : 
     394             : TimeIntervals
     395           0 : WAVTrackDemuxer::GetBuffered()
     396             : {
     397           0 :   TimeUnit duration = Duration();
     398             : 
     399           0 :   if (duration <= TimeUnit()) {
     400           0 :     return TimeIntervals();
     401             :   }
     402             : 
     403           0 :   AutoPinned<MediaResource> stream(mSource.GetResource());
     404           0 :   return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
     405             : }
     406             : 
     407             : int64_t
     408           0 : WAVTrackDemuxer::StreamLength() const
     409             : {
     410           0 :   return mSource.GetLength();
     411             : }
     412             : 
     413             : TimeUnit
     414           0 : WAVTrackDemuxer::Duration() const
     415             : {
     416           0 :   if (!mDataLength ||!mChannels || !mSampleFormat) {
     417           0 :     return TimeUnit();
     418             :   }
     419             : 
     420             :   int64_t numSamples =
     421           0 :     static_cast<int64_t>(mDataLength) * 8 / mChannels / mSampleFormat;
     422             : 
     423           0 :   int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
     424             : 
     425           0 :   if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
     426           0 :     numUSeconds++;
     427             :   }
     428             : 
     429           0 :   return TimeUnit::FromMicroseconds(numUSeconds);
     430             : }
     431             : 
     432             : TimeUnit
     433           0 : WAVTrackDemuxer::Duration(int64_t aNumDataChunks) const
     434             : {
     435           0 :   if (!mSamplesPerSecond || !mSamplesPerChunk) {
     436           0 :     return TimeUnit();
     437             :   }
     438             :   const double usPerDataChunk =
     439           0 :     USECS_PER_S * static_cast<double>(mSamplesPerChunk) / mSamplesPerSecond;
     440           0 :   return TimeUnit::FromMicroseconds(aNumDataChunks * usPerDataChunk);
     441             : }
     442             : 
     443             : TimeUnit
     444           0 : WAVTrackDemuxer::DurationFromBytes(uint32_t aNumBytes) const
     445             : {
     446           0 :   if (!mSamplesPerSecond || !mChannels || !mSampleFormat) {
     447           0 :     return TimeUnit();
     448             :   }
     449             : 
     450           0 :   int64_t numSamples = aNumBytes * 8 / mChannels / mSampleFormat;
     451             : 
     452           0 :   int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
     453             : 
     454           0 :   if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
     455           0 :     numUSeconds++;
     456             :   }
     457             : 
     458           0 :   return TimeUnit::FromMicroseconds(numUSeconds);
     459             : }
     460             : 
     461             : MediaByteRange
     462           0 : WAVTrackDemuxer::FindNextChunk()
     463             : {
     464           0 :   if (mOffset + DATA_CHUNK_SIZE < mFirstChunkOffset + mDataLength) {
     465           0 :     return { mOffset, mOffset + DATA_CHUNK_SIZE };
     466             :   } else {
     467           0 :     return { mOffset, mFirstChunkOffset + mDataLength };
     468             :   }
     469             : }
     470             : 
     471             : MediaByteRange
     472           0 : WAVTrackDemuxer::FindChunkHeader()
     473             : {
     474           0 :   return { mOffset, mOffset + CHUNK_HEAD_SIZE };
     475             : }
     476             : 
     477             : MediaByteRange
     478           0 : WAVTrackDemuxer::FindRIFFHeader()
     479             : {
     480           0 :   return { mOffset, mOffset + RIFF_CHUNK_SIZE };
     481             : }
     482             : 
     483             : MediaByteRange
     484           0 : WAVTrackDemuxer::FindFmtChunk()
     485             : {
     486           0 :   return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
     487             : }
     488             : 
     489             : MediaByteRange
     490           0 : WAVTrackDemuxer::FindListChunk()
     491             : {
     492           0 :   return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
     493             : }
     494             : 
     495             : MediaByteRange
     496           0 : WAVTrackDemuxer::FindInfoTag()
     497             : {
     498           0 :   return { mOffset, mOffset + 4 };
     499             : }
     500             : 
     501             : bool
     502           0 : WAVTrackDemuxer::SkipNextChunk(const MediaByteRange& aRange)
     503             : {
     504           0 :   UpdateState(aRange);
     505           0 :   return true;
     506             : }
     507             : 
     508             : already_AddRefed<MediaRawData>
     509           0 : WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange)
     510             : {
     511           0 :   if (!aRange.Length()) {
     512           0 :     return nullptr;
     513             :   }
     514             : 
     515           0 :   RefPtr<MediaRawData> datachunk = new MediaRawData();
     516           0 :   datachunk->mOffset = aRange.mStart;
     517             : 
     518           0 :   nsAutoPtr<MediaRawDataWriter> chunkWriter(datachunk->CreateWriter());
     519           0 :   if (!chunkWriter->SetSize(aRange.Length())) {
     520           0 :     return nullptr;
     521             :   }
     522             : 
     523             :   const uint32_t read =
     524           0 :     Read(chunkWriter->Data(), datachunk->mOffset, datachunk->Size());
     525             : 
     526           0 :   if (read != aRange.Length()) {
     527           0 :     return nullptr;
     528             :   }
     529             : 
     530           0 :   UpdateState(aRange);
     531           0 :   ++mNumParsedChunks;
     532           0 :   ++mChunkIndex;
     533             : 
     534           0 :   datachunk->mTime = Duration(mChunkIndex - 1);
     535             : 
     536           0 :   if (static_cast<uint32_t>(mChunkIndex) * DATA_CHUNK_SIZE < mDataLength) {
     537           0 :     datachunk->mDuration = Duration(1);
     538             :   } else {
     539             :     uint32_t mBytesRemaining =
     540           0 :       mDataLength - mChunkIndex * DATA_CHUNK_SIZE;
     541           0 :     datachunk->mDuration = DurationFromBytes(mBytesRemaining);
     542             :   }
     543           0 :   datachunk->mTimecode = datachunk->mTime;
     544           0 :   datachunk->mKeyframe = true;
     545             : 
     546           0 :   MOZ_ASSERT(!datachunk->mTime.IsNegative());
     547           0 :   MOZ_ASSERT(!datachunk->mDuration.IsNegative());
     548             : 
     549           0 :   return datachunk.forget();
     550             : }
     551             : 
     552             : already_AddRefed<MediaRawData>
     553           0 : WAVTrackDemuxer::GetFileHeader(const MediaByteRange& aRange)
     554             : {
     555           0 :   if (!aRange.Length()) {
     556           0 :     return nullptr;
     557             :   }
     558             : 
     559           0 :   RefPtr<MediaRawData> fileHeader = new MediaRawData();
     560           0 :   fileHeader->mOffset = aRange.mStart;
     561             : 
     562           0 :   nsAutoPtr<MediaRawDataWriter> headerWriter(fileHeader->CreateWriter());
     563           0 :   if (!headerWriter->SetSize(aRange.Length())) {
     564           0 :     return nullptr;
     565             :   }
     566             : 
     567             :   const uint32_t read =
     568           0 :     Read(headerWriter->Data(), fileHeader->mOffset, fileHeader->Size());
     569             : 
     570           0 :   if (read != aRange.Length()) {
     571           0 :     return nullptr;
     572             :   }
     573             : 
     574           0 :   UpdateState(aRange);
     575             : 
     576           0 :   return fileHeader.forget();
     577             : }
     578             : 
     579             : int64_t
     580           0 : WAVTrackDemuxer::OffsetFromChunkIndex(int64_t aChunkIndex) const
     581             : {
     582           0 :   return mFirstChunkOffset + aChunkIndex * DATA_CHUNK_SIZE;
     583             : }
     584             : 
     585             : int64_t
     586           0 : WAVTrackDemuxer::ChunkIndexFromOffset(int64_t aOffset) const
     587             : {
     588           0 :   int64_t chunkIndex = (aOffset - mFirstChunkOffset) / DATA_CHUNK_SIZE;
     589           0 :   return std::max<int64_t>(0, chunkIndex);
     590             : }
     591             : 
     592             : int64_t
     593           0 : WAVTrackDemuxer::ChunkIndexFromTime(const media::TimeUnit& aTime) const
     594             : {
     595           0 :   if (!mSamplesPerChunk || !mSamplesPerSecond) {
     596           0 :     return 0;
     597             :   }
     598             :   int64_t chunkIndex =
     599           0 :     (aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerChunk) - 1;
     600           0 :   return chunkIndex;
     601             : }
     602             : 
     603             : void
     604           0 : WAVTrackDemuxer::UpdateState(const MediaByteRange& aRange)
     605             : {
     606             :   // Full chunk parsed, move offset to its end.
     607           0 :   mOffset = aRange.mEnd;
     608           0 :   mTotalChunkLen += aRange.Length();
     609           0 : }
     610             : 
     611             : int32_t
     612           0 : WAVTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
     613             : {
     614           0 :   const int64_t streamLen = StreamLength();
     615           0 :   if (mInfo && streamLen > 0) {
     616           0 :     aSize = std::min<int64_t>(aSize, streamLen - aOffset);
     617             :   }
     618           0 :   uint32_t read = 0;
     619           0 :   const nsresult rv = mSource.ReadAt(aOffset,
     620             :                                      reinterpret_cast<char*>(aBuffer),
     621             :                                      static_cast<uint32_t>(aSize),
     622           0 :                                      &read);
     623           0 :   NS_ENSURE_SUCCESS(rv, 0);
     624           0 :   return static_cast<int32_t>(read);
     625             : }
     626             : 
     627             : // RIFFParser
     628             : 
     629             : uint32_t
     630           0 : RIFFParser::Parse(ByteReader& aReader)
     631             : {
     632           0 :   while (aReader.CanRead8() && !mRiffHeader.ParseNext(aReader.ReadU8())) { }
     633             : 
     634           0 :   if (mRiffHeader.IsValid()) {
     635           0 :     return RIFF_CHUNK_SIZE;
     636             :   }
     637             : 
     638           0 :   return 0;
     639             : }
     640             : 
     641             : void
     642           0 : RIFFParser::Reset()
     643             : {
     644           0 :   mRiffHeader.Reset();
     645           0 : }
     646             : 
     647             : const RIFFParser::RIFFHeader&
     648           0 : RIFFParser::RiffHeader() const
     649             : {
     650           0 :   return mRiffHeader;
     651             : }
     652             : 
     653             : // RIFFParser::RIFFHeader
     654             : 
     655           0 : RIFFParser::RIFFHeader::RIFFHeader()
     656             : {
     657           0 :   Reset();
     658           0 : }
     659             : 
     660             : void
     661           0 : RIFFParser::RIFFHeader::Reset()
     662             : {
     663           0 :   memset(mRaw, 0, sizeof(mRaw));
     664           0 :   mPos = 0;
     665           0 : }
     666             : 
     667             : bool
     668           0 : RIFFParser::RIFFHeader::ParseNext(uint8_t c)
     669             : {
     670           0 :   if (!Update(c)) {
     671           0 :     Reset();
     672           0 :     if (!Update(c)) {
     673           0 :       Reset();
     674             :     }
     675             :   }
     676           0 :   return IsValid();
     677             : }
     678             : 
     679             : bool
     680           0 : RIFFParser::RIFFHeader::IsValid(int aPos) const
     681             : {
     682           0 :   if (aPos > -1 && aPos < 4) {
     683           0 :     return RIFF[aPos] == mRaw[aPos];
     684           0 :   } else if (aPos > 7 && aPos < 12) {
     685           0 :     return WAVE[aPos - 8] == mRaw[aPos];
     686             :   } else {
     687           0 :     return true;
     688             :   }
     689             : }
     690             : 
     691             : bool
     692           0 : RIFFParser::RIFFHeader::IsValid() const
     693             : {
     694           0 :   return mPos >= RIFF_CHUNK_SIZE;
     695             : }
     696             : 
     697             : bool
     698           0 : RIFFParser::RIFFHeader::Update(uint8_t c)
     699             : {
     700           0 :   if (mPos < RIFF_CHUNK_SIZE) {
     701           0 :     mRaw[mPos] = c;
     702             :   }
     703           0 :   return IsValid(mPos++);
     704             : }
     705             : 
     706             : // HeaderParser
     707             : 
     708             : uint32_t
     709           0 : HeaderParser::Parse(ByteReader& aReader)
     710             : {
     711           0 :   while (aReader.CanRead8() && !mHeader.ParseNext(aReader.ReadU8())) { }
     712             : 
     713           0 :   if (mHeader.IsValid()) {
     714           0 :     return CHUNK_HEAD_SIZE;
     715             :   }
     716             : 
     717           0 :   return 0;
     718             : }
     719             : 
     720             : void
     721           0 : HeaderParser::Reset()
     722             : {
     723           0 :   mHeader.Reset();
     724           0 : }
     725             : 
     726             : const HeaderParser::ChunkHeader&
     727           0 : HeaderParser::GiveHeader() const
     728             : {
     729           0 :   return mHeader;
     730             : }
     731             : 
     732             : // HeaderParser::ChunkHeader
     733             : 
     734           0 : HeaderParser::ChunkHeader::ChunkHeader()
     735             : {
     736           0 :   Reset();
     737           0 : }
     738             : 
     739             : void
     740           0 : HeaderParser::ChunkHeader::Reset()
     741             : {
     742           0 :   memset(mRaw, 0, sizeof(mRaw));
     743           0 :   mPos = 0;
     744           0 : }
     745             : 
     746             : bool
     747           0 : HeaderParser::ChunkHeader::ParseNext(uint8_t c)
     748             : {
     749           0 :   Update(c);
     750           0 :   return IsValid();
     751             : }
     752             : 
     753             : bool
     754           0 : HeaderParser::ChunkHeader::IsValid() const
     755             : {
     756           0 :   return mPos >= CHUNK_HEAD_SIZE;
     757             : }
     758             : 
     759             : uint32_t
     760           0 : HeaderParser::ChunkHeader::ChunkName() const
     761             : {
     762           0 :   return ((mRaw[0] << 24)
     763           0 :           | (mRaw[1] << 16)
     764           0 :           | (mRaw[2] << 8 )
     765           0 :           | (mRaw[3]));
     766             : }
     767             : 
     768             : uint32_t
     769           0 : HeaderParser::ChunkHeader::ChunkSize() const
     770             : {
     771           0 :   return ((mRaw[7] << 24)
     772           0 :           | (mRaw[6] << 16)
     773           0 :           | (mRaw[5] << 8 )
     774           0 :           | (mRaw[4]));
     775             : }
     776             : 
     777             : void
     778           0 : HeaderParser::ChunkHeader::Update(uint8_t c)
     779             : {
     780           0 :   if (mPos < CHUNK_HEAD_SIZE) {
     781           0 :     mRaw[mPos++] = c;
     782             :   }
     783           0 : }
     784             : 
     785             : // FormatParser
     786             : 
     787             : uint32_t
     788           0 : FormatParser::Parse(ByteReader& aReader)
     789             : {
     790           0 :   while (aReader.CanRead8() && !mFmtChunk.ParseNext(aReader.ReadU8())) { }
     791             : 
     792           0 :   if (mFmtChunk.IsValid()) {
     793           0 :     return FMT_CHUNK_MIN_SIZE;
     794             :   }
     795             : 
     796           0 :   return 0;
     797             : }
     798             : 
     799             : void
     800           0 : FormatParser::Reset()
     801             : {
     802           0 :   mFmtChunk.Reset();
     803           0 : }
     804             : 
     805             : const FormatParser::FormatChunk&
     806           0 : FormatParser::FmtChunk() const
     807             : {
     808           0 :   return mFmtChunk;
     809             : }
     810             : 
     811             : // FormatParser::FormatChunk
     812             : 
     813           0 : FormatParser::FormatChunk::FormatChunk()
     814             : {
     815           0 :   Reset();
     816           0 : }
     817             : 
     818             : void
     819           0 : FormatParser::FormatChunk::Reset()
     820             : {
     821           0 :   memset(mRaw, 0, sizeof(mRaw));
     822           0 :   mPos = 0;
     823           0 : }
     824             : 
     825             : uint16_t
     826           0 : FormatParser::FormatChunk::WaveFormat() const
     827             : {
     828           0 :   return (mRaw[1] << 8) | (mRaw[0]);
     829             : }
     830             : 
     831             : uint16_t
     832           0 : FormatParser::FormatChunk::Channels() const
     833             : {
     834           0 :   return (mRaw[3] << 8) | (mRaw[2]);
     835             : }
     836             : 
     837             : uint32_t
     838           0 : FormatParser::FormatChunk::SampleRate() const
     839             : {
     840           0 :   return (mRaw[7] << 24)
     841           0 :          | (mRaw[6] << 16)
     842           0 :          | (mRaw[5] << 8)
     843           0 :          | (mRaw[4]);
     844             : }
     845             : 
     846             : uint16_t
     847           0 : FormatParser::FormatChunk::FrameSize() const
     848             : {
     849           0 :   return (mRaw[13] << 8) | (mRaw[12]);
     850             : }
     851             : 
     852             : uint16_t
     853           0 : FormatParser::FormatChunk::SampleFormat() const
     854             : {
     855           0 :   return (mRaw[15] << 8) | (mRaw[14]);
     856             : }
     857             : 
     858             : bool
     859           0 : FormatParser::FormatChunk::ParseNext(uint8_t c)
     860             : {
     861           0 :   Update(c);
     862           0 :   return IsValid();
     863             : }
     864             : 
     865             : bool
     866           0 : FormatParser::FormatChunk::IsValid() const
     867             : {
     868           0 :   return (FrameSize() == SampleRate() * Channels() / 8)
     869           0 :          && (mPos >= FMT_CHUNK_MIN_SIZE);
     870             : }
     871             : 
     872             : void
     873           0 : FormatParser::FormatChunk::Update(uint8_t c)
     874             : {
     875           0 :   if (mPos < FMT_CHUNK_MIN_SIZE) {
     876           0 :     mRaw[mPos++] = c;
     877             :   }
     878           0 : }
     879             : 
     880             : // DataParser
     881             : 
     882           0 : DataParser::DataParser()
     883             : {
     884           0 : }
     885             : 
     886             : void
     887           0 : DataParser::Reset()
     888             : {
     889           0 :   mChunk.Reset();
     890           0 : }
     891             : 
     892             : const DataParser::DataChunk&
     893           0 : DataParser::CurrentChunk() const
     894             : {
     895           0 :   return mChunk;
     896             : }
     897             : 
     898             : // DataParser::DataChunk
     899             : 
     900             : void
     901           0 : DataParser::DataChunk::Reset()
     902             : {
     903           0 :   mPos = 0;
     904           0 : }
     905             : 
     906             : } // namespace mozilla

Generated by: LCOV version 1.13