LCOV - code coverage report
Current view: top level - dom/media/fmp4 - MP4Demuxer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 307 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 27 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 <algorithm>
       8             : #include <limits>
       9             : #include <stdint.h>
      10             : 
      11             : #include "MP4Demuxer.h"
      12             : 
      13             : #include "MediaPrefs.h"
      14             : // Used for telemetry
      15             : #include "mozilla/Telemetry.h"
      16             : #include "mp4_demuxer/AnnexB.h"
      17             : #include "mp4_demuxer/H264.h"
      18             : #include "mp4_demuxer/MoofParser.h"
      19             : #include "mp4_demuxer/MP4Metadata.h"
      20             : #include "mp4_demuxer/ResourceStream.h"
      21             : #include "mp4_demuxer/BufferStream.h"
      22             : #include "mp4_demuxer/Index.h"
      23             : #include "nsAutoPtr.h"
      24             : #include "nsPrintfCString.h"
      25             : 
      26             : extern mozilla::LazyLogModule gMediaDemuxerLog;
      27           0 : mozilla::LogModule* GetDemuxerLog()
      28             : {
      29           0 :   return gMediaDemuxerLog;
      30             : }
      31             : 
      32             : #define LOG(arg, ...) MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("MP4Demuxer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      33             : 
      34             : namespace mozilla {
      35             : 
      36           0 : class MP4TrackDemuxer : public MediaTrackDemuxer
      37             : {
      38             : public:
      39             :   MP4TrackDemuxer(MP4Demuxer* aParent,
      40             :                   UniquePtr<TrackInfo>&& aInfo,
      41             :                   const mp4_demuxer::IndiceWrapper& aIndices);
      42             : 
      43             :   UniquePtr<TrackInfo> GetInfo() const override;
      44             : 
      45             :   RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
      46             : 
      47             :   RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
      48             : 
      49             :   void Reset() override;
      50             : 
      51             :   nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;
      52             : 
      53             :   RefPtr<SkipAccessPointPromise>
      54             :   SkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreshold) override;
      55             : 
      56             :   media::TimeIntervals GetBuffered() override;
      57             : 
      58             :   void BreakCycles() override;
      59             : 
      60             :   void NotifyDataRemoved();
      61             : 
      62             : private:
      63             :   friend class MP4Demuxer;
      64             :   void NotifyDataArrived();
      65             :   already_AddRefed<MediaRawData> GetNextSample();
      66             :   void EnsureUpToDateIndex();
      67             :   void SetNextKeyFrameTime();
      68             :   RefPtr<MP4Demuxer> mParent;
      69             :   RefPtr<mp4_demuxer::ResourceStream> mStream;
      70             :   UniquePtr<TrackInfo> mInfo;
      71             :   RefPtr<mp4_demuxer::Index> mIndex;
      72             :   UniquePtr<mp4_demuxer::SampleIterator> mIterator;
      73             :   Maybe<media::TimeUnit> mNextKeyframeTime;
      74             :   // Queued samples extracted by the demuxer, but not yet returned.
      75             :   RefPtr<MediaRawData> mQueuedSample;
      76             :   bool mNeedReIndex;
      77             :   bool mNeedSPSForTelemetry;
      78             :   bool mIsH264 = false;
      79             : };
      80             : 
      81             : 
      82             : // Returns true if no SPS was found and search for it should continue.
      83             : bool
      84           0 : AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
      85             : {
      86           0 :   mp4_demuxer::SPSData spsdata;
      87           0 :   if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
      88           0 :     uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0)
      89           0 :                           | (spsdata.constraint_set1_flag ? (1 << 1) : 0)
      90           0 :                           | (spsdata.constraint_set2_flag ? (1 << 2) : 0)
      91           0 :                           | (spsdata.constraint_set3_flag ? (1 << 3) : 0)
      92           0 :                           | (spsdata.constraint_set4_flag ? (1 << 4) : 0)
      93           0 :                           | (spsdata.constraint_set5_flag ? (1 << 5) : 0);
      94           0 :     Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
      95           0 :                           constraints);
      96             : 
      97             :     // Collect profile_idc values up to 244, otherwise 0 for unknown.
      98           0 :     Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE,
      99           0 :                           spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0);
     100             : 
     101             :     // Make sure level_idc represents a value between levels 1 and 5.2,
     102             :     // otherwise collect 0 for unknown level.
     103           0 :     Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
     104           0 :                           (spsdata.level_idc >= 10 && spsdata.level_idc <= 52)
     105           0 :                           ? spsdata.level_idc
     106           0 :                           : 0);
     107             : 
     108             :     // max_num_ref_frames should be between 0 and 16, anything larger will
     109             :     // be treated as invalid.
     110           0 :     Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES,
     111           0 :                           std::min(spsdata.max_num_ref_frames, 17u));
     112             : 
     113           0 :     return false;
     114             :   }
     115             : 
     116           0 :   return true;
     117             : }
     118             : 
     119           0 : MP4Demuxer::MP4Demuxer(MediaResource* aResource)
     120             :   : mResource(aResource)
     121           0 :   , mStream(new mp4_demuxer::ResourceStream(aResource))
     122             : {
     123           0 : }
     124             : 
     125             : RefPtr<MP4Demuxer::InitPromise>
     126           0 : MP4Demuxer::Init()
     127             : {
     128           0 :   AutoPinned<mp4_demuxer::ResourceStream> stream(mStream);
     129             : 
     130             :   // 'result' will capture the first warning, if any.
     131           0 :   MediaResult result{NS_OK};
     132             : 
     133             :   mp4_demuxer::MP4Metadata::ResultAndByteBuffer initData =
     134           0 :     mp4_demuxer::MP4Metadata::Metadata(stream);
     135           0 :   if (!initData.Ref()) {
     136             :     return InitPromise::CreateAndReject(
     137           0 :       NS_FAILED(initData.Result())
     138           0 :       ? Move(initData.Result())
     139             :       : MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     140           0 :                     RESULT_DETAIL("Invalid MP4 metadata or OOM")),
     141           0 :       __func__);
     142           0 :   } else if (NS_FAILED(initData.Result()) && result == NS_OK) {
     143           0 :     result = Move(initData.Result());
     144             :   }
     145             : 
     146             :   RefPtr<mp4_demuxer::BufferStream> bufferstream =
     147           0 :     new mp4_demuxer::BufferStream(initData.Ref());
     148             : 
     149           0 :   mp4_demuxer::MP4Metadata metadata{bufferstream};
     150             : 
     151           0 :   auto audioTrackCount = metadata.GetNumberTracks(TrackInfo::kAudioTrack);
     152           0 :   if (audioTrackCount.Ref() == mp4_demuxer::MP4Metadata::NumberTracksError()) {
     153           0 :     if (MediaPrefs::MediaWarningsAsErrors()) {
     154             :       return InitPromise::CreateAndReject(
     155           0 :         MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     156           0 :                     RESULT_DETAIL("Invalid audio track (%s)",
     157             :                                   audioTrackCount.Result().Description().get())),
     158           0 :         __func__);
     159             :     }
     160           0 :     audioTrackCount.Ref() = 0;
     161             :   }
     162             : 
     163           0 :   auto videoTrackCount = metadata.GetNumberTracks(TrackInfo::kVideoTrack);
     164           0 :   if (videoTrackCount.Ref() == mp4_demuxer::MP4Metadata::NumberTracksError()) {
     165           0 :     if (MediaPrefs::MediaWarningsAsErrors()) {
     166             :       return InitPromise::CreateAndReject(
     167           0 :         MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     168           0 :                     RESULT_DETAIL("Invalid video track (%s)",
     169             :                                   videoTrackCount.Result().Description().get())),
     170           0 :         __func__);
     171             :     }
     172           0 :     videoTrackCount.Ref() = 0;
     173             :   }
     174             : 
     175           0 :   if (audioTrackCount.Ref() == 0 && videoTrackCount.Ref() == 0) {
     176             :     return InitPromise::CreateAndReject(
     177           0 :       MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     178           0 :                   RESULT_DETAIL("No MP4 audio (%s) or video (%s) tracks",
     179             :                                 audioTrackCount.Result().Description().get(),
     180             :                                 videoTrackCount.Result().Description().get())),
     181           0 :       __func__);
     182             :   }
     183             : 
     184           0 :   if (NS_FAILED(audioTrackCount.Result()) && result == NS_OK) {
     185           0 :     result = Move(audioTrackCount.Result());
     186             :   }
     187           0 :   if (NS_FAILED(videoTrackCount.Result()) && result == NS_OK) {
     188           0 :     result = Move(videoTrackCount.Result());
     189             :   }
     190             : 
     191           0 :   if (audioTrackCount.Ref() != 0) {
     192           0 :     for (size_t i = 0; i < audioTrackCount.Ref(); i++) {
     193             :       mp4_demuxer::MP4Metadata::ResultAndTrackInfo info =
     194           0 :         metadata.GetTrackInfo(TrackInfo::kAudioTrack, i);
     195           0 :       if (!info.Ref()) {
     196           0 :         if (MediaPrefs::MediaWarningsAsErrors()) {
     197             :           return InitPromise::CreateAndReject(
     198           0 :             MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     199           0 :                         RESULT_DETAIL("Invalid MP4 audio track (%s)",
     200             :                                       info.Result().Description().get())),
     201           0 :             __func__);
     202             :         }
     203           0 :         if (result == NS_OK) {
     204           0 :           result = MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     205           0 :                                RESULT_DETAIL("Invalid MP4 audio track (%s)",
     206           0 :                                              info.Result().Description().get()));
     207             :         }
     208           0 :         continue;
     209           0 :       } else if (NS_FAILED(info.Result()) && result == NS_OK) {
     210           0 :         result = Move(info.Result());
     211             :       }
     212             :       mp4_demuxer::MP4Metadata::ResultAndIndice indices =
     213           0 :         metadata.GetTrackIndice(info.Ref()->mTrackId);
     214           0 :       if (!indices.Ref()) {
     215           0 :         if (NS_FAILED(info.Result()) && result == NS_OK) {
     216           0 :           result = Move(indices.Result());
     217             :         }
     218           0 :         continue;
     219             :       }
     220           0 :       mAudioDemuxers.AppendElement(
     221           0 :         new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get()));
     222             :     }
     223             :   }
     224             : 
     225           0 :   if (videoTrackCount.Ref() != 0) {
     226           0 :     for (size_t i = 0; i < videoTrackCount.Ref(); i++) {
     227             :       mp4_demuxer::MP4Metadata::ResultAndTrackInfo info =
     228           0 :         metadata.GetTrackInfo(TrackInfo::kVideoTrack, i);
     229           0 :       if (!info.Ref()) {
     230           0 :         if (MediaPrefs::MediaWarningsAsErrors()) {
     231             :           return InitPromise::CreateAndReject(
     232           0 :             MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     233           0 :                         RESULT_DETAIL("Invalid MP4 video track (%s)",
     234             :                                       info.Result().Description().get())),
     235           0 :             __func__);
     236             :         }
     237           0 :         if (result == NS_OK) {
     238           0 :           result = MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     239           0 :                                RESULT_DETAIL("Invalid MP4 video track (%s)",
     240           0 :                                              info.Result().Description().get()));
     241             :         }
     242           0 :         continue;
     243           0 :       } else if (NS_FAILED(info.Result()) && result == NS_OK) {
     244           0 :         result = Move(info.Result());
     245             :       }
     246             :       mp4_demuxer::MP4Metadata::ResultAndIndice indices =
     247           0 :         metadata.GetTrackIndice(info.Ref()->mTrackId);
     248           0 :       if (!indices.Ref()) {
     249           0 :         if (NS_FAILED(info.Result()) && result == NS_OK) {
     250           0 :           result = Move(indices.Result());
     251             :         }
     252           0 :         continue;
     253             :       }
     254           0 :       mVideoDemuxers.AppendElement(
     255           0 :         new MP4TrackDemuxer(this, Move(info.Ref()), *indices.Ref().get()));
     256             :     }
     257             :   }
     258             : 
     259             :   mp4_demuxer::MP4Metadata::ResultAndCryptoFile cryptoFile =
     260           0 :     metadata.Crypto();
     261           0 :   if (NS_FAILED(cryptoFile.Result()) && result == NS_OK) {
     262           0 :     result = Move(cryptoFile.Result());
     263             :   }
     264           0 :   MOZ_ASSERT(cryptoFile.Ref());
     265           0 :   if (cryptoFile.Ref()->valid) {
     266           0 :     const nsTArray<mp4_demuxer::PsshInfo>& psshs = cryptoFile.Ref()->pssh;
     267           0 :     for (uint32_t i = 0; i < psshs.Length(); i++) {
     268           0 :       mCryptoInitData.AppendElements(psshs[i].data);
     269             :     }
     270             :   }
     271             : 
     272           0 :   mIsSeekable = metadata.CanSeek();
     273             : 
     274           0 :   return InitPromise::CreateAndResolve(result, __func__);
     275             : }
     276             : 
     277             : bool
     278           0 : MP4Demuxer::HasTrackType(TrackInfo::TrackType aType) const
     279             : {
     280           0 :   return GetNumberTracks(aType) != 0;
     281             : }
     282             : 
     283             : uint32_t
     284           0 : MP4Demuxer::GetNumberTracks(TrackInfo::TrackType aType) const
     285             : {
     286           0 :   switch (aType) {
     287           0 :     case TrackInfo::kAudioTrack: return uint32_t(mAudioDemuxers.Length());
     288           0 :     case TrackInfo::kVideoTrack: return uint32_t(mVideoDemuxers.Length());
     289           0 :     default: return 0;
     290             :   }
     291             : }
     292             : 
     293             : already_AddRefed<MediaTrackDemuxer>
     294           0 : MP4Demuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
     295             : {
     296           0 :   switch (aType) {
     297             :     case TrackInfo::kAudioTrack:
     298           0 :       if (aTrackNumber >= uint32_t(mAudioDemuxers.Length())) {
     299           0 :         return nullptr;
     300             :       }
     301           0 :       return RefPtr<MediaTrackDemuxer>(mAudioDemuxers[aTrackNumber]).forget();
     302             :     case TrackInfo::kVideoTrack:
     303           0 :       if (aTrackNumber >= uint32_t(mVideoDemuxers.Length())) {
     304           0 :         return nullptr;
     305             :       }
     306           0 :       return RefPtr<MediaTrackDemuxer>(mVideoDemuxers[aTrackNumber]).forget();
     307             :     default:
     308           0 :       return nullptr;
     309             :   }
     310             : }
     311             : 
     312             : bool
     313           0 : MP4Demuxer::IsSeekable() const
     314             : {
     315           0 :   return mIsSeekable;
     316             : }
     317             : 
     318             : void
     319           0 : MP4Demuxer::NotifyDataArrived()
     320             : {
     321           0 :   for (auto& dmx : mAudioDemuxers) {
     322           0 :     dmx->NotifyDataArrived();
     323             :   }
     324           0 :   for (auto& dmx : mVideoDemuxers) {
     325           0 :     dmx->NotifyDataArrived();
     326             :   }
     327           0 : }
     328             : 
     329             : void
     330           0 : MP4Demuxer::NotifyDataRemoved()
     331             : {
     332           0 :   for (auto& dmx : mAudioDemuxers) {
     333           0 :     dmx->NotifyDataRemoved();
     334             :   }
     335           0 :   for (auto& dmx : mVideoDemuxers) {
     336           0 :     dmx->NotifyDataRemoved();
     337             :   }
     338           0 : }
     339             : 
     340             : UniquePtr<EncryptionInfo>
     341           0 : MP4Demuxer::GetCrypto()
     342             : {
     343           0 :   UniquePtr<EncryptionInfo> crypto;
     344           0 :   if (!mCryptoInitData.IsEmpty()) {
     345           0 :     crypto.reset(new EncryptionInfo{});
     346           0 :     crypto->AddInitData(NS_LITERAL_STRING("cenc"), mCryptoInitData);
     347             :   }
     348           0 :   return crypto;
     349             : }
     350             : 
     351           0 : MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
     352             :                                  UniquePtr<TrackInfo>&& aInfo,
     353           0 :                                  const mp4_demuxer::IndiceWrapper& aIndices)
     354             :   : mParent(aParent)
     355           0 :   , mStream(new mp4_demuxer::ResourceStream(mParent->mResource))
     356           0 :   , mInfo(Move(aInfo))
     357             :   , mIndex(new mp4_demuxer::Index(aIndices,
     358             :                                   mStream,
     359           0 :                                   mInfo->mTrackId,
     360           0 :                                   mInfo->IsAudio()))
     361             :   , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex))
     362           0 :   , mNeedReIndex(true)
     363             : {
     364           0 :   EnsureUpToDateIndex(); // Force update of index
     365             : 
     366           0 :   VideoInfo* videoInfo = mInfo->GetAsVideoInfo();
     367             :   // Collect telemetry from h264 AVCC SPS.
     368           0 :   if (videoInfo
     369           0 :       && (mInfo->mMimeType.EqualsLiteral("video/mp4")
     370           0 :           || mInfo->mMimeType.EqualsLiteral("video/avc"))) {
     371           0 :     mIsH264 = true;
     372           0 :     RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData;
     373           0 :     mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData);
     374           0 :     mp4_demuxer::SPSData spsdata;
     375           0 :     if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata)
     376           0 :         && spsdata.pic_width > 0 && spsdata.pic_height > 0
     377           0 :         && mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
     378           0 :       videoInfo->mImage.width = spsdata.pic_width;
     379           0 :       videoInfo->mImage.height = spsdata.pic_height;
     380           0 :       videoInfo->mDisplay.width = spsdata.display_width;
     381           0 :       videoInfo->mDisplay.height = spsdata.display_height;
     382             :     }
     383             :   } else {
     384             :     // No SPS to be found.
     385           0 :     mNeedSPSForTelemetry = false;
     386             :   }
     387           0 : }
     388             : 
     389             : UniquePtr<TrackInfo>
     390           0 : MP4TrackDemuxer::GetInfo() const
     391             : {
     392           0 :   return mInfo->Clone();
     393             : }
     394             : 
     395             : void
     396           0 : MP4TrackDemuxer::EnsureUpToDateIndex()
     397             : {
     398           0 :   if (!mNeedReIndex) {
     399           0 :     return;
     400             :   }
     401           0 :   AutoPinned<MediaResource> resource(mParent->mResource);
     402           0 :   MediaByteRangeSet byteRanges;
     403           0 :   nsresult rv = resource->GetCachedRanges(byteRanges);
     404           0 :   if (NS_FAILED(rv)) {
     405           0 :     return;
     406             :   }
     407           0 :   mIndex->UpdateMoofIndex(byteRanges);
     408           0 :   mNeedReIndex = false;
     409             : }
     410             : 
     411             : RefPtr<MP4TrackDemuxer::SeekPromise>
     412           0 : MP4TrackDemuxer::Seek(const media::TimeUnit& aTime)
     413             : {
     414           0 :   auto seekTime = aTime;
     415           0 :   mQueuedSample = nullptr;
     416             : 
     417           0 :   mIterator->Seek(seekTime.ToMicroseconds());
     418             : 
     419             :   // Check what time we actually seeked to.
     420           0 :   mQueuedSample = GetNextSample();
     421           0 :   if (mQueuedSample) {
     422           0 :     seekTime = mQueuedSample->mTime;
     423             :   }
     424             : 
     425           0 :   SetNextKeyFrameTime();
     426             : 
     427           0 :   return SeekPromise::CreateAndResolve(seekTime, __func__);
     428             : }
     429             : 
     430             : already_AddRefed<MediaRawData>
     431           0 : MP4TrackDemuxer::GetNextSample()
     432             : {
     433           0 :   RefPtr<MediaRawData> sample = mIterator->GetNext();
     434           0 :   if (!sample) {
     435           0 :     return nullptr;
     436             :   }
     437           0 :   if (mInfo->GetAsVideoInfo()) {
     438           0 :     sample->mExtraData = mInfo->GetAsVideoInfo()->mExtraData;
     439           0 :     if (mIsH264) {
     440             :       mp4_demuxer::H264::FrameType type =
     441           0 :         mp4_demuxer::H264::GetFrameType(sample);
     442           0 :       switch (type) {
     443             :         case mp4_demuxer::H264::FrameType::I_FRAME: MOZ_FALLTHROUGH;
     444             :         case mp4_demuxer::H264::FrameType::OTHER:
     445             :         {
     446           0 :           bool keyframe = type == mp4_demuxer::H264::FrameType::I_FRAME;
     447           0 :           if (sample->mKeyframe != keyframe) {
     448           0 :             NS_WARNING(nsPrintfCString("Frame incorrectly marked as %skeyframe "
     449             :                                        "@ pts:%" PRId64 " dur:%" PRId64
     450             :                                        " dts:%" PRId64,
     451             :                                        keyframe ? "" : "non-",
     452             :                                        sample->mTime.ToMicroseconds(),
     453             :                                        sample->mDuration.ToMicroseconds(),
     454             :                                        sample->mTimecode.ToMicroseconds())
     455           0 :                          .get());
     456           0 :             sample->mKeyframe = keyframe;
     457             :           }
     458           0 :           break;
     459             :         }
     460             :         case mp4_demuxer::H264::FrameType::INVALID:
     461           0 :           NS_WARNING(
     462             :             nsPrintfCString("Invalid H264 frame @ pts:%" PRId64 " dur:%" PRId64
     463             :                             " dts:%" PRId64,
     464             :                             sample->mTime.ToMicroseconds(),
     465             :                             sample->mDuration.ToMicroseconds(),
     466             :                             sample->mTimecode.ToMicroseconds())
     467           0 :               .get());
     468             :           // We could reject the sample now, however demuxer errors are fatal.
     469             :           // So we keep the invalid frame, relying on the H264 decoder to
     470             :           // handle the error later.
     471             :           // TODO: make demuxer errors non-fatal.
     472           0 :           break;
     473             :       }
     474             :     }
     475             :   }
     476             : 
     477           0 :   if (sample->mCrypto.mValid) {
     478           0 :     nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
     479           0 :     writer->mCrypto.mMode = mInfo->mCrypto.mMode;
     480             : 
     481             :     // Only use the default key parsed from the moov if we haven't already got
     482             :     // one from the sample group description.
     483           0 :     if (writer->mCrypto.mKeyId.Length() == 0) {
     484           0 :       writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
     485           0 :       writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
     486             :     }
     487             :   }
     488           0 :   return sample.forget();
     489             : }
     490             : 
     491             : RefPtr<MP4TrackDemuxer::SamplesPromise>
     492           0 : MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
     493             : {
     494           0 :   EnsureUpToDateIndex();
     495           0 :   RefPtr<SamplesHolder> samples = new SamplesHolder;
     496           0 :   if (!aNumSamples) {
     497             :     return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
     498           0 :                                            __func__);
     499             :   }
     500             : 
     501           0 :   if (mQueuedSample) {
     502           0 :     NS_ASSERTION(mQueuedSample->mKeyframe,
     503             :                  "mQueuedSample must be a keyframe");
     504           0 :     samples->mSamples.AppendElement(mQueuedSample);
     505           0 :     mQueuedSample = nullptr;
     506           0 :     aNumSamples--;
     507             :   }
     508           0 :   RefPtr<MediaRawData> sample;
     509           0 :   while (aNumSamples && (sample = GetNextSample())) {
     510           0 :     if (!sample->Size()) {
     511           0 :       continue;
     512             :     }
     513           0 :     samples->mSamples.AppendElement(sample);
     514           0 :     aNumSamples--;
     515             :   }
     516             : 
     517           0 :   if (samples->mSamples.IsEmpty()) {
     518             :     return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
     519           0 :                                            __func__);
     520             :   }
     521           0 :   for (const auto& sample : samples->mSamples) {
     522             :     // Collect telemetry from h264 Annex B SPS.
     523           0 :     if (mNeedSPSForTelemetry && mIsH264 &&
     524           0 :         mp4_demuxer::AnnexB::IsAVCC(sample)) {
     525             :       RefPtr<MediaByteBuffer> extradata =
     526           0 :         mp4_demuxer::H264::ExtractExtraData(sample);
     527           0 :       if (mp4_demuxer::H264::HasSPS(extradata)) {
     528             :         RefPtr<MediaByteBuffer> extradata =
     529           0 :           mp4_demuxer::H264::ExtractExtraData(sample);
     530           0 :         mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata);
     531             :       }
     532             :     }
     533             :   }
     534             : 
     535           0 :   if (mNextKeyframeTime.isNothing()
     536           0 :       || samples->mSamples.LastElement()->mTime
     537           0 :       >= mNextKeyframeTime.value()) {
     538           0 :     SetNextKeyFrameTime();
     539             :   }
     540           0 :   return SamplesPromise::CreateAndResolve(samples, __func__);
     541             : }
     542             : 
     543             : void
     544           0 : MP4TrackDemuxer::SetNextKeyFrameTime()
     545             : {
     546           0 :   mNextKeyframeTime.reset();
     547           0 :   mp4_demuxer::Microseconds frameTime = mIterator->GetNextKeyframeTime();
     548           0 :   if (frameTime != -1) {
     549           0 :     mNextKeyframeTime.emplace(
     550           0 :       media::TimeUnit::FromMicroseconds(frameTime));
     551             :   }
     552           0 : }
     553             : 
     554             : void
     555           0 : MP4TrackDemuxer::Reset()
     556             : {
     557           0 :   mQueuedSample = nullptr;
     558             :   // TODO, Seek to first frame available, which isn't always 0.
     559           0 :   mIterator->Seek(0);
     560           0 :   SetNextKeyFrameTime();
     561           0 : }
     562             : 
     563             : nsresult
     564           0 : MP4TrackDemuxer::GetNextRandomAccessPoint(media::TimeUnit* aTime)
     565             : {
     566           0 :   if (mNextKeyframeTime.isNothing()) {
     567             :     // There's no next key frame.
     568           0 :     *aTime = media::TimeUnit::FromInfinity();
     569             :   } else {
     570           0 :     *aTime = mNextKeyframeTime.value();
     571             :   }
     572           0 :   return NS_OK;
     573             : }
     574             : 
     575             : RefPtr<MP4TrackDemuxer::SkipAccessPointPromise>
     576           0 : MP4TrackDemuxer::SkipToNextRandomAccessPoint(
     577             :   const media::TimeUnit& aTimeThreshold)
     578             : {
     579           0 :   mQueuedSample = nullptr;
     580             :   // Loop until we reach the next keyframe after the threshold.
     581           0 :   uint32_t parsed = 0;
     582           0 :   bool found = false;
     583           0 :   RefPtr<MediaRawData> sample;
     584           0 :   while (!found && (sample = GetNextSample())) {
     585           0 :     parsed++;
     586           0 :     if (sample->mKeyframe && sample->mTime >= aTimeThreshold) {
     587           0 :       found = true;
     588           0 :       mQueuedSample = sample;
     589             :     }
     590             :   }
     591           0 :   SetNextKeyFrameTime();
     592           0 :   if (found) {
     593           0 :     return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
     594             :   }
     595           0 :   SkipFailureHolder failure(NS_ERROR_DOM_MEDIA_END_OF_STREAM, parsed);
     596           0 :   return SkipAccessPointPromise::CreateAndReject(Move(failure), __func__);
     597             : }
     598             : 
     599             : media::TimeIntervals
     600           0 : MP4TrackDemuxer::GetBuffered()
     601             : {
     602           0 :   EnsureUpToDateIndex();
     603           0 :   AutoPinned<MediaResource> resource(mParent->mResource);
     604           0 :   MediaByteRangeSet byteRanges;
     605           0 :   nsresult rv = resource->GetCachedRanges(byteRanges);
     606             : 
     607           0 :   if (NS_FAILED(rv)) {
     608           0 :     return media::TimeIntervals();
     609             :   }
     610             : 
     611           0 :   return mIndex->ConvertByteRangesToTimeRanges(byteRanges);
     612             : }
     613             : 
     614             : void
     615           0 : MP4TrackDemuxer::NotifyDataArrived()
     616             : {
     617           0 :   mNeedReIndex = true;
     618           0 : }
     619             : 
     620             : void
     621           0 : MP4TrackDemuxer::NotifyDataRemoved()
     622             : {
     623           0 :   AutoPinned<MediaResource> resource(mParent->mResource);
     624           0 :   MediaByteRangeSet byteRanges;
     625           0 :   nsresult rv = resource->GetCachedRanges(byteRanges);
     626           0 :   if (NS_FAILED(rv)) {
     627           0 :     return;
     628             :   }
     629           0 :   mIndex->UpdateMoofIndex(byteRanges, true /* can evict */);
     630           0 :   mNeedReIndex = false;
     631             : }
     632             : 
     633             : void
     634           0 : MP4TrackDemuxer::BreakCycles()
     635             : {
     636           0 :   mParent = nullptr;
     637           0 : }
     638             : 
     639             : } // namespace mozilla
     640             : 
     641             : #undef LOG

Generated by: LCOV version 1.13