LCOV - code coverage report
Current view: top level - dom/media - MediaFormatReader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 1688 0.1 %
Date: 2017-07-14 16:53:18 Functions: 0 272 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 "MediaFormatReader.h"
       8             : 
       9             : #include "AutoTaskQueue.h"
      10             : #include "Layers.h"
      11             : #include "MediaData.h"
      12             : #include "MediaInfo.h"
      13             : #include "MediaResource.h"
      14             : #include "VideoFrameContainer.h"
      15             : #include "VideoUtils.h"
      16             : #include "mozilla/AbstractThread.h"
      17             : #include "mozilla/CDMProxy.h"
      18             : #include "mozilla/ClearOnShutdown.h"
      19             : #include "mozilla/Preferences.h"
      20             : #include "mozilla/SharedThreadPool.h"
      21             : #include "mozilla/SizePrintfMacros.h"
      22             : #include "mozilla/SyncRunnable.h"
      23             : #include "mozilla/Telemetry.h"
      24             : #include "mozilla/Unused.h"
      25             : #include "mozilla/dom/HTMLMediaElement.h"
      26             : #include "mozilla/layers/ShadowLayers.h"
      27             : #include "nsContentUtils.h"
      28             : #include "nsPrintfCString.h"
      29             : #include "nsSize.h"
      30             : 
      31             : #include <algorithm>
      32             : #include <queue>
      33             : 
      34             : using namespace mozilla::media;
      35             : 
      36             : using mozilla::layers::Image;
      37             : using mozilla::layers::LayerManager;
      38             : using mozilla::layers::LayersBackend;
      39             : 
      40             : static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
      41             : mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");
      42             : 
      43             : #define LOG(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      44             : #define LOGV(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      45             : 
      46             : #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
      47             : 
      48             : namespace mozilla {
      49             : 
      50             : /**
      51             :  * This is a singleton which controls the number of decoders that can be
      52             :  * created concurrently. Before calling PDMFactory::CreateDecoder(), Alloc()
      53             :  * must be called to get a token object as a permission to create a decoder.
      54             :  * The token should stay alive until Shutdown() is called on the decoder.
      55             :  * The destructor of the token will restore the decoder count so it is available
      56             :  * for next calls of Alloc().
      57             :  */
      58             : class GlobalAllocPolicy
      59             : {
      60             :   using TrackType = TrackInfo::TrackType;
      61             : 
      62             : public:
      63           0 :   class Token
      64             :   {
      65           0 :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Token)
      66             :   protected:
      67           0 :     virtual ~Token() {}
      68             :   };
      69             : 
      70             :   using Promise = MozPromise<RefPtr<Token>, bool, true>;
      71             : 
      72             :   // Acquire a token for decoder creation. Thread-safe.
      73             :   auto Alloc() -> RefPtr<Promise>;
      74             : 
      75             :   // Called by ClearOnShutdown() to delete the singleton.
      76             :   void operator=(decltype(nullptr));
      77             : 
      78             :   // Get the singleton for the given track type. Thread-safe.
      79             :   static GlobalAllocPolicy& Instance(TrackType aTrack);
      80             : 
      81             : private:
      82             :   class AutoDeallocToken;
      83             :   using PromisePrivate = Promise::Private;
      84             :   GlobalAllocPolicy();
      85             :   ~GlobalAllocPolicy();
      86             :   // Called by the destructor of TokenImpl to restore the decoder limit.
      87             :   void Dealloc();
      88             :   // Decrement the decoder limit and resolve a promise if available.
      89             :   void ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock);
      90             : 
      91             :   // Protect access to Instance().
      92             :   static StaticMutex sMutex;
      93             : 
      94             :   ReentrantMonitor mMonitor;
      95             :   // The number of decoders available for creation.
      96             :   int mDecoderLimit;
      97             :   // Requests to acquire tokens.
      98             :   std::queue<RefPtr<PromisePrivate>> mPromises;
      99             : };
     100             : 
     101           3 : StaticMutex GlobalAllocPolicy::sMutex;
     102             : 
     103             : class GlobalAllocPolicy::AutoDeallocToken : public Token
     104             : {
     105             : public:
     106           0 :   explicit AutoDeallocToken(GlobalAllocPolicy& aPolicy) : mPolicy(aPolicy) { }
     107             : 
     108             : private:
     109           0 :   ~AutoDeallocToken()
     110           0 :   {
     111           0 :     mPolicy.Dealloc();
     112           0 :   }
     113             : 
     114             :   GlobalAllocPolicy& mPolicy; // reference to a singleton object.
     115             : };
     116             : 
     117           0 : GlobalAllocPolicy::GlobalAllocPolicy()
     118             :   : mMonitor("DecoderAllocPolicy::mMonitor")
     119           0 :   , mDecoderLimit(MediaPrefs::MediaDecoderLimit())
     120             : {
     121           0 :   SystemGroup::Dispatch(
     122             :     "GlobalAllocPolicy::ClearOnShutdown",
     123             :     TaskCategory::Other,
     124           0 :     NS_NewRunnableFunction("GlobalAllocPolicy::GlobalAllocPolicy", [this]() {
     125           0 :       ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
     126           0 :     }));
     127           0 : }
     128             : 
     129           0 : GlobalAllocPolicy::~GlobalAllocPolicy()
     130             : {
     131           0 :   while (!mPromises.empty()) {
     132           0 :     RefPtr<PromisePrivate> p = mPromises.front().forget();
     133           0 :     mPromises.pop();
     134           0 :     p->Reject(true, __func__);
     135             :   }
     136           0 : }
     137             : 
     138             : GlobalAllocPolicy&
     139           0 : GlobalAllocPolicy::Instance(TrackType aTrack)
     140             : {
     141           0 :   StaticMutexAutoLock lock(sMutex);
     142           0 :   if (aTrack == TrackType::kAudioTrack) {
     143           0 :     static auto sAudioPolicy = new GlobalAllocPolicy();
     144           0 :     return *sAudioPolicy;
     145             :   } else {
     146           0 :     static auto sVideoPolicy = new GlobalAllocPolicy();
     147           0 :     return *sVideoPolicy;
     148             :   }
     149             : }
     150             : 
     151             : auto
     152           0 : GlobalAllocPolicy::Alloc() -> RefPtr<Promise>
     153             : {
     154             :   // No decoder limit set.
     155           0 :   if (mDecoderLimit < 0) {
     156           0 :     return Promise::CreateAndResolve(new Token(), __func__);
     157             :   }
     158             : 
     159           0 :   ReentrantMonitorAutoEnter mon(mMonitor);
     160           0 :   RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
     161           0 :   mPromises.push(p);
     162           0 :   ResolvePromise(mon);
     163           0 :   return p.forget();
     164             : }
     165             : 
     166             : void
     167           0 : GlobalAllocPolicy::Dealloc()
     168             : {
     169           0 :   ReentrantMonitorAutoEnter mon(mMonitor);
     170           0 :   ++mDecoderLimit;
     171           0 :   ResolvePromise(mon);
     172           0 : }
     173             : 
     174             : void
     175           0 : GlobalAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
     176             : {
     177           0 :   MOZ_ASSERT(mDecoderLimit >= 0);
     178             : 
     179           0 :   if (mDecoderLimit > 0 && !mPromises.empty()) {
     180           0 :     --mDecoderLimit;
     181           0 :     RefPtr<PromisePrivate> p = mPromises.front().forget();
     182           0 :     mPromises.pop();
     183           0 :     p->Resolve(new AutoDeallocToken(*this), __func__);
     184             :   }
     185           0 : }
     186             : 
     187             : void
     188           0 : GlobalAllocPolicy::operator=(std::nullptr_t)
     189             : {
     190           0 :   delete this;
     191           0 : }
     192             : 
     193             : /**
     194             :  * This class addresses the concern of bug 1339310 comment 4 where the Widevine
     195             :  * CDM doesn't support running multiple instances of a video decoder at once per
     196             :  * CDM instance by sequencing the order of decoder creation and shutdown. Note
     197             :  * this class addresses a different concern from that of GlobalAllocPolicy which
     198             :  * controls a system-wide number of decoders while this class control a per-MFR
     199             :  * number (which is one per CDM requirement).
     200             :  */
     201             : class LocalAllocPolicy
     202             : {
     203             :   using TrackType = TrackInfo::TrackType;
     204             :   using Promise = GlobalAllocPolicy::Promise;
     205             :   using Token = GlobalAllocPolicy::Token;
     206             : 
     207           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalAllocPolicy)
     208             : 
     209             : public:
     210           0 :   LocalAllocPolicy(TrackType aTrack, TaskQueue* aOwnerThread)
     211           0 :     : mTrack(aTrack)
     212           0 :     , mOwnerThread(aOwnerThread)
     213             :   {
     214           0 :   }
     215             : 
     216             :   // Acquire a token for decoder creation. Note the resolved token will
     217             :   // aggregate a GlobalAllocPolicy token to comply to its policy. Note
     218             :   // this function shouldn't be called again until the returned promise
     219             :   // is resolved or rejected.
     220             :   RefPtr<Promise> Alloc();
     221             : 
     222             :   // Cancel the request to GlobalAllocPolicy and reject the current token
     223             :   // request. Note this must happen before mOwnerThread->BeginShutdown().
     224             :   void Cancel();
     225             : 
     226             : private:
     227             :   /*
     228             :    * An RAII class to manage LocalAllocPolicy::mDecoderLimit.
     229             :    */
     230             :   class AutoDeallocToken : public Token
     231             :   {
     232             :   public:
     233           0 :     explicit AutoDeallocToken(LocalAllocPolicy* aOwner)
     234           0 :       : mOwner(aOwner)
     235             :     {
     236           0 :       MOZ_DIAGNOSTIC_ASSERT(mOwner->mDecoderLimit > 0);
     237           0 :       --mOwner->mDecoderLimit;
     238           0 :     }
     239             :     // Aggregate a GlobalAllocPolicy token to present a single instance of
     240             :     // Token to the client so the client doesn't have to deal with
     241             :     // GlobalAllocPolicy and LocalAllocPolicy separately.
     242           0 :     void Append(Token* aToken)
     243             :     {
     244           0 :       mToken = aToken;
     245           0 :     }
     246             :   private:
     247             :     // Release tokens allocated from GlobalAllocPolicy and LocalAllocPolicy
     248             :     // and process next token request if any.
     249           0 :     ~AutoDeallocToken()
     250           0 :     {
     251           0 :       mToken = nullptr; // Dealloc the global token.
     252           0 :       ++mOwner->mDecoderLimit; // Dealloc the local token.
     253           0 :       mOwner->ProcessRequest(); // Process next pending request.
     254           0 :     }
     255             :     RefPtr<LocalAllocPolicy> mOwner;
     256             :     RefPtr<Token> mToken;
     257             :   };
     258             : 
     259           0 :   ~LocalAllocPolicy() { }
     260             :   void ProcessRequest();
     261             : 
     262             :   int mDecoderLimit = 1;
     263             :   const TrackType mTrack;
     264             :   RefPtr<TaskQueue> mOwnerThread;
     265             :   MozPromiseHolder<Promise> mPendingPromise;
     266             :   MozPromiseRequestHolder<Promise> mTokenRequest;
     267             : };
     268             : 
     269             : RefPtr<LocalAllocPolicy::Promise>
     270           0 : LocalAllocPolicy::Alloc()
     271             : {
     272           0 :   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
     273           0 :   MOZ_DIAGNOSTIC_ASSERT(mPendingPromise.IsEmpty());
     274           0 :   RefPtr<Promise> p = mPendingPromise.Ensure(__func__);
     275           0 :   if (mDecoderLimit > 0) {
     276           0 :     ProcessRequest();
     277             :   }
     278           0 :   return p.forget();
     279             : }
     280             : 
     281             : void
     282           0 : LocalAllocPolicy::ProcessRequest()
     283             : {
     284           0 :   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
     285           0 :   MOZ_DIAGNOSTIC_ASSERT(mDecoderLimit > 0);
     286             : 
     287             :   // No pending request.
     288           0 :   if (mPendingPromise.IsEmpty()) {
     289           0 :     return;
     290             :   }
     291             : 
     292           0 :   RefPtr<AutoDeallocToken> token = new AutoDeallocToken(this);
     293           0 :   RefPtr<LocalAllocPolicy> self = this;
     294             : 
     295           0 :   GlobalAllocPolicy::Instance(mTrack).Alloc()->Then(
     296             :     mOwnerThread, __func__,
     297           0 :     [self, token](RefPtr<Token> aToken) {
     298           0 :       self->mTokenRequest.Complete();
     299           0 :       token->Append(aToken);
     300           0 :       self->mPendingPromise.Resolve(token, __func__);
     301           0 :     },
     302           0 :     [self, token]() {
     303           0 :       self->mTokenRequest.Complete();
     304           0 :       self->mPendingPromise.Reject(true, __func__);
     305           0 :     })->Track(mTokenRequest);
     306             : }
     307             : 
     308             : void
     309           0 : LocalAllocPolicy::Cancel()
     310             : {
     311           0 :   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
     312           0 :   mPendingPromise.RejectIfExists(true, __func__);
     313           0 :   mTokenRequest.DisconnectIfExists();
     314           0 : }
     315             : 
     316             : /**
     317             :  * This class tracks shutdown promises to ensure all decoders are shut down
     318             :  * completely before MFR continues the rest of the shutdown procedure.
     319             :  */
     320           0 : class MediaFormatReader::ShutdownPromisePool
     321             : {
     322             : public:
     323           0 :   ShutdownPromisePool()
     324           0 :     : mOnShutdownComplete(new ShutdownPromise::Private(__func__))
     325             :   {
     326           0 :   }
     327             : 
     328             :   // Return a promise which will be resolved when all the tracking promises
     329             :   // are resolved. Note no more promises should be added for tracking once
     330             :   // this function is called.
     331             :   RefPtr<ShutdownPromise> Shutdown();
     332             : 
     333             :    // Track a shutdown promise.
     334             :   void Track(RefPtr<ShutdownPromise> aPromise);
     335             : 
     336             :    // Shut down a decoder and track its shutdown promise.
     337           0 :   void ShutdownDecoder(already_AddRefed<MediaDataDecoder> aDecoder)
     338             :   {
     339           0 :     Track(RefPtr<MediaDataDecoder>(aDecoder)->Shutdown());
     340           0 :   }
     341             : 
     342             : private:
     343             :   bool mShutdown = false;
     344             :   const RefPtr<ShutdownPromise::Private> mOnShutdownComplete;
     345             :   nsTHashtable<nsRefPtrHashKey<ShutdownPromise>> mPromises;
     346             : };
     347             : 
     348             : RefPtr<ShutdownPromise>
     349           0 : MediaFormatReader::ShutdownPromisePool::Shutdown()
     350             : {
     351           0 :   MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
     352           0 :   mShutdown = true;
     353           0 :   if (mPromises.Count() == 0) {
     354           0 :     mOnShutdownComplete->Resolve(true, __func__);
     355             :   }
     356           0 :   return mOnShutdownComplete;
     357             : }
     358             : 
     359             : void
     360           0 : MediaFormatReader::ShutdownPromisePool::Track(RefPtr<ShutdownPromise> aPromise)
     361             : {
     362           0 :   MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
     363           0 :   MOZ_DIAGNOSTIC_ASSERT(!mPromises.Contains(aPromise));
     364           0 :   mPromises.PutEntry(aPromise);
     365             :   aPromise->Then(
     366           0 :     AbstractThread::GetCurrent(), __func__,
     367           0 :     [aPromise, this]() {
     368           0 :       MOZ_DIAGNOSTIC_ASSERT(mPromises.Contains(aPromise));
     369           0 :       mPromises.RemoveEntry(aPromise);
     370           0 :       if (mShutdown && mPromises.Count() == 0) {
     371           0 :         mOnShutdownComplete->Resolve(true, __func__);
     372             :       }
     373           0 :     });
     374           0 : }
     375             : 
     376             : void
     377           0 : MediaFormatReader::DecoderData::ShutdownDecoder()
     378             : {
     379           0 :   MutexAutoLock lock(mMutex);
     380             : 
     381           0 :   if (!mDecoder) {
     382             :     // No decoder to shut down.
     383           0 :     return;
     384             :   }
     385             : 
     386           0 :   if (mFlushing) {
     387             :     // Flush is is in action. Shutdown will be initiated after flush completes.
     388           0 :     MOZ_DIAGNOSTIC_ASSERT(mShutdownPromise);
     389           0 :     mOwner->mShutdownPromisePool->Track(mShutdownPromise->Ensure(__func__));
     390             :     // The order of decoder creation and shutdown is handled by LocalAllocPolicy
     391             :     // and ShutdownPromisePool. MFR can now reset these members to a fresh state
     392             :     // and be ready to create new decoders again without explicitly waiting for
     393             :     // flush/shutdown to complete.
     394           0 :     mShutdownPromise = nullptr;
     395           0 :     mFlushing = false;
     396             :   } else {
     397             :     // No flush is in action. We can shut down the decoder now.
     398           0 :     mOwner->mShutdownPromisePool->Track(mDecoder->Shutdown());
     399             :   }
     400             : 
     401             :   // mShutdownPromisePool will handle the order of decoder shutdown so
     402             :   // we can forget mDecoder and be ready to create a new one.
     403           0 :   mDecoder = nullptr;
     404           0 :   mDescription = "shutdown";
     405           0 :   mOwner->ScheduleUpdate(mType == MediaData::AUDIO_DATA
     406             :                          ? TrackType::kAudioTrack
     407           0 :                          : TrackType::kVideoTrack);
     408             : }
     409             : 
     410             : void
     411           0 : MediaFormatReader::DecoderData::Flush()
     412             : {
     413           0 :   if (mFlushing || mFlushed) {
     414             :     // Flush still pending or already flushed, nothing more to do.
     415           0 :     return;
     416             :   }
     417           0 :   mDecodeRequest.DisconnectIfExists();
     418           0 :   mDrainRequest.DisconnectIfExists();
     419           0 :   mDrainState = DrainState::None;
     420           0 :   CancelWaitingForKey();
     421           0 :   mOutput.Clear();
     422           0 :   mNumSamplesInput = 0;
     423           0 :   mNumSamplesOutput = 0;
     424           0 :   mSizeOfQueue = 0;
     425           0 :   if (mDecoder) {
     426           0 :     TrackType type = mType == MediaData::AUDIO_DATA
     427           0 :                      ? TrackType::kAudioTrack
     428           0 :                      : TrackType::kVideoTrack;
     429           0 :     mFlushing = true;
     430           0 :     MOZ_DIAGNOSTIC_ASSERT(!mShutdownPromise);
     431           0 :     mShutdownPromise = new SharedShutdownPromiseHolder();
     432           0 :     RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
     433           0 :     RefPtr<MediaDataDecoder> d = mDecoder;
     434           0 :     mDecoder->Flush()
     435           0 :       ->Then(mOwner->OwnerThread(), __func__,
     436           0 :              [type, this, p, d]() {
     437           0 :                if (!p->IsEmpty()) {
     438             :                  // Shutdown happened before flush completes. Let's continue to
     439             :                  // shut down the decoder. Note we don't access |this| because
     440             :                  // this decoder is no longer managed by MFR::DecoderData.
     441           0 :                  d->Shutdown()->ChainTo(p->Steal(), __func__);
     442           0 :                  return;
     443             :                }
     444           0 :                mFlushing = false;
     445           0 :                mShutdownPromise = nullptr;
     446           0 :                mOwner->ScheduleUpdate(type);
     447             :              },
     448           0 :              [type, this, p, d](const MediaResult& aError) {
     449           0 :                if (!p->IsEmpty()) {
     450           0 :                  d->Shutdown()->ChainTo(p->Steal(), __func__);
     451           0 :                  return;
     452             :                }
     453           0 :                mFlushing = false;
     454           0 :                mShutdownPromise = nullptr;
     455           0 :                mOwner->NotifyError(type, aError);
     456           0 :              });
     457             :   }
     458           0 :   mFlushed = true;
     459             : }
     460             : 
     461           0 : class MediaFormatReader::DecoderFactory
     462             : {
     463             :   using InitPromise = MediaDataDecoder::InitPromise;
     464             :   using TokenPromise = GlobalAllocPolicy::Promise;
     465             :   using Token = GlobalAllocPolicy::Token;
     466             : 
     467             : public:
     468           0 :   explicit DecoderFactory(MediaFormatReader* aOwner)
     469           0 :     : mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread())
     470             :     , mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread())
     471           0 :     , mOwner(WrapNotNull(aOwner)) { }
     472             : 
     473             :   void CreateDecoder(TrackType aTrack);
     474             : 
     475             :   // Shutdown any decoder pending initialization and reset mAudio/mVideo to its
     476             :   // pristine state so CreateDecoder() is ready to be called again immediately.
     477           0 :   void ShutdownDecoder(TrackType aTrack)
     478             :   {
     479           0 :     MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
     480             :                || aTrack == TrackInfo::kVideoTrack);
     481           0 :     auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
     482           0 :     data.mPolicy->Cancel();
     483           0 :     data.mTokenRequest.DisconnectIfExists();
     484           0 :     data.mInitRequest.DisconnectIfExists();
     485           0 :     if (data.mDecoder) {
     486           0 :       mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
     487             :     }
     488           0 :     data.mStage = Stage::None;
     489           0 :     MOZ_ASSERT(!data.mToken);
     490           0 :   }
     491             : 
     492             : private:
     493             :   class Wrapper;
     494             : 
     495             :   enum class Stage : int8_t
     496             :   {
     497             :     None,
     498             :     WaitForToken,
     499             :     CreateDecoder,
     500             :     WaitForInit
     501             :   };
     502             : 
     503           0 :   struct Data
     504             :   {
     505           0 :     Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
     506           0 :       : mOwnerData(aOwnerData)
     507             :       , mTrack(aTrack)
     508           0 :       , mPolicy(new LocalAllocPolicy(aTrack, aThread)) { }
     509             :     DecoderData& mOwnerData;
     510             :     const TrackType mTrack;
     511             :     RefPtr<LocalAllocPolicy> mPolicy;
     512             :     Stage mStage = Stage::None;
     513             :     RefPtr<Token> mToken;
     514             :     RefPtr<MediaDataDecoder> mDecoder;
     515             :     MozPromiseRequestHolder<TokenPromise> mTokenRequest;
     516             :     MozPromiseRequestHolder<InitPromise> mInitRequest;
     517             :   } mAudio, mVideo;
     518             : 
     519             :   void RunStage(Data& aData);
     520             :   MediaResult DoCreateDecoder(Data& aData);
     521             :   void DoInitDecoder(Data& aData);
     522             : 
     523             :   // guaranteed to be valid by the owner.
     524             :   const NotNull<MediaFormatReader*> mOwner;
     525             : };
     526             : 
     527             : void
     528           0 : MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack)
     529             : {
     530           0 :   MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
     531             :              || aTrack == TrackInfo::kVideoTrack);
     532           0 :   RunStage(aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo);
     533           0 : }
     534             : 
     535           0 : class MediaFormatReader::DecoderFactory::Wrapper : public MediaDataDecoder
     536             : {
     537             :   using Token = GlobalAllocPolicy::Token;
     538             : 
     539             : public:
     540           0 :   Wrapper(already_AddRefed<MediaDataDecoder> aDecoder,
     541             :           already_AddRefed<Token> aToken)
     542           0 :     : mDecoder(aDecoder), mToken(aToken) {}
     543             : 
     544           0 :   RefPtr<InitPromise> Init() override { return mDecoder->Init(); }
     545           0 :   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
     546             :   {
     547           0 :     return mDecoder->Decode(aSample);
     548             :   }
     549           0 :   RefPtr<DecodePromise> Drain() override { return mDecoder->Drain(); }
     550           0 :   RefPtr<FlushPromise> Flush() override { return mDecoder->Flush(); }
     551           0 :   bool IsHardwareAccelerated(nsACString& aFailureReason) const override
     552             :   {
     553           0 :     return mDecoder->IsHardwareAccelerated(aFailureReason);
     554             :   }
     555           0 :   const char* GetDescriptionName() const override
     556             :   {
     557           0 :     return mDecoder->GetDescriptionName();
     558             :   }
     559           0 :   void SetSeekThreshold(const TimeUnit& aTime) override
     560             :   {
     561           0 :     mDecoder->SetSeekThreshold(aTime);
     562           0 :   }
     563           0 :   bool SupportDecoderRecycling() const override
     564             :   {
     565           0 :     return mDecoder->SupportDecoderRecycling();
     566             :   }
     567           0 :   RefPtr<ShutdownPromise> Shutdown() override
     568             :   {
     569           0 :     RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
     570           0 :     RefPtr<Token> token = mToken.forget();
     571           0 :     return decoder->Shutdown()->Then(
     572           0 :       AbstractThread::GetCurrent(), __func__,
     573           0 :       [token]() {
     574             :         return ShutdownPromise::CreateAndResolve(true, __func__);
     575           0 :       });
     576             :   }
     577             : 
     578             : private:
     579             :   RefPtr<MediaDataDecoder> mDecoder;
     580             :   RefPtr<Token> mToken;
     581             : };
     582             : 
     583             : void
     584           0 : MediaFormatReader::DecoderFactory::RunStage(Data& aData)
     585             : {
     586           0 :   switch (aData.mStage) {
     587             :     case Stage::None: {
     588           0 :       MOZ_ASSERT(!aData.mToken);
     589           0 :       aData.mPolicy->Alloc()->Then(
     590           0 :         mOwner->OwnerThread(), __func__,
     591           0 :         [this, &aData] (RefPtr<Token> aToken) {
     592           0 :           aData.mTokenRequest.Complete();
     593           0 :           aData.mToken = aToken.forget();
     594           0 :           aData.mStage = Stage::CreateDecoder;
     595           0 :           RunStage(aData);
     596           0 :         },
     597           0 :         [&aData] () {
     598           0 :           aData.mTokenRequest.Complete();
     599           0 :           aData.mStage = Stage::None;
     600           0 :         })->Track(aData.mTokenRequest);
     601           0 :       aData.mStage = Stage::WaitForToken;
     602           0 :       break;
     603             :     }
     604             : 
     605             :     case Stage::WaitForToken: {
     606           0 :       MOZ_ASSERT(!aData.mToken);
     607           0 :       MOZ_ASSERT(aData.mTokenRequest.Exists());
     608           0 :       break;
     609             :     }
     610             : 
     611             :     case Stage::CreateDecoder: {
     612           0 :       MOZ_ASSERT(aData.mToken);
     613           0 :       MOZ_ASSERT(!aData.mDecoder);
     614           0 :       MOZ_ASSERT(!aData.mInitRequest.Exists());
     615             : 
     616           0 :       MediaResult rv = DoCreateDecoder(aData);
     617           0 :       if (NS_FAILED(rv)) {
     618           0 :         NS_WARNING("Error constructing decoders");
     619           0 :         aData.mToken = nullptr;
     620           0 :         aData.mStage = Stage::None;
     621           0 :         mOwner->NotifyError(aData.mTrack, rv);
     622           0 :         return;
     623             :       }
     624             : 
     625           0 :       aData.mDecoder = new Wrapper(aData.mDecoder.forget(), aData.mToken.forget());
     626           0 :       DoInitDecoder(aData);
     627           0 :       aData.mStage = Stage::WaitForInit;
     628           0 :       break;
     629             :     }
     630             : 
     631             :     case Stage::WaitForInit: {
     632           0 :       MOZ_ASSERT(aData.mDecoder);
     633           0 :       MOZ_ASSERT(aData.mInitRequest.Exists());
     634           0 :       break;
     635             :     }
     636             :   }
     637             : }
     638             : 
     639             : MediaResult
     640           0 : MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData)
     641             : {
     642           0 :   auto& ownerData = aData.mOwnerData;
     643             : 
     644           0 :   auto decoderCreatingError = "error creating audio decoder";
     645             :   MediaResult result =
     646           0 :     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, decoderCreatingError);
     647             : 
     648           0 :   if (!mOwner->mPlatform) {
     649           0 :     mOwner->mPlatform = new PDMFactory();
     650           0 :     if (mOwner->IsEncrypted()) {
     651           0 :       MOZ_ASSERT(mOwner->mCDMProxy);
     652           0 :       mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy);
     653             :     }
     654             :   }
     655             : 
     656           0 :   switch (aData.mTrack) {
     657             :     case TrackInfo::kAudioTrack: {
     658           0 :       aData.mDecoder = mOwner->mPlatform->CreateDecoder({
     659             :         ownerData.mInfo
     660           0 :         ? *ownerData.mInfo->GetAsAudioInfo()
     661           0 :         : *ownerData.mOriginalInfo->GetAsAudioInfo(),
     662             :         ownerData.mTaskQueue,
     663           0 :         mOwner->mCrashHelper,
     664             :         ownerData.mIsNullDecode,
     665           0 :         &result,
     666             :         TrackInfo::kAudioTrack,
     667           0 :         &mOwner->OnTrackWaitingForKeyProducer()
     668           0 :       });
     669           0 :       break;
     670             :     }
     671             : 
     672             :     case TrackType::kVideoTrack: {
     673             :       // Decoders use the layers backend to decide if they can use hardware decoding,
     674             :       // so specify LAYERS_NONE if we want to forcibly disable it.
     675           0 :       aData.mDecoder = mOwner->mPlatform->CreateDecoder({
     676             :         ownerData.mInfo
     677           0 :         ? *ownerData.mInfo->GetAsVideoInfo()
     678           0 :         : *ownerData.mOriginalInfo->GetAsVideoInfo(),
     679             :         ownerData.mTaskQueue,
     680           0 :         mOwner->mKnowsCompositor,
     681           0 :         mOwner->GetImageContainer(),
     682           0 :         mOwner->mCrashHelper,
     683             :         ownerData.mIsNullDecode,
     684           0 :         &result,
     685             :         TrackType::kVideoTrack,
     686           0 :         &mOwner->OnTrackWaitingForKeyProducer()
     687           0 :       });
     688           0 :       break;
     689             :     }
     690             : 
     691             :     default:
     692           0 :       break;
     693             :   }
     694             : 
     695           0 :   if (aData.mDecoder) {
     696           0 :     return NS_OK;
     697             :   }
     698             : 
     699           0 :   ownerData.mDescription = decoderCreatingError;
     700           0 :   return result;
     701             : }
     702             : 
     703             : void
     704           0 : MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
     705             : {
     706           0 :   auto& ownerData = aData.mOwnerData;
     707             : 
     708           0 :   aData.mDecoder->Init()
     709           0 :     ->Then(mOwner->OwnerThread(), __func__,
     710           0 :            [this, &aData, &ownerData](TrackType aTrack) {
     711           0 :              aData.mInitRequest.Complete();
     712           0 :              aData.mStage = Stage::None;
     713           0 :              MutexAutoLock lock(ownerData.mMutex);
     714           0 :              ownerData.mDecoder = aData.mDecoder.forget();
     715           0 :              ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
     716           0 :              mOwner->SetVideoDecodeThreshold();
     717           0 :              mOwner->ScheduleUpdate(aTrack);
     718           0 :            },
     719           0 :            [this, &aData, &ownerData](const MediaResult& aError) {
     720           0 :              aData.mInitRequest.Complete();
     721           0 :              MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
     722             :                                 "Can't have a decoder already set");
     723           0 :              aData.mStage = Stage::None;
     724           0 :              mOwner->mShutdownPromisePool->ShutdownDecoder(aData.mDecoder.forget());
     725           0 :              mOwner->NotifyError(aData.mTrack, aError);
     726           0 :            })
     727           0 :     ->Track(aData.mInitRequest);
     728           0 : }
     729             : 
     730             : // DemuxerProxy ensures that the original main demuxer is only ever accessed
     731             : // via its own dedicated task queue.
     732             : // This ensure that the reader's taskqueue will never blocked while a demuxer
     733             : // is itself blocked attempting to access the MediaCache or the MediaResource.
     734             : class MediaFormatReader::DemuxerProxy
     735             : {
     736             :   using TrackType = TrackInfo::TrackType;
     737             :   class Wrapper;
     738             : 
     739             : public:
     740           0 :   explicit DemuxerProxy(MediaDataDemuxer* aDemuxer)
     741           0 :     : mTaskQueue(new AutoTaskQueue(
     742           0 :         GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
     743           0 :         "DemuxerProxy::mTaskQueue"))
     744           0 :     , mData(new Data(aDemuxer))
     745             :   {
     746           0 :     MOZ_COUNT_CTOR(DemuxerProxy);
     747           0 :   }
     748             : 
     749           0 :   ~DemuxerProxy()
     750           0 :   {
     751           0 :     MOZ_COUNT_DTOR(DemuxerProxy);
     752           0 :   }
     753             : 
     754           0 :   RefPtr<ShutdownPromise> Shutdown()
     755             :   {
     756           0 :     RefPtr<Data> data = mData.forget();
     757           0 :     return InvokeAsync(mTaskQueue, __func__, [data]() {
     758             :       // We need to clear our reference to the demuxer now. So that in the event
     759             :       // the init promise wasn't resolved, such as what can happen with the
     760             :       // mediasource demuxer that is waiting on more data, it will force the
     761             :       // init promise to be rejected.
     762           0 :       data->mDemuxer = nullptr;
     763           0 :       data->mAudioDemuxer = nullptr;
     764           0 :       data->mVideoDemuxer = nullptr;
     765           0 :       return ShutdownPromise::CreateAndResolve(true, __func__);
     766           0 :     });
     767             :   }
     768             : 
     769             :   RefPtr<MediaDataDemuxer::InitPromise> Init();
     770             : 
     771             :   Wrapper*
     772           0 :   GetTrackDemuxer(TrackType aTrack, uint32_t aTrackNumber)
     773             :   {
     774           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     775             : 
     776           0 :     switch (aTrack) {
     777             :       case TrackInfo::kAudioTrack:
     778           0 :         return mData->mAudioDemuxer;
     779             :       case TrackInfo::kVideoTrack:
     780           0 :         return mData->mVideoDemuxer;
     781             :       default:
     782           0 :         return nullptr;
     783             :     }
     784             :   }
     785             : 
     786           0 :   uint32_t GetNumberTracks(TrackType aTrack) const
     787             :   {
     788           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     789             : 
     790           0 :     switch (aTrack) {
     791             :       case TrackInfo::kAudioTrack:
     792           0 :         return mData->mNumAudioTrack;
     793             :       case TrackInfo::kVideoTrack:
     794           0 :         return mData->mNumVideoTrack;
     795             :       default:
     796           0 :         return 0;
     797             :     }
     798             :   }
     799             : 
     800           0 :   bool IsSeekable() const
     801             :   {
     802           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     803             : 
     804           0 :     return mData->mSeekable;
     805             :   }
     806             : 
     807           0 :   bool IsSeekableOnlyInBufferedRanges() const
     808             :   {
     809           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     810             : 
     811           0 :     return mData->mSeekableOnlyInBufferedRange;
     812             :   }
     813             : 
     814           0 :   UniquePtr<EncryptionInfo> GetCrypto() const
     815             :   {
     816           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     817             : 
     818           0 :     if (!mData->mCrypto) {
     819           0 :       return nullptr;
     820             :     }
     821           0 :     auto crypto = MakeUnique<EncryptionInfo>();
     822           0 :     *crypto = *mData->mCrypto;
     823           0 :     return crypto;
     824             :   }
     825             : 
     826             :   RefPtr<NotifyDataArrivedPromise> NotifyDataArrived();
     827             : 
     828           0 :   bool ShouldComputeStartTime() const
     829             :   {
     830           0 :     MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
     831             : 
     832           0 :     return mData->mShouldComputeStartTime;
     833             :   }
     834             : 
     835             : private:
     836             :   const RefPtr<AutoTaskQueue> mTaskQueue;
     837             :   struct Data
     838             :   {
     839           0 :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Data)
     840             : 
     841           0 :     explicit Data(MediaDataDemuxer* aDemuxer)
     842           0 :       : mInitDone(false)
     843           0 :       , mDemuxer(aDemuxer)
     844             :     {
     845           0 :     }
     846             : 
     847             :     Atomic<bool> mInitDone;
     848             :     // Only ever accessed over mTaskQueue once.
     849             :     RefPtr<MediaDataDemuxer> mDemuxer;
     850             :     // Only accessed once InitPromise has been resolved and immutable after.
     851             :     // So we can safely access them without the use of the mutex.
     852             :     uint32_t mNumAudioTrack = 0;
     853             :     RefPtr<Wrapper> mAudioDemuxer;
     854             :     uint32_t mNumVideoTrack = 0;
     855             :     RefPtr<Wrapper> mVideoDemuxer;
     856             :     bool mSeekable = false;
     857             :     bool mSeekableOnlyInBufferedRange = false;
     858             :     bool mShouldComputeStartTime = true;
     859             :     UniquePtr<EncryptionInfo> mCrypto;
     860             :   private:
     861           0 :     ~Data() { }
     862             :   };
     863             :   RefPtr<Data> mData;
     864             : };
     865             : 
     866             : class MediaFormatReader::DemuxerProxy::Wrapper : public MediaTrackDemuxer
     867             : {
     868             : public:
     869           0 :   Wrapper(MediaTrackDemuxer* aTrackDemuxer, AutoTaskQueue* aTaskQueue)
     870           0 :     : mMutex("TrackDemuxer Mutex")
     871             :     , mTaskQueue(aTaskQueue)
     872           0 :     , mGetSamplesMayBlock(aTrackDemuxer->GetSamplesMayBlock())
     873           0 :     , mInfo(aTrackDemuxer->GetInfo())
     874           0 :     , mTrackDemuxer(aTrackDemuxer)
     875             :   {
     876           0 :   }
     877             : 
     878           0 :   UniquePtr<TrackInfo> GetInfo() const override
     879             :   {
     880           0 :     if (!mInfo) {
     881           0 :       return nullptr;
     882             :     }
     883           0 :     return mInfo->Clone();
     884             :   }
     885             : 
     886           0 :   RefPtr<SeekPromise> Seek(const TimeUnit& aTime) override
     887             :   {
     888           0 :     RefPtr<Wrapper> self = this;
     889           0 :     return InvokeAsync(
     890             :              mTaskQueue, __func__,
     891           0 :              [self, aTime]() { return self->mTrackDemuxer->Seek(aTime); })
     892           0 :       ->Then(mTaskQueue, __func__,
     893           0 :              [self](const TimeUnit& aTime) {
     894           0 :                self->UpdateRandomAccessPoint();
     895           0 :                return SeekPromise::CreateAndResolve(aTime, __func__);
     896             :              },
     897           0 :              [self](const MediaResult& aError) {
     898           0 :                self->UpdateRandomAccessPoint();
     899           0 :                return SeekPromise::CreateAndReject(aError, __func__);
     900           0 :              });
     901             :   }
     902             : 
     903           0 :   RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override
     904             :   {
     905           0 :     RefPtr<Wrapper> self = this;
     906           0 :     return InvokeAsync(mTaskQueue, __func__,
     907           0 :                        [self, aNumSamples]() {
     908           0 :                          return self->mTrackDemuxer->GetSamples(aNumSamples);
     909           0 :                        })
     910           0 :       ->Then(mTaskQueue, __func__,
     911           0 :              [self](RefPtr<SamplesHolder> aSamples) {
     912           0 :                self->UpdateRandomAccessPoint();
     913           0 :                return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
     914             :              },
     915           0 :              [self](const MediaResult& aError) {
     916           0 :                self->UpdateRandomAccessPoint();
     917           0 :                return SamplesPromise::CreateAndReject(aError, __func__);
     918           0 :              });
     919             :   }
     920             : 
     921           0 :   bool GetSamplesMayBlock() const override
     922             :   {
     923           0 :     return mGetSamplesMayBlock;
     924             :   }
     925             : 
     926           0 :   void Reset() override
     927             :   {
     928           0 :     RefPtr<Wrapper> self = this;
     929           0 :     mTaskQueue->Dispatch(
     930           0 :       NS_NewRunnableFunction("MediaFormatReader::DemuxerProxy::Wrapper::Reset",
     931           0 :                              [self]() { self->mTrackDemuxer->Reset(); }));
     932           0 :   }
     933             : 
     934           0 :   nsresult GetNextRandomAccessPoint(TimeUnit* aTime) override
     935             :   {
     936           0 :     MutexAutoLock lock(mMutex);
     937           0 :     if (NS_SUCCEEDED(mNextRandomAccessPointResult)) {
     938           0 :       *aTime = mNextRandomAccessPoint;
     939             :     }
     940           0 :     return mNextRandomAccessPointResult;
     941             :   }
     942             : 
     943             :   RefPtr<SkipAccessPointPromise>
     944           0 :   SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) override
     945             :   {
     946           0 :     RefPtr<Wrapper> self = this;
     947           0 :     return InvokeAsync(
     948             :              mTaskQueue, __func__,
     949           0 :              [self, aTimeThreshold]()  {
     950           0 :                return self->mTrackDemuxer->SkipToNextRandomAccessPoint(
     951           0 :                  aTimeThreshold);
     952           0 :              })
     953           0 :       ->Then(mTaskQueue, __func__,
     954           0 :              [self](uint32_t aVal) {
     955           0 :                self->UpdateRandomAccessPoint();
     956           0 :                return SkipAccessPointPromise::CreateAndResolve(aVal, __func__);
     957             :              },
     958           0 :              [self](const SkipFailureHolder& aError) {
     959           0 :                self->UpdateRandomAccessPoint();
     960           0 :                return SkipAccessPointPromise::CreateAndReject(aError, __func__);
     961           0 :              });
     962             :   }
     963             : 
     964           0 :   TimeIntervals GetBuffered() override
     965             :   {
     966           0 :     MutexAutoLock lock(mMutex);
     967           0 :     return mBuffered;
     968             :   }
     969             : 
     970           0 :   void BreakCycles() override { }
     971             : 
     972             : private:
     973             :   Mutex mMutex;
     974             :   const RefPtr<AutoTaskQueue> mTaskQueue;
     975             :   const bool mGetSamplesMayBlock;
     976             :   const UniquePtr<TrackInfo> mInfo;
     977             :   // mTrackDemuxer is only ever accessed on demuxer's task queue.
     978             :   RefPtr<MediaTrackDemuxer> mTrackDemuxer;
     979             :   // All following members are protected by mMutex
     980             :   nsresult mNextRandomAccessPointResult = NS_OK;
     981             :   TimeUnit mNextRandomAccessPoint;
     982             :   TimeIntervals mBuffered;
     983             :   friend class DemuxerProxy;
     984             : 
     985           0 :   ~Wrapper()
     986           0 :   {
     987           0 :     RefPtr<MediaTrackDemuxer> trackDemuxer = mTrackDemuxer.forget();
     988           0 :     mTaskQueue->Dispatch(NS_NewRunnableFunction(
     989             :       "MediaFormatReader::DemuxerProxy::Wrapper::~Wrapper",
     990           0 :       [trackDemuxer]() { trackDemuxer->BreakCycles(); }));
     991           0 :   }
     992             : 
     993           0 :   void UpdateRandomAccessPoint()
     994             :   {
     995           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     996           0 :     if (!mTrackDemuxer) {
     997             :       // Detached.
     998           0 :       return;
     999             :     }
    1000           0 :     MutexAutoLock lock(mMutex);
    1001           0 :     mNextRandomAccessPointResult =
    1002           0 :       mTrackDemuxer->GetNextRandomAccessPoint(&mNextRandomAccessPoint);
    1003             :   }
    1004             : 
    1005           0 :   void UpdateBuffered()
    1006             :   {
    1007           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
    1008           0 :     if (!mTrackDemuxer) {
    1009             :       // Detached.
    1010           0 :       return;
    1011             :     }
    1012           0 :     MutexAutoLock lock(mMutex);
    1013           0 :     mBuffered = mTrackDemuxer->GetBuffered();
    1014             :   }
    1015             : };
    1016             : 
    1017             : RefPtr<MediaDataDemuxer::InitPromise>
    1018           0 : MediaFormatReader::DemuxerProxy::Init()
    1019             : {
    1020             :   using InitPromise = MediaDataDemuxer::InitPromise;
    1021             : 
    1022           0 :   RefPtr<Data> data = mData;
    1023           0 :   RefPtr<AutoTaskQueue> taskQueue = mTaskQueue;
    1024           0 :   return InvokeAsync(mTaskQueue, __func__,
    1025           0 :                      [data, taskQueue]() {
    1026           0 :                        if (!data->mDemuxer) {
    1027             :                          return InitPromise::CreateAndReject(
    1028           0 :                            NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1029             :                        }
    1030           0 :                        return data->mDemuxer->Init();
    1031           0 :                      })
    1032           0 :     ->Then(taskQueue, __func__,
    1033           0 :            [data, taskQueue]() {
    1034           0 :              if (!data->mDemuxer) { // Was shutdown.
    1035             :                return InitPromise::CreateAndReject(
    1036           0 :                    NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1037             :              }
    1038           0 :              data->mNumAudioTrack =
    1039           0 :                data->mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
    1040           0 :              if (data->mNumAudioTrack) {
    1041             :                RefPtr<MediaTrackDemuxer> d =
    1042           0 :                  data->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
    1043           0 :                if (d) {
    1044             :                  RefPtr<Wrapper> wrapper =
    1045           0 :                    new DemuxerProxy::Wrapper(d, taskQueue);
    1046           0 :                  wrapper->UpdateBuffered();
    1047           0 :                  data->mAudioDemuxer = wrapper;
    1048             :                }
    1049             :              }
    1050           0 :              data->mNumVideoTrack =
    1051           0 :                data->mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
    1052           0 :              if (data->mNumVideoTrack) {
    1053             :                RefPtr<MediaTrackDemuxer> d =
    1054           0 :                  data->mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
    1055           0 :                if (d) {
    1056             :                  RefPtr<Wrapper> wrapper =
    1057           0 :                    new DemuxerProxy::Wrapper(d, taskQueue);
    1058           0 :                  wrapper->UpdateBuffered();
    1059           0 :                  data->mVideoDemuxer = wrapper;
    1060             :                }
    1061             :              }
    1062           0 :              data->mCrypto = data->mDemuxer->GetCrypto();
    1063           0 :              data->mSeekable = data->mDemuxer->IsSeekable();
    1064           0 :              data->mSeekableOnlyInBufferedRange =
    1065           0 :                data->mDemuxer->IsSeekableOnlyInBufferedRanges();
    1066           0 :              data->mShouldComputeStartTime =
    1067           0 :                data->mDemuxer->ShouldComputeStartTime();
    1068           0 :              data->mInitDone = true;
    1069           0 :              return InitPromise::CreateAndResolve(NS_OK, __func__);
    1070             :            },
    1071           0 :            [](const MediaResult& aError) {
    1072             :              return InitPromise::CreateAndReject(aError, __func__);
    1073           0 :            });
    1074             : }
    1075             : 
    1076             : RefPtr<MediaFormatReader::NotifyDataArrivedPromise>
    1077           0 : MediaFormatReader::DemuxerProxy::NotifyDataArrived()
    1078             : {
    1079           0 :   RefPtr<Data> data = mData;
    1080           0 :   return InvokeAsync(mTaskQueue, __func__, [data]() {
    1081           0 :     if (!data->mDemuxer) {
    1082             :       // Was shutdown.
    1083             :       return NotifyDataArrivedPromise::CreateAndReject(
    1084           0 :         NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1085             :     }
    1086           0 :     data->mDemuxer->NotifyDataArrived();
    1087           0 :     if (data->mAudioDemuxer) {
    1088           0 :       data->mAudioDemuxer->UpdateBuffered();
    1089             :     }
    1090           0 :     if (data->mVideoDemuxer) {
    1091           0 :       data->mVideoDemuxer->UpdateBuffered();
    1092             :     }
    1093           0 :     return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
    1094           0 :   });
    1095             : }
    1096             : 
    1097           0 : MediaFormatReader::MediaFormatReader(const MediaDecoderReaderInit& aInit,
    1098           0 :                                      MediaDataDemuxer* aDemuxer)
    1099             :   : MediaDecoderReader(aInit)
    1100             :   , mAudio(this, MediaData::AUDIO_DATA,
    1101           0 :            MediaPrefs::MaxAudioDecodeError())
    1102             :   , mVideo(this, MediaData::VIDEO_DATA,
    1103           0 :            MediaPrefs::MaxVideoDecodeError())
    1104           0 :   , mDemuxer(new DemuxerProxy(aDemuxer))
    1105             :   , mDemuxerInitDone(false)
    1106             :   , mPendingNotifyDataArrived(false)
    1107             :   , mLastReportedNumDecodedFrames(0)
    1108             :   , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
    1109             :   , mInitDone(false)
    1110             :   , mTrackDemuxersMayBlock(false)
    1111             :   , mSeekScheduled(false)
    1112           0 :   , mVideoFrameContainer(aInit.mVideoFrameContainer)
    1113           0 :   , mDecoderFactory(new DecoderFactory(this))
    1114           0 :   , mShutdownPromisePool(new ShutdownPromisePool())
    1115             : {
    1116           0 :   MOZ_ASSERT(aDemuxer);
    1117           0 :   MOZ_COUNT_CTOR(MediaFormatReader);
    1118             : 
    1119           0 :   AbstractMediaDecoder* decoder = aInit.mDecoder;
    1120           0 :   if (decoder && decoder->CompositorUpdatedEvent()) {
    1121           0 :     mCompositorUpdatedListener = decoder->CompositorUpdatedEvent()->Connect(
    1122           0 :       mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
    1123             :   }
    1124           0 :   mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
    1125           0 :     mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
    1126           0 : }
    1127             : 
    1128           0 : MediaFormatReader::~MediaFormatReader()
    1129             : {
    1130           0 :   MOZ_COUNT_DTOR(MediaFormatReader);
    1131           0 : }
    1132             : 
    1133             : RefPtr<ShutdownPromise>
    1134           0 : MediaFormatReader::Shutdown()
    1135             : {
    1136           0 :   MOZ_ASSERT(OnTaskQueue());
    1137           0 :   LOG("");
    1138             : 
    1139           0 :   mDemuxerInitRequest.DisconnectIfExists();
    1140           0 :   mNotifyDataArrivedPromise.DisconnectIfExists();
    1141           0 :   mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1142           0 :   mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1143           0 :   mSkipRequest.DisconnectIfExists();
    1144             : 
    1145           0 :   if (mAudio.HasPromise()) {
    1146           0 :     mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1147             :   }
    1148           0 :   if (mVideo.HasPromise()) {
    1149           0 :     mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1150             :   }
    1151             : 
    1152           0 :   if (HasAudio()) {
    1153           0 :     mAudio.ResetDemuxer();
    1154           0 :     mAudio.mTrackDemuxer->BreakCycles();
    1155           0 :     mAudio.mTrackDemuxer = nullptr;
    1156           0 :     mAudio.ResetState();
    1157           0 :     ShutdownDecoder(TrackInfo::kAudioTrack);
    1158             :   }
    1159             : 
    1160           0 :   if (HasVideo()) {
    1161           0 :     mVideo.ResetDemuxer();
    1162           0 :     mVideo.mTrackDemuxer->BreakCycles();
    1163           0 :     mVideo.mTrackDemuxer = nullptr;
    1164           0 :     mVideo.ResetState();
    1165           0 :     ShutdownDecoder(TrackInfo::kVideoTrack);
    1166             :   }
    1167             : 
    1168           0 :   mShutdownPromisePool->Track(mDemuxer->Shutdown());
    1169           0 :   mDemuxer = nullptr;
    1170             : 
    1171           0 :   mCompositorUpdatedListener.DisconnectIfExists();
    1172           0 :   mOnTrackWaitingForKeyListener.Disconnect();
    1173             : 
    1174           0 :   mShutdown = true;
    1175           0 :   return mShutdownPromisePool->Shutdown()
    1176           0 :     ->Then(OwnerThread(), __func__, this,
    1177             :            &MediaFormatReader::TearDownDecoders,
    1178           0 :            &MediaFormatReader::TearDownDecoders);
    1179             : }
    1180             : 
    1181             : void
    1182           0 : MediaFormatReader::ShutdownDecoder(TrackType aTrack)
    1183             : {
    1184           0 :   LOGV("%s", TrackTypeToStr(aTrack));
    1185             : 
    1186             :   // Shut down the pending decoder if any.
    1187           0 :   mDecoderFactory->ShutdownDecoder(aTrack);
    1188             : 
    1189           0 :   auto& decoder = GetDecoderData(aTrack);
    1190             :   // Flush the decoder if necessary.
    1191           0 :   decoder.Flush();
    1192             :   // Shut down the decoder if any.
    1193           0 :   decoder.ShutdownDecoder();
    1194           0 : }
    1195             : 
    1196             : RefPtr<ShutdownPromise>
    1197           0 : MediaFormatReader::TearDownDecoders()
    1198             : {
    1199           0 :   if (mAudio.mTaskQueue) {
    1200           0 :     mAudio.mTaskQueue->BeginShutdown();
    1201           0 :     mAudio.mTaskQueue->AwaitShutdownAndIdle();
    1202           0 :     mAudio.mTaskQueue = nullptr;
    1203             :   }
    1204           0 :   if (mVideo.mTaskQueue) {
    1205           0 :     mVideo.mTaskQueue->BeginShutdown();
    1206           0 :     mVideo.mTaskQueue->AwaitShutdownAndIdle();
    1207           0 :     mVideo.mTaskQueue = nullptr;
    1208             :   }
    1209             : 
    1210           0 :   mDecoderFactory = nullptr;
    1211           0 :   mPlatform = nullptr;
    1212           0 :   mVideoFrameContainer = nullptr;
    1213             : 
    1214           0 :   return MediaDecoderReader::Shutdown();
    1215             : }
    1216             : 
    1217             : void
    1218           0 : MediaFormatReader::InitLayersBackendType()
    1219             : {
    1220             :   // Extract the layer manager backend type so that platform decoders
    1221             :   // can determine whether it's worthwhile using hardware accelerated
    1222             :   // video decoding.
    1223           0 :   if (!mDecoder) {
    1224           0 :     return;
    1225             :   }
    1226           0 :   MediaDecoderOwner* owner = mDecoder->GetOwner();
    1227           0 :   if (!owner) {
    1228           0 :     NS_WARNING("MediaFormatReader without a decoder owner, can't get HWAccel");
    1229           0 :     return;
    1230             :   }
    1231             : 
    1232           0 :   dom::HTMLMediaElement* element = owner->GetMediaElement();
    1233           0 :   NS_ENSURE_TRUE_VOID(element);
    1234             : 
    1235             :   RefPtr<LayerManager> layerManager =
    1236           0 :     nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
    1237           0 :   NS_ENSURE_TRUE_VOID(layerManager);
    1238             : 
    1239           0 :   mKnowsCompositor = layerManager->AsShadowForwarder();
    1240             : }
    1241             : 
    1242             : nsresult
    1243           0 : MediaFormatReader::InitInternal()
    1244             : {
    1245           0 :   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
    1246             : 
    1247           0 :   InitLayersBackendType();
    1248             : 
    1249             :   mAudio.mTaskQueue = new TaskQueue(
    1250           0 :     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
    1251           0 :     "MFR::mAudio::mTaskQueue");
    1252             : 
    1253             :   mVideo.mTaskQueue = new TaskQueue(
    1254           0 :     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
    1255           0 :     "MFR::mVideo::mTaskQueue");
    1256             : 
    1257           0 :   if (mDecoder) {
    1258             :     // Note: GMPCrashHelper must be created on main thread, as it may use
    1259             :     // weak references, which aren't threadsafe.
    1260           0 :     mCrashHelper = mDecoder->GetCrashHelper();
    1261             :   }
    1262           0 :   return NS_OK;
    1263             : }
    1264             : 
    1265           0 : class DispatchKeyNeededEvent : public Runnable
    1266             : {
    1267             : public:
    1268           0 :   DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
    1269             :                          nsTArray<uint8_t>& aInitData,
    1270             :                          const nsString& aInitDataType)
    1271           0 :     : Runnable("DispatchKeyNeededEvent")
    1272             :     , mDecoder(aDecoder)
    1273             :     , mInitData(aInitData)
    1274           0 :     , mInitDataType(aInitDataType)
    1275             :   {
    1276           0 :   }
    1277           0 :   NS_IMETHOD Run() override
    1278             :   {
    1279             :     // Note: Null check the owner, as the decoder could have been shutdown
    1280             :     // since this event was dispatched.
    1281           0 :     MediaDecoderOwner* owner = mDecoder->GetOwner();
    1282           0 :     if (owner) {
    1283           0 :       owner->DispatchEncrypted(mInitData, mInitDataType);
    1284             :     }
    1285           0 :     mDecoder = nullptr;
    1286           0 :     return NS_OK;
    1287             :   }
    1288             : private:
    1289             :   RefPtr<AbstractMediaDecoder> mDecoder;
    1290             :   nsTArray<uint8_t> mInitData;
    1291             :   nsString mInitDataType;
    1292             : };
    1293             : 
    1294             : void
    1295           0 : MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
    1296             : {
    1297           0 :   RefPtr<CDMProxy> proxy = aProxy;
    1298           0 :   RefPtr<MediaFormatReader> self = this;
    1299             :   nsCOMPtr<nsIRunnable> r =
    1300           0 :     NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
    1301           0 :       MOZ_ASSERT(self->OnTaskQueue());
    1302           0 :       self->mCDMProxy = proxy;
    1303           0 :     });
    1304           0 :   OwnerThread()->Dispatch(r.forget());
    1305           0 : }
    1306             : 
    1307             : bool
    1308           0 : MediaFormatReader::IsWaitingOnCDMResource()
    1309             : {
    1310           0 :   MOZ_ASSERT(OnTaskQueue());
    1311           0 :   return IsEncrypted() && !mCDMProxy;
    1312             : }
    1313             : 
    1314             : RefPtr<MediaDecoderReader::MetadataPromise>
    1315           0 : MediaFormatReader::AsyncReadMetadata()
    1316             : {
    1317           0 :   MOZ_ASSERT(OnTaskQueue());
    1318             : 
    1319           0 :   MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
    1320             : 
    1321           0 :   if (mInitDone) {
    1322             :     // We are returning from dormant.
    1323           0 :     MetadataHolder metadata;
    1324           0 :     metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
    1325           0 :     return MetadataPromise::CreateAndResolve(Move(metadata), __func__);
    1326             :   }
    1327             : 
    1328           0 :   RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
    1329             : 
    1330           0 :   mDemuxer->Init()
    1331           0 :     ->Then(OwnerThread(), __func__, this,
    1332             :            &MediaFormatReader::OnDemuxerInitDone,
    1333             :            &MediaFormatReader::OnDemuxerInitFailed)
    1334           0 :     ->Track(mDemuxerInitRequest);
    1335           0 :   return p;
    1336             : }
    1337             : 
    1338             : void
    1339           0 : MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult)
    1340             : {
    1341           0 :   MOZ_ASSERT(OnTaskQueue());
    1342           0 :   mDemuxerInitRequest.Complete();
    1343             : 
    1344           0 :   if (NS_FAILED(aResult) && MediaPrefs::MediaWarningsAsErrors()) {
    1345           0 :     mMetadataPromise.Reject(aResult, __func__);
    1346           0 :     return;
    1347             :   }
    1348             : 
    1349           0 :   mDemuxerInitDone = true;
    1350             : 
    1351           0 :   UniquePtr<MetadataTags> tags(MakeUnique<MetadataTags>());
    1352             : 
    1353           0 :   RefPtr<PDMFactory> platform;
    1354           0 :   if (!IsWaitingOnCDMResource()) {
    1355           0 :     platform = new PDMFactory();
    1356             :   }
    1357             : 
    1358             :   // To decode, we need valid video and a place to put it.
    1359             :   bool videoActive =
    1360           0 :     !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && GetImageContainer();
    1361             : 
    1362           0 :   if (videoActive) {
    1363             :     // We currently only handle the first video track.
    1364           0 :     mVideo.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
    1365           0 :     if (!mVideo.mTrackDemuxer) {
    1366           0 :       mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
    1367           0 :       return;
    1368             :     }
    1369             : 
    1370           0 :     UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
    1371           0 :     videoActive = videoInfo && videoInfo->IsValid();
    1372           0 :     if (videoActive) {
    1373           0 :       if (platform
    1374           0 :           && !platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
    1375             :         // We have no decoder for this track. Error.
    1376           0 :         mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
    1377           0 :         return;
    1378             :       }
    1379           0 :       mInfo.mVideo = *videoInfo->GetAsVideoInfo();
    1380           0 :       for (const MetadataTag& tag : videoInfo->mTags) {
    1381           0 :         tags->Put(tag.mKey, tag.mValue);
    1382             :       }
    1383           0 :       mVideo.mOriginalInfo = Move(videoInfo);
    1384           0 :       mTrackDemuxersMayBlock |= mVideo.mTrackDemuxer->GetSamplesMayBlock();
    1385             :     } else {
    1386           0 :       mVideo.mTrackDemuxer->BreakCycles();
    1387           0 :       mVideo.mTrackDemuxer = nullptr;
    1388             :     }
    1389             :   }
    1390             : 
    1391           0 :   bool audioActive = !!mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
    1392           0 :   if (audioActive) {
    1393           0 :     mAudio.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
    1394           0 :     if (!mAudio.mTrackDemuxer) {
    1395           0 :       mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
    1396           0 :       return;
    1397             :     }
    1398             : 
    1399           0 :     UniquePtr<TrackInfo> audioInfo = mAudio.mTrackDemuxer->GetInfo();
    1400             :     // We actively ignore audio tracks that we know we can't play.
    1401           0 :     audioActive =
    1402             :       audioInfo
    1403           0 :       && audioInfo->IsValid()
    1404           0 :       && (!platform || platform->SupportsMimeType(audioInfo->mMimeType,
    1405             :                                                   nullptr));
    1406             : 
    1407           0 :     if (audioActive) {
    1408           0 :       mInfo.mAudio = *audioInfo->GetAsAudioInfo();
    1409           0 :       for (const MetadataTag& tag : audioInfo->mTags) {
    1410           0 :         tags->Put(tag.mKey, tag.mValue);
    1411             :       }
    1412           0 :       mAudio.mOriginalInfo = Move(audioInfo);
    1413           0 :       mTrackDemuxersMayBlock |= mAudio.mTrackDemuxer->GetSamplesMayBlock();
    1414             :     } else {
    1415           0 :       mAudio.mTrackDemuxer->BreakCycles();
    1416           0 :       mAudio.mTrackDemuxer = nullptr;
    1417             :     }
    1418             :   }
    1419             : 
    1420           0 :   UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
    1421           0 :   if (mDecoder && crypto && crypto->IsEncrypted()) {
    1422             :     // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
    1423           0 :     for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
    1424             :       nsCOMPtr<nsIRunnable> r =
    1425           0 :         new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData,
    1426           0 :                                    crypto->mInitDatas[i].mType);
    1427           0 :       mDecoder->AbstractMainThread()->Dispatch(r.forget());
    1428             :     }
    1429           0 :     mInfo.mCrypto = *crypto;
    1430             :   }
    1431             : 
    1432           0 :   auto videoDuration = HasVideo() ? mInfo.mVideo.mDuration : TimeUnit::Zero();
    1433           0 :   auto audioDuration = HasAudio() ? mInfo.mAudio.mDuration : TimeUnit::Zero();
    1434             : 
    1435           0 :   auto duration = std::max(videoDuration, audioDuration);
    1436           0 :   if (duration.IsPositive()) {
    1437           0 :     mInfo.mMetadataDuration = Some(duration);
    1438             :   }
    1439             : 
    1440           0 :   mInfo.mMediaSeekable = mDemuxer->IsSeekable();
    1441           0 :   mInfo.mMediaSeekableOnlyInBufferedRanges =
    1442           0 :     mDemuxer->IsSeekableOnlyInBufferedRanges();
    1443             : 
    1444           0 :   if (!videoActive && !audioActive) {
    1445           0 :     mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
    1446           0 :     return;
    1447             :   }
    1448             : 
    1449           0 :   mTags = Move(tags);
    1450           0 :   mInitDone = true;
    1451             : 
    1452             :   // Try to get the start time.
    1453             :   // For MSE case, the start time of each track is assumed to be 0.
    1454             :   // For others, we must demux the first sample to know the start time for each
    1455             :   // track.
    1456           0 :   if (!mDemuxer->ShouldComputeStartTime()) {
    1457           0 :     mAudio.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
    1458           0 :     mVideo.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
    1459             :   } else {
    1460           0 :     if (HasAudio()) {
    1461           0 :       RequestDemuxSamples(TrackInfo::kAudioTrack);
    1462             :     }
    1463             : 
    1464           0 :     if (HasVideo()) {
    1465           0 :       RequestDemuxSamples(TrackInfo::kVideoTrack);
    1466             :     }
    1467             :   }
    1468             : 
    1469           0 :   if (aResult != NS_OK && mDecoder) {
    1470           0 :     RefPtr<AbstractMediaDecoder> decoder = mDecoder;
    1471           0 :     mDecoder->AbstractMainThread()->Dispatch(NS_NewRunnableFunction(
    1472           0 :       "MediaFormatReader::OnDemuxerInitDone", [decoder, aResult]() {
    1473           0 :         if (decoder->GetOwner()) {
    1474           0 :           decoder->GetOwner()->DecodeWarning(aResult);
    1475             :         }
    1476           0 :       }));
    1477             :   }
    1478             : 
    1479           0 :   MaybeResolveMetadataPromise();
    1480             : }
    1481             : 
    1482             : void
    1483           0 : MediaFormatReader::MaybeResolveMetadataPromise()
    1484             : {
    1485           0 :   MOZ_ASSERT(OnTaskQueue());
    1486             : 
    1487           0 :   if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing())
    1488           0 :       || (HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
    1489           0 :     return;
    1490             :   }
    1491             : 
    1492             :   TimeUnit startTime =
    1493           0 :     std::min(mAudio.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()),
    1494           0 :              mVideo.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()));
    1495             : 
    1496           0 :   if (!startTime.IsInfinite()) {
    1497           0 :     mInfo.mStartTime = startTime; // mInfo.mStartTime is initialized to 0.
    1498             :   }
    1499             : 
    1500           0 :   MetadataHolder metadata;
    1501           0 :   metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
    1502           0 :   metadata.mTags = mTags->Count() ? Move(mTags) : nullptr;
    1503             : 
    1504             :   // We now have all the informations required to calculate the initial buffered
    1505             :   // range.
    1506           0 :   mHasStartTime = true;
    1507           0 :   UpdateBuffered();
    1508             : 
    1509           0 :   mMetadataPromise.Resolve(Move(metadata), __func__);
    1510             : }
    1511             : 
    1512             : bool
    1513           0 : MediaFormatReader::IsEncrypted() const
    1514             : {
    1515           0 :   return (HasAudio() && mInfo.mAudio.mCrypto.mValid)
    1516           0 :          || (HasVideo() && mInfo.mVideo.mCrypto.mValid);
    1517             : }
    1518             : 
    1519             : void
    1520           0 : MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
    1521             : {
    1522           0 :   mDemuxerInitRequest.Complete();
    1523           0 :   mMetadataPromise.Reject(aError, __func__);
    1524           0 : }
    1525             : 
    1526             : void
    1527           0 : MediaFormatReader::ReadUpdatedMetadata(MediaInfo* aInfo)
    1528             : {
    1529           0 :   *aInfo = mInfo;
    1530           0 : }
    1531             : 
    1532             : MediaFormatReader::DecoderData&
    1533           0 : MediaFormatReader::GetDecoderData(TrackType aTrack)
    1534             : {
    1535           0 :   MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
    1536             :              || aTrack == TrackInfo::kVideoTrack);
    1537           0 :   if (aTrack == TrackInfo::kAudioTrack) {
    1538           0 :     return mAudio;
    1539             :   }
    1540           0 :   return mVideo;
    1541             : }
    1542             : 
    1543             : bool
    1544           0 : MediaFormatReader::ShouldSkip(TimeUnit aTimeThreshold)
    1545             : {
    1546           0 :   MOZ_ASSERT(HasVideo());
    1547             : 
    1548           0 :   if (!MediaPrefs::MFRSkipToNextKeyFrameEnabled()) {
    1549           0 :     return false;
    1550             :   }
    1551             : 
    1552           0 :   TimeUnit nextKeyframe;
    1553           0 :   nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
    1554           0 :   if (NS_FAILED(rv)) {
    1555             :     // Only OggTrackDemuxer with video type gets into here.
    1556             :     // We don't support skip-to-next-frame for this case.
    1557           0 :     return false;
    1558             :   }
    1559           0 :   return (nextKeyframe <= aTimeThreshold
    1560           0 :           || (mVideo.mTimeThreshold
    1561           0 :               && mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold))
    1562           0 :          && nextKeyframe.ToMicroseconds() >= 0
    1563           0 :          && !nextKeyframe.IsInfinite();
    1564             : }
    1565             : 
    1566             : RefPtr<MediaDecoderReader::VideoDataPromise>
    1567           0 : MediaFormatReader::RequestVideoData(const TimeUnit& aTimeThreshold)
    1568             : {
    1569           0 :   MOZ_ASSERT(OnTaskQueue());
    1570           0 :   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
    1571             :                         "No sample requests allowed while seeking");
    1572           0 :   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
    1573           0 :   MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists()
    1574             :                         || mVideo.mTimeThreshold.isSome());
    1575           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
    1576           0 :   LOGV("RequestVideoData(%" PRId64 ")", aTimeThreshold.ToMicroseconds());
    1577             : 
    1578           0 :   if (!HasVideo()) {
    1579           0 :     LOG("called with no video track");
    1580             :     return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    1581           0 :                                              __func__);
    1582             :   }
    1583             : 
    1584           0 :   if (IsSeeking()) {
    1585           0 :     LOG("called mid-seek. Rejecting.");
    1586             :     return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
    1587           0 :                                              __func__);
    1588             :   }
    1589             : 
    1590           0 :   if (mShutdown) {
    1591           0 :     NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
    1592             :     return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
    1593           0 :                                              __func__);
    1594             :   }
    1595             : 
    1596             :   // Ensure we have no pending seek going as ShouldSkip could return out of date
    1597             :   // information.
    1598           0 :   if (!mVideo.HasInternalSeekPending() && ShouldSkip(aTimeThreshold)) {
    1599           0 :     RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
    1600           0 :     SkipVideoDemuxToNextKeyFrame(aTimeThreshold);
    1601           0 :     return p;
    1602             :   }
    1603             : 
    1604           0 :   RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
    1605           0 :   ScheduleUpdate(TrackInfo::kVideoTrack);
    1606             : 
    1607           0 :   return p;
    1608             : }
    1609             : 
    1610             : void
    1611           0 : MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError)
    1612             : {
    1613           0 :   MOZ_ASSERT(OnTaskQueue());
    1614           0 :   LOG("Failed to demux %s, failure:%" PRIu32,
    1615             :       aTrack == TrackType::kVideoTrack ? "video" : "audio",
    1616             :       static_cast<uint32_t>(aError.Code()));
    1617           0 :   auto& decoder = GetDecoderData(aTrack);
    1618           0 :   decoder.mDemuxRequest.Complete();
    1619           0 :   switch (aError.Code()) {
    1620             :     case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
    1621           0 :       if (!decoder.mWaitingForData) {
    1622           0 :         decoder.RequestDrain();
    1623             :       }
    1624           0 :       NotifyEndOfStream(aTrack);
    1625           0 :       break;
    1626             :     case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
    1627           0 :       if (!decoder.mWaitingForData) {
    1628           0 :         decoder.RequestDrain();
    1629             :       }
    1630           0 :       NotifyWaitingForData(aTrack);
    1631           0 :       break;
    1632             :     case NS_ERROR_DOM_MEDIA_CANCELED:
    1633           0 :       if (decoder.HasPromise()) {
    1634           0 :         decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    1635             :       }
    1636           0 :       break;
    1637             :     default:
    1638           0 :       NotifyError(aTrack, aError);
    1639           0 :       break;
    1640             :   }
    1641           0 : }
    1642             : 
    1643             : void
    1644           0 : MediaFormatReader::DoDemuxVideo()
    1645             : {
    1646             :   using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
    1647             : 
    1648           0 :   auto p = mVideo.mTrackDemuxer->GetSamples(1);
    1649             : 
    1650           0 :   if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
    1651           0 :     RefPtr<MediaFormatReader> self = this;
    1652           0 :     p = p->Then(OwnerThread(), __func__,
    1653           0 :                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
    1654           0 :                   self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
    1655           0 :                   return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
    1656             :                 },
    1657           0 :                 [self] (const MediaResult& aError) {
    1658           0 :                   self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
    1659           0 :                   return SamplesPromise::CreateAndReject(aError, __func__);
    1660           0 :                 });
    1661             :   }
    1662             : 
    1663           0 :   p->Then(OwnerThread(), __func__, this,
    1664             :           &MediaFormatReader::OnVideoDemuxCompleted,
    1665             :           &MediaFormatReader::OnVideoDemuxFailed)
    1666           0 :    ->Track(mVideo.mDemuxRequest);
    1667           0 : }
    1668             : 
    1669             : void
    1670           0 : MediaFormatReader::OnVideoDemuxCompleted(
    1671             :   RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
    1672             : {
    1673           0 :   LOGV("%" PRIuSIZE " video samples demuxed (sid:%d)",
    1674             :        aSamples->mSamples.Length(),
    1675             :        aSamples->mSamples[0]->mTrackInfo
    1676             :        ? aSamples->mSamples[0]->mTrackInfo->GetID()
    1677             :        : 0);
    1678           0 :   mVideo.mDemuxRequest.Complete();
    1679           0 :   mVideo.mQueuedSamples.AppendElements(aSamples->mSamples);
    1680           0 :   ScheduleUpdate(TrackInfo::kVideoTrack);
    1681           0 : }
    1682             : 
    1683             : RefPtr<MediaDecoderReader::AudioDataPromise>
    1684           0 : MediaFormatReader::RequestAudioData()
    1685             : {
    1686           0 :   MOZ_ASSERT(OnTaskQueue());
    1687           0 :   MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
    1688           0 :   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
    1689             :                         "No sample requests allowed while seeking");
    1690           0 :   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking()
    1691             :                         || !mAudio.mSeekRequest.Exists()
    1692             :                         || mAudio.mTimeThreshold.isSome());
    1693           0 :   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
    1694           0 :   LOGV("");
    1695             : 
    1696           0 :   if (!HasAudio()) {
    1697           0 :     LOG("called with no audio track");
    1698             :     return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    1699           0 :                                              __func__);
    1700             :   }
    1701             : 
    1702           0 :   if (IsSeeking()) {
    1703           0 :     LOG("called mid-seek. Rejecting.");
    1704             :     return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
    1705           0 :                                              __func__);
    1706             :   }
    1707             : 
    1708           0 :   if (mShutdown) {
    1709           0 :     NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
    1710             :     return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
    1711           0 :                                              __func__);
    1712             :   }
    1713             : 
    1714           0 :   RefPtr<AudioDataPromise> p = mAudio.EnsurePromise(__func__);
    1715           0 :   ScheduleUpdate(TrackInfo::kAudioTrack);
    1716             : 
    1717           0 :   return p;
    1718             : }
    1719             : 
    1720             : void
    1721           0 : MediaFormatReader::DoDemuxAudio()
    1722             : {
    1723             :   using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
    1724             : 
    1725           0 :   auto p = mAudio.mTrackDemuxer->GetSamples(1);
    1726             : 
    1727           0 :   if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
    1728           0 :     RefPtr<MediaFormatReader> self = this;
    1729           0 :     p = p->Then(OwnerThread(), __func__,
    1730           0 :                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
    1731           0 :                   self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
    1732           0 :                   return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
    1733             :                 },
    1734           0 :                 [self] (const MediaResult& aError) {
    1735           0 :                   self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
    1736           0 :                   return SamplesPromise::CreateAndReject(aError, __func__);
    1737           0 :                 });
    1738             :   }
    1739             : 
    1740           0 :   p->Then(OwnerThread(), __func__, this,
    1741             :           &MediaFormatReader::OnAudioDemuxCompleted,
    1742             :           &MediaFormatReader::OnAudioDemuxFailed)
    1743           0 :    ->Track(mAudio.mDemuxRequest);
    1744           0 : }
    1745             : 
    1746             : void
    1747           0 : MediaFormatReader::OnAudioDemuxCompleted(
    1748             :   RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
    1749             : {
    1750           0 :   LOGV("%" PRIuSIZE " audio samples demuxed (sid:%d)",
    1751             :        aSamples->mSamples.Length(),
    1752             :        aSamples->mSamples[0]->mTrackInfo
    1753             :        ? aSamples->mSamples[0]->mTrackInfo->GetID()
    1754             :        : 0);
    1755           0 :   mAudio.mDemuxRequest.Complete();
    1756           0 :   mAudio.mQueuedSamples.AppendElements(aSamples->mSamples);
    1757           0 :   ScheduleUpdate(TrackInfo::kAudioTrack);
    1758           0 : }
    1759             : 
    1760             : void
    1761           0 : MediaFormatReader::NotifyNewOutput(
    1762             :   TrackType aTrack, const MediaDataDecoder::DecodedData& aResults)
    1763             : {
    1764           0 :   MOZ_ASSERT(OnTaskQueue());
    1765           0 :   auto& decoder = GetDecoderData(aTrack);
    1766           0 :   for (auto& sample : aResults) {
    1767           0 :     LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
    1768             :          TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(),
    1769             :          sample->mDuration.ToMicroseconds());
    1770           0 :     decoder.mOutput.AppendElement(sample);
    1771           0 :     decoder.mNumSamplesOutput++;
    1772           0 :     decoder.mNumOfConsecutiveError = 0;
    1773             :   }
    1774           0 :   LOG("Done processing new %s samples", TrackTypeToStr(aTrack));
    1775             : 
    1776           0 :   if (!aResults.IsEmpty()) {
    1777             :     // We have decoded our first frame, we can now starts to skip future errors.
    1778           0 :     decoder.mFirstFrameTime.reset();
    1779             :   }
    1780           0 :   ScheduleUpdate(aTrack);
    1781           0 : }
    1782             : 
    1783             : void
    1784           0 : MediaFormatReader::NotifyError(TrackType aTrack, const MediaResult& aError)
    1785             : {
    1786           0 :   MOZ_ASSERT(OnTaskQueue());
    1787           0 :   NS_WARNING(aError.Description().get());
    1788           0 :   LOGV("%s Decoding error", TrackTypeToStr(aTrack));
    1789           0 :   auto& decoder = GetDecoderData(aTrack);
    1790           0 :   decoder.mError = decoder.HasFatalError() ? decoder.mError : Some(aError);
    1791           0 :   ScheduleUpdate(aTrack);
    1792           0 : }
    1793             : 
    1794             : void
    1795           0 : MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
    1796             : {
    1797           0 :   MOZ_ASSERT(OnTaskQueue());
    1798           0 :   auto& decoder = GetDecoderData(aTrack);
    1799           0 :   decoder.mWaitingForData = true;
    1800           0 :   if (decoder.mTimeThreshold) {
    1801           0 :     decoder.mTimeThreshold.ref().mWaiting = true;
    1802             :   }
    1803           0 :   ScheduleUpdate(aTrack);
    1804           0 : }
    1805             : 
    1806             : void
    1807           0 : MediaFormatReader::NotifyWaitingForKey(TrackType aTrack)
    1808             : {
    1809           0 :   MOZ_ASSERT(OnTaskQueue());
    1810           0 :   auto& decoder = GetDecoderData(aTrack);
    1811           0 :   if (mDecoder) {
    1812           0 :     mDecoder->NotifyWaitingForKey();
    1813             :   }
    1814           0 :   if (!decoder.mDecodeRequest.Exists()) {
    1815           0 :     LOGV("WaitingForKey received while no pending decode. Ignoring");
    1816           0 :     return;
    1817             :   }
    1818           0 :   decoder.mWaitingForKey = true;
    1819           0 :   ScheduleUpdate(aTrack);
    1820             : }
    1821             : 
    1822             : void
    1823           0 : MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
    1824             : {
    1825           0 :   MOZ_ASSERT(OnTaskQueue());
    1826           0 :   auto& decoder = GetDecoderData(aTrack);
    1827           0 :   decoder.mDemuxEOS = true;
    1828           0 :   ScheduleUpdate(aTrack);
    1829           0 : }
    1830             : 
    1831             : bool
    1832           0 : MediaFormatReader::NeedInput(DecoderData& aDecoder)
    1833             : {
    1834             :   // The decoder will not be fed a new raw sample until the current decoding
    1835             :   // requests has completed.
    1836             :   return
    1837           0 :     (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome())
    1838           0 :     && !aDecoder.HasPendingDrain()
    1839           0 :     && !aDecoder.HasFatalError()
    1840           0 :     && !aDecoder.mDemuxRequest.Exists()
    1841           0 :     && !aDecoder.mOutput.Length()
    1842           0 :     && !aDecoder.HasInternalSeekPending()
    1843           0 :     && !aDecoder.mDecodeRequest.Exists();
    1844             : }
    1845             : 
    1846             : void
    1847           0 : MediaFormatReader::ScheduleUpdate(TrackType aTrack)
    1848             : {
    1849           0 :   MOZ_ASSERT(OnTaskQueue());
    1850           0 :   if (mShutdown) {
    1851           0 :     return;
    1852             :   }
    1853           0 :   auto& decoder = GetDecoderData(aTrack);
    1854           0 :   if (decoder.mUpdateScheduled) {
    1855           0 :     return;
    1856             :   }
    1857           0 :   LOGV("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
    1858           0 :   decoder.mUpdateScheduled = true;
    1859           0 :   RefPtr<nsIRunnable> task(NewRunnableMethod<TrackType>(
    1860           0 :     "MediaFormatReader::Update", this, &MediaFormatReader::Update, aTrack));
    1861           0 :   OwnerThread()->Dispatch(task.forget());
    1862             : }
    1863             : 
    1864             : bool
    1865           0 : MediaFormatReader::UpdateReceivedNewData(TrackType aTrack)
    1866             : {
    1867           0 :   MOZ_ASSERT(OnTaskQueue());
    1868           0 :   auto& decoder = GetDecoderData(aTrack);
    1869             : 
    1870           0 :   if (!decoder.mReceivedNewData) {
    1871           0 :     return false;
    1872             :   }
    1873             : 
    1874             :   // We do not want to clear mWaitingForData while there are pending
    1875             :   // demuxing or seeking operations that could affect the value of this flag.
    1876             :   // This is in order to ensure that we will retry once they complete as we may
    1877             :   // now have new data that could potentially allow those operations to
    1878             :   // successfully complete if tried again.
    1879           0 :   if (decoder.mSeekRequest.Exists()) {
    1880             :     // Nothing more to do until this operation complete.
    1881           0 :     return true;
    1882             :   }
    1883             : 
    1884           0 :   if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
    1885           0 :     LOGV("Skipping in progress, nothing more to do");
    1886           0 :     return true;
    1887             :   }
    1888             : 
    1889           0 :   if (decoder.mDemuxRequest.Exists()) {
    1890             :     // We may have pending operations to process, so we want to continue
    1891             :     // after UpdateReceivedNewData returns.
    1892           0 :     return false;
    1893             :   }
    1894             : 
    1895           0 :   if (decoder.HasPendingDrain()) {
    1896             :     // We do not want to clear mWaitingForData or mDemuxEOS while
    1897             :     // a drain is in progress in order to properly complete the operation.
    1898           0 :     return false;
    1899             :   }
    1900             : 
    1901           0 :   decoder.mReceivedNewData = false;
    1902           0 :   if (decoder.mTimeThreshold) {
    1903           0 :     decoder.mTimeThreshold.ref().mWaiting = false;
    1904             :   }
    1905           0 :   decoder.mWaitingForData = false;
    1906             : 
    1907           0 :   if (decoder.HasFatalError()) {
    1908           0 :     return false;
    1909             :   }
    1910             : 
    1911           0 :   if (!mSeekPromise.IsEmpty()
    1912           0 :       && (!IsVideoSeeking() || aTrack == TrackInfo::kVideoTrack)) {
    1913           0 :     MOZ_ASSERT(!decoder.HasPromise());
    1914           0 :     MOZ_DIAGNOSTIC_ASSERT(
    1915             :       (IsVideoSeeking() || !mAudio.mTimeThreshold) && !mVideo.mTimeThreshold,
    1916             :       "InternalSeek must have been aborted when Seek was first called");
    1917           0 :     MOZ_DIAGNOSTIC_ASSERT(
    1918             :       (IsVideoSeeking() || !mAudio.HasWaitingPromise())
    1919             :       && !mVideo.HasWaitingPromise(),
    1920             :       "Waiting promises must have been rejected when Seek was first called");
    1921           0 :     if (mVideo.mSeekRequest.Exists()
    1922           0 :         || (!IsVideoSeeking() && mAudio.mSeekRequest.Exists())) {
    1923             :       // Already waiting for a seek to complete. Nothing more to do.
    1924           0 :       return true;
    1925             :     }
    1926           0 :     LOG("Attempting Seek");
    1927           0 :     ScheduleSeek();
    1928           0 :     return true;
    1929             :   }
    1930           0 :   if (decoder.HasInternalSeekPending() || decoder.HasWaitingPromise()) {
    1931           0 :     if (decoder.HasInternalSeekPending()) {
    1932           0 :       LOG("Attempting Internal Seek");
    1933           0 :       InternalSeek(aTrack, decoder.mTimeThreshold.ref());
    1934             :     }
    1935           0 :     if (decoder.HasWaitingPromise() && !decoder.IsWaiting()) {
    1936           0 :       MOZ_ASSERT(!decoder.HasPromise());
    1937           0 :       LOG("We have new data. Resolving WaitingPromise");
    1938           0 :       decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
    1939             :     }
    1940           0 :     return true;
    1941             :   }
    1942           0 :   return false;
    1943             : }
    1944             : 
    1945             : void
    1946           0 : MediaFormatReader::RequestDemuxSamples(TrackType aTrack)
    1947             : {
    1948           0 :   MOZ_ASSERT(OnTaskQueue());
    1949           0 :   auto& decoder = GetDecoderData(aTrack);
    1950           0 :   MOZ_ASSERT(!decoder.mDemuxRequest.Exists());
    1951             : 
    1952           0 :   if (!decoder.mQueuedSamples.IsEmpty()) {
    1953             :     // No need to demux new samples.
    1954           0 :     return;
    1955             :   }
    1956             : 
    1957           0 :   if (decoder.mDemuxEOS) {
    1958             :     // Nothing left to demux.
    1959             :     // We do not want to attempt to demux while in waiting for data mode
    1960             :     // as it would retrigger an unecessary drain.
    1961           0 :     return;
    1962             :   }
    1963             : 
    1964           0 :   LOGV("Requesting extra demux %s", TrackTypeToStr(aTrack));
    1965           0 :   if (aTrack == TrackInfo::kVideoTrack) {
    1966           0 :     DoDemuxVideo();
    1967             :   } else {
    1968           0 :     DoDemuxAudio();
    1969             :   }
    1970             : }
    1971             : 
    1972             : void
    1973           0 : MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
    1974             :                                         MediaRawData* aSample)
    1975             : {
    1976           0 :   MOZ_ASSERT(OnTaskQueue());
    1977           0 :   auto& decoder = GetDecoderData(aTrack);
    1978           0 :   RefPtr<MediaFormatReader> self = this;
    1979           0 :   decoder.mFlushed = false;
    1980           0 :   decoder.mDecoder->Decode(aSample)
    1981           0 :     ->Then(mTaskQueue, __func__,
    1982           0 :            [self, this, aTrack, &decoder]
    1983           0 :            (const MediaDataDecoder::DecodedData& aResults) {
    1984           0 :              decoder.mDecodeRequest.Complete();
    1985           0 :              NotifyNewOutput(aTrack, aResults);
    1986           0 :            },
    1987           0 :            [self, this, aTrack, &decoder](const MediaResult& aError) {
    1988           0 :              decoder.mDecodeRequest.Complete();
    1989           0 :              NotifyError(aTrack, aError);
    1990           0 :            })
    1991           0 :     ->Track(decoder.mDecodeRequest);
    1992           0 : }
    1993             : 
    1994             : void
    1995           0 : MediaFormatReader::HandleDemuxedSamples(
    1996             :   TrackType aTrack, AbstractMediaDecoder::AutoNotifyDecoded& aA)
    1997             : {
    1998           0 :   MOZ_ASSERT(OnTaskQueue());
    1999             : 
    2000           0 :   auto& decoder = GetDecoderData(aTrack);
    2001             : 
    2002           0 :   if (decoder.mFlushing) {
    2003           0 :     LOGV("Decoder operation in progress, let it complete.");
    2004           0 :     return;
    2005             :   }
    2006             : 
    2007           0 :   if (decoder.mQueuedSamples.IsEmpty()) {
    2008           0 :     return;
    2009             :   }
    2010             : 
    2011           0 :   if (!decoder.mDecoder) {
    2012           0 :     mDecoderFactory->CreateDecoder(aTrack);
    2013           0 :     return;
    2014             :   }
    2015             : 
    2016           0 :   LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
    2017             : 
    2018             :   // Decode all our demuxed frames.
    2019           0 :   while (decoder.mQueuedSamples.Length()) {
    2020           0 :     RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
    2021           0 :     RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
    2022             : 
    2023           0 :     if (info && decoder.mLastStreamSourceID != info->GetID()) {
    2024           0 :       bool recyclable = MediaPrefs::MediaDecoderCheckRecycling()
    2025           0 :                         && decoder.mDecoder->SupportDecoderRecycling();
    2026           0 :       if (!recyclable
    2027           0 :           && decoder.mTimeThreshold.isNothing()
    2028           0 :           && (decoder.mNextStreamSourceID.isNothing()
    2029           0 :               || decoder.mNextStreamSourceID.ref() != info->GetID())) {
    2030           0 :         LOG("%s stream id has changed from:%d to:%d, draining decoder.",
    2031             :           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
    2032             :           info->GetID());
    2033           0 :         decoder.RequestDrain();
    2034           0 :         decoder.mNextStreamSourceID = Some(info->GetID());
    2035           0 :         ScheduleUpdate(aTrack);
    2036           0 :         return;
    2037             :       }
    2038             : 
    2039           0 :       LOG("%s stream id has changed from:%d to:%d.",
    2040             :           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
    2041             :           info->GetID());
    2042           0 :       decoder.mLastStreamSourceID = info->GetID();
    2043           0 :       decoder.mNextStreamSourceID.reset();
    2044             : 
    2045           0 :       if (!recyclable) {
    2046           0 :         LOG("Decoder does not support recycling, recreate decoder.");
    2047             :         // If flushing is required, it will clear our array of queued samples.
    2048             :         // So make a copy now.
    2049           0 :         nsTArray<RefPtr<MediaRawData>> samples{ Move(decoder.mQueuedSamples) };
    2050           0 :         ShutdownDecoder(aTrack);
    2051           0 :         if (sample->mKeyframe) {
    2052           0 :           decoder.mQueuedSamples.AppendElements(Move(samples));
    2053             :         }
    2054           0 :       } else if (decoder.HasWaitingPromise()) {
    2055           0 :         decoder.Flush();
    2056             :       }
    2057             : 
    2058           0 :       decoder.mInfo = info;
    2059             : 
    2060           0 :       if (sample->mKeyframe) {
    2061           0 :         ScheduleUpdate(aTrack);
    2062             :       } else {
    2063           0 :         auto time = TimeInterval(sample->mTime, sample->GetEndTime());
    2064             :         InternalSeekTarget seekTarget =
    2065           0 :           decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
    2066           0 :         LOG("Stream change occurred on a non-keyframe. Seeking to:%" PRId64,
    2067             :             sample->mTime.ToMicroseconds());
    2068           0 :         InternalSeek(aTrack, seekTarget);
    2069             :       }
    2070           0 :       return;
    2071             :     }
    2072             : 
    2073           0 :     LOGV("Input:%" PRId64 " (dts:%" PRId64 " kf:%d)",
    2074             :          sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(),
    2075             :          sample->mKeyframe);
    2076           0 :     decoder.mNumSamplesInput++;
    2077           0 :     decoder.mSizeOfQueue++;
    2078           0 :     if (aTrack == TrackInfo::kVideoTrack) {
    2079           0 :       aA.mStats.mParsedFrames++;
    2080             :     }
    2081             : 
    2082           0 :     DecodeDemuxedSamples(aTrack, sample);
    2083             : 
    2084           0 :     decoder.mQueuedSamples.RemoveElementAt(0);
    2085           0 :     break;
    2086             :   }
    2087             : }
    2088             : 
    2089             : void
    2090           0 : MediaFormatReader::InternalSeek(TrackType aTrack,
    2091             :                                 const InternalSeekTarget& aTarget)
    2092             : {
    2093           0 :   MOZ_ASSERT(OnTaskQueue());
    2094           0 :   LOG("%s internal seek to %f",
    2095             :       TrackTypeToStr(aTrack), aTarget.Time().ToSeconds());
    2096             : 
    2097           0 :   auto& decoder = GetDecoderData(aTrack);
    2098           0 :   decoder.Flush();
    2099           0 :   decoder.ResetDemuxer();
    2100           0 :   decoder.mTimeThreshold = Some(aTarget);
    2101           0 :   RefPtr<MediaFormatReader> self = this;
    2102           0 :   decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
    2103           0 :     ->Then(OwnerThread(), __func__,
    2104           0 :            [self, aTrack] (TimeUnit aTime) {
    2105           0 :              auto& decoder = self->GetDecoderData(aTrack);
    2106           0 :              decoder.mSeekRequest.Complete();
    2107           0 :              MOZ_ASSERT(
    2108             :                decoder.mTimeThreshold,
    2109             :                "Seek promise must be disconnected when timethreshold is reset");
    2110           0 :              decoder.mTimeThreshold.ref().mHasSeeked = true;
    2111           0 :              self->SetVideoDecodeThreshold();
    2112           0 :              self->ScheduleUpdate(aTrack);
    2113           0 :            },
    2114           0 :            [self, aTrack] (const MediaResult& aError) {
    2115           0 :              auto& decoder = self->GetDecoderData(aTrack);
    2116           0 :              decoder.mSeekRequest.Complete();
    2117           0 :              switch (aError.Code()) {
    2118             :                case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
    2119           0 :                  self->NotifyWaitingForData(aTrack);
    2120           0 :                  break;
    2121             :                case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
    2122           0 :                  decoder.mTimeThreshold.reset();
    2123           0 :                  self->NotifyEndOfStream(aTrack);
    2124           0 :                  break;
    2125             :                case NS_ERROR_DOM_MEDIA_CANCELED:
    2126           0 :                  decoder.mTimeThreshold.reset();
    2127           0 :                  break;
    2128             :                default:
    2129           0 :                  decoder.mTimeThreshold.reset();
    2130           0 :                  self->NotifyError(aTrack, aError);
    2131           0 :                  break;
    2132             :              }
    2133           0 :            })
    2134           0 :     ->Track(decoder.mSeekRequest);
    2135           0 : }
    2136             : 
    2137             : void
    2138           0 : MediaFormatReader::DrainDecoder(TrackType aTrack)
    2139             : {
    2140           0 :   MOZ_ASSERT(OnTaskQueue());
    2141             : 
    2142           0 :   auto& decoder = GetDecoderData(aTrack);
    2143           0 :   if (decoder.mDrainState == DrainState::Draining) {
    2144           0 :     return;
    2145             :   }
    2146           0 :   if (!decoder.mDecoder
    2147           0 :       || (decoder.mDrainState != DrainState::PartialDrainPending
    2148           0 :           && decoder.mNumSamplesInput == decoder.mNumSamplesOutput)) {
    2149             :     // No frames to drain.
    2150           0 :     LOGV("Draining %s with nothing to drain", TrackTypeToStr(aTrack));
    2151           0 :     decoder.mDrainState = DrainState::DrainAborted;
    2152           0 :     ScheduleUpdate(aTrack);
    2153           0 :     return;
    2154             :   }
    2155             : 
    2156           0 :   decoder.mDrainState = DrainState::Draining;
    2157             : 
    2158           0 :   RefPtr<MediaFormatReader> self = this;
    2159           0 :   decoder.mDecoder->Drain()
    2160           0 :     ->Then(mTaskQueue, __func__,
    2161           0 :            [self, this, aTrack, &decoder]
    2162           0 :            (const MediaDataDecoder::DecodedData& aResults) {
    2163           0 :              decoder.mDrainRequest.Complete();
    2164           0 :              if (aResults.IsEmpty()) {
    2165           0 :                decoder.mDrainState = DrainState::DrainCompleted;
    2166             :              } else {
    2167           0 :                NotifyNewOutput(aTrack, aResults);
    2168             :                // Let's see if we have any more data available to drain.
    2169           0 :                decoder.mDrainState = DrainState::PartialDrainPending;
    2170             :              }
    2171           0 :              ScheduleUpdate(aTrack);
    2172           0 :            },
    2173           0 :            [self, this, aTrack, &decoder](const MediaResult& aError) {
    2174           0 :              decoder.mDrainRequest.Complete();
    2175           0 :              NotifyError(aTrack, aError);
    2176           0 :            })
    2177           0 :     ->Track(decoder.mDrainRequest);
    2178           0 :   LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
    2179             : }
    2180             : 
    2181             : void
    2182           0 : MediaFormatReader::Update(TrackType aTrack)
    2183             : {
    2184           0 :   MOZ_ASSERT(OnTaskQueue());
    2185             : 
    2186           0 :   if (mShutdown) {
    2187           0 :     return;
    2188             :   }
    2189             : 
    2190           0 :   LOGV("Processing update for %s", TrackTypeToStr(aTrack));
    2191             : 
    2192           0 :   bool needOutput = false;
    2193           0 :   auto& decoder = GetDecoderData(aTrack);
    2194           0 :   decoder.mUpdateScheduled = false;
    2195             : 
    2196           0 :   if (!mInitDone) {
    2197           0 :     return;
    2198             :   }
    2199             : 
    2200           0 :   if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
    2201           0 :     LOGV("Skipping in progress, nothing more to do");
    2202           0 :     return;
    2203             :   }
    2204             : 
    2205           0 :   if (UpdateReceivedNewData(aTrack)) {
    2206           0 :     LOGV("Nothing more to do");
    2207           0 :     return;
    2208             :   }
    2209             : 
    2210           0 :   if (decoder.mSeekRequest.Exists()) {
    2211           0 :     LOGV("Seeking hasn't completed, nothing more to do");
    2212           0 :     return;
    2213             :   }
    2214             : 
    2215           0 :   MOZ_DIAGNOSTIC_ASSERT(
    2216             :     !decoder.HasInternalSeekPending()
    2217             :     || (!decoder.mOutput.Length() && !decoder.mQueuedSamples.Length()),
    2218             :     "No frames can be demuxed or decoded while an internal seek is pending");
    2219             : 
    2220             :   // Record number of frames decoded and parsed. Automatically update the
    2221             :   // stats counters using the AutoNotifyDecoded stack-based class.
    2222           0 :   AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
    2223             : 
    2224             :   // Drop any frames found prior our internal seek target.
    2225           0 :   while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
    2226           0 :     RefPtr<MediaData>& output = decoder.mOutput[0];
    2227           0 :     InternalSeekTarget target = decoder.mTimeThreshold.ref();
    2228           0 :     auto time = output->mTime;
    2229           0 :     if (time >= target.Time()) {
    2230             :       // We have reached our internal seek target.
    2231           0 :       decoder.mTimeThreshold.reset();
    2232             :       // We might have dropped some keyframes.
    2233           0 :       mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
    2234             :     }
    2235           0 :     if (time < target.Time() || (target.mDropTarget && target.Contains(time))) {
    2236           0 :       LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
    2237             :            TrackTypeToStr(aTrack),
    2238             :            output->mTime.ToSeconds(),
    2239             :            target.Time().ToSeconds(),
    2240             :            output->mKeyframe);
    2241           0 :       decoder.mOutput.RemoveElementAt(0);
    2242           0 :       decoder.mSizeOfQueue -= 1;
    2243             :     }
    2244             :   }
    2245             : 
    2246           0 :   while (decoder.mOutput.Length()
    2247           0 :          && decoder.mOutput[0]->mType == MediaData::NULL_DATA) {
    2248           0 :     LOGV("Dropping null data. Time: %" PRId64,
    2249             :          decoder.mOutput[0]->mTime.ToMicroseconds());
    2250           0 :     decoder.mOutput.RemoveElementAt(0);
    2251           0 :     decoder.mSizeOfQueue -= 1;
    2252             :   }
    2253             : 
    2254           0 :   if (decoder.HasPromise()) {
    2255           0 :     needOutput = true;
    2256           0 :     if (decoder.mOutput.Length()) {
    2257           0 :       RefPtr<MediaData> output = decoder.mOutput[0];
    2258           0 :       decoder.mOutput.RemoveElementAt(0);
    2259           0 :       decoder.mSizeOfQueue -= 1;
    2260             :       decoder.mLastDecodedSampleTime =
    2261           0 :         Some(TimeInterval(output->mTime, output->GetEndTime()));
    2262           0 :       decoder.mNumSamplesOutputTotal++;
    2263           0 :       ReturnOutput(output, aTrack);
    2264             :       // We have a decoded sample ready to be returned.
    2265           0 :       if (aTrack == TrackType::kVideoTrack) {
    2266             :         uint64_t delta =
    2267           0 :           decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
    2268           0 :         a.mStats.mDecodedFrames = static_cast<uint32_t>(delta);
    2269           0 :         mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
    2270           0 :         if (output->mKeyframe) {
    2271           0 :           if (mPreviousDecodedKeyframeTime_us < output->mTime.ToMicroseconds()) {
    2272             :             // There is a previous keyframe -> Record inter-keyframe stats.
    2273             :             uint64_t segment_us =
    2274           0 :               output->mTime.ToMicroseconds() - mPreviousDecodedKeyframeTime_us;
    2275           0 :             a.mStats.mInterKeyframeSum_us += segment_us;
    2276           0 :             a.mStats.mInterKeyframeCount += 1;
    2277           0 :             if (a.mStats.mInterKeyFrameMax_us < segment_us) {
    2278           0 :               a.mStats.mInterKeyFrameMax_us = segment_us;
    2279             :             }
    2280             :           }
    2281           0 :           mPreviousDecodedKeyframeTime_us = output->mTime.ToMicroseconds();
    2282             :         }
    2283           0 :         nsCString error;
    2284           0 :         mVideo.mIsHardwareAccelerated =
    2285           0 :           mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
    2286             : #ifdef XP_WIN
    2287             :         // D3D11_YCBCR_IMAGE images are GPU based, we try to limit the amount
    2288             :         // of GPU RAM used.
    2289             :         VideoData* videoData = static_cast<VideoData*>(output.get());
    2290             :         mVideo.mIsHardwareAccelerated =
    2291             :           mVideo.mIsHardwareAccelerated ||
    2292             :           (videoData->mImage &&
    2293             :            videoData->mImage->GetFormat() == ImageFormat::D3D11_YCBCR_IMAGE);
    2294             : #endif
    2295             :       }
    2296           0 :     } else if (decoder.HasFatalError()) {
    2297           0 :       LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
    2298           0 :       decoder.RejectPromise(decoder.mError.ref(), __func__);
    2299           0 :       return;
    2300           0 :     } else if (decoder.HasCompletedDrain()) {
    2301           0 :       if (decoder.mDemuxEOS) {
    2302           0 :         LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
    2303           0 :         decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
    2304           0 :       } else if (decoder.mWaitingForData) {
    2305           0 :         if (decoder.mDrainState == DrainState::DrainCompleted
    2306           0 :             && decoder.mLastDecodedSampleTime
    2307           0 :             && !decoder.mNextStreamSourceID) {
    2308             :           // We have completed draining the decoder following WaitingForData.
    2309             :           // Set up the internal seek machinery to be able to resume from the
    2310             :           // last sample decoded.
    2311           0 :           LOG("Seeking to last sample time: %" PRId64,
    2312             :               decoder.mLastDecodedSampleTime.ref().mStart.ToMicroseconds());
    2313             :           InternalSeek(aTrack,
    2314           0 :                        InternalSeekTarget(decoder.mLastDecodedSampleTime.ref(), true));
    2315             :         }
    2316           0 :         if (!decoder.mReceivedNewData) {
    2317           0 :           LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
    2318           0 :           decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
    2319             :         }
    2320             :       }
    2321             : 
    2322           0 :       decoder.mDrainState = DrainState::None;
    2323             : 
    2324             :       // Now that draining has completed, we check if we have received
    2325             :       // new data again as the result may now be different from the earlier
    2326             :       // run.
    2327           0 :       if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) {
    2328           0 :         LOGV("Nothing more to do");
    2329           0 :         return;
    2330             :       }
    2331           0 :     } else if (decoder.mDemuxEOS
    2332           0 :                && !decoder.HasPendingDrain()
    2333           0 :                && decoder.mQueuedSamples.IsEmpty()) {
    2334             :       // It is possible to transition from WAITING_FOR_DATA directly to EOS
    2335             :       // state during the internal seek; in which case no draining would occur.
    2336             :       // There is no more samples left to be decoded and we are already in
    2337             :       // EOS state. We can immediately reject the data promise.
    2338           0 :       LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
    2339           0 :       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
    2340           0 :     } else if (decoder.mWaitingForKey) {
    2341           0 :       LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
    2342             :           TrackTypeToStr(aTrack));
    2343           0 :       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
    2344             :     }
    2345             :   }
    2346             : 
    2347           0 :   if (decoder.mDrainState == DrainState::DrainRequested
    2348           0 :       || decoder.mDrainState == DrainState::PartialDrainPending) {
    2349           0 :     if (decoder.mOutput.IsEmpty()) {
    2350           0 :       DrainDecoder(aTrack);
    2351             :     }
    2352           0 :     return;
    2353             :   }
    2354             : 
    2355           0 :   if (decoder.mError && !decoder.HasFatalError()) {
    2356           0 :     MOZ_RELEASE_ASSERT(!decoder.HasInternalSeekPending(),
    2357             :                        "No error can occur while an internal seek is pending");
    2358             :     bool needsNewDecoder =
    2359           0 :       decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
    2360           0 :     if (!needsNewDecoder
    2361           0 :         && ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
    2362           0 :       NotifyError(aTrack, decoder.mError.ref());
    2363           0 :       return;
    2364             :     }
    2365           0 :     decoder.mError.reset();
    2366             : 
    2367           0 :     LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
    2368             :         decoder.mNumOfConsecutiveError);
    2369             : 
    2370           0 :     if (needsNewDecoder) {
    2371           0 :       LOG("Error: Need new decoder");
    2372           0 :       ShutdownDecoder(aTrack);
    2373             :     }
    2374           0 :     if (decoder.mFirstFrameTime) {
    2375             :       TimeInterval seekInterval = TimeInterval(decoder.mFirstFrameTime.ref(),
    2376           0 :                                                 decoder.mFirstFrameTime.ref());
    2377           0 :       InternalSeek(aTrack, InternalSeekTarget(seekInterval, false));
    2378           0 :       return;
    2379             :     }
    2380             : 
    2381           0 :     TimeUnit nextKeyframe;
    2382           0 :     if (aTrack == TrackType::kVideoTrack &&
    2383           0 :         NS_SUCCEEDED(
    2384           0 :           decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe)) &&
    2385           0 :         !nextKeyframe.IsInfinite()) {
    2386           0 :       SkipVideoDemuxToNextKeyFrame(
    2387           0 :         decoder.mLastDecodedSampleTime.refOr(TimeInterval()).Length());
    2388           0 :     } else if (aTrack == TrackType::kAudioTrack) {
    2389           0 :       decoder.Flush();
    2390             :     } else {
    2391             :       // We can't recover from this error.
    2392           0 :       NotifyError(aTrack, NS_ERROR_DOM_MEDIA_FATAL_ERR);
    2393             :     }
    2394           0 :     return;
    2395             :   }
    2396             : 
    2397           0 :   bool needInput = NeedInput(decoder);
    2398             : 
    2399           0 :   LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
    2400             :        " qs=%u decoding:%d flushing:%d desc:%s pending:%u waiting:%d eos:%d "
    2401             :        "ds:%d sid:%u",
    2402             :        TrackTypeToStr(aTrack),
    2403             :        needInput,
    2404             :        needOutput,
    2405             :        decoder.mNumSamplesInput,
    2406             :        decoder.mNumSamplesOutput,
    2407             :        uint32_t(size_t(decoder.mSizeOfQueue)),
    2408             :        decoder.mDecodeRequest.Exists(),
    2409             :        decoder.mFlushing,
    2410             :        decoder.mDescription,
    2411             :        uint32_t(decoder.mOutput.Length()),
    2412             :        decoder.mWaitingForData,
    2413             :        decoder.mDemuxEOS,
    2414             :        int32_t(decoder.mDrainState),
    2415             :        decoder.mLastStreamSourceID);
    2416             : 
    2417           0 :   if ((decoder.mWaitingForData
    2418           0 :        && (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
    2419           0 :       || (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
    2420             :     // Nothing more we can do at present.
    2421           0 :     LOGV("Still waiting for data or key.");
    2422           0 :     return;
    2423             :   }
    2424             : 
    2425           0 :   if (decoder.CancelWaitingForKey()) {
    2426           0 :     LOGV("No longer waiting for key. Resolving waiting promise");
    2427           0 :     return;
    2428             :   }
    2429             : 
    2430           0 :   if (!needInput) {
    2431           0 :     LOGV("No need for additional input (pending:%u)",
    2432             :          uint32_t(decoder.mOutput.Length()));
    2433           0 :     return;
    2434             :   }
    2435             : 
    2436             :   // Demux samples if we don't have some.
    2437           0 :   RequestDemuxSamples(aTrack);
    2438             : 
    2439           0 :   HandleDemuxedSamples(aTrack, a);
    2440             : }
    2441             : 
    2442             : void
    2443           0 : MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
    2444             : {
    2445           0 :   MOZ_ASSERT(GetDecoderData(aTrack).HasPromise());
    2446           0 :   MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::NULL_DATA);
    2447           0 :   LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]", TrackTypeToStr(aTrack),
    2448             :       aData->mTime.ToMicroseconds(), aData->GetEndTime().ToMicroseconds());
    2449             : 
    2450           0 :   if (aTrack == TrackInfo::kAudioTrack) {
    2451           0 :     AudioData* audioData = static_cast<AudioData*>(aData);
    2452             : 
    2453           0 :     if (audioData->mChannels != mInfo.mAudio.mChannels
    2454           0 :         || audioData->mRate != mInfo.mAudio.mRate) {
    2455           0 :       LOG("change of audio format (rate:%d->%d). "
    2456             :           "This is an unsupported configuration",
    2457             :           mInfo.mAudio.mRate, audioData->mRate);
    2458           0 :       mInfo.mAudio.mRate = audioData->mRate;
    2459           0 :       mInfo.mAudio.mChannels = audioData->mChannels;
    2460             :     }
    2461           0 :     mAudio.ResolvePromise(audioData, __func__);
    2462           0 :   } else if (aTrack == TrackInfo::kVideoTrack) {
    2463           0 :     VideoData* videoData = static_cast<VideoData*>(aData);
    2464             : 
    2465           0 :     if (videoData->mDisplay != mInfo.mVideo.mDisplay) {
    2466           0 :       LOG("change of video display size (%dx%d->%dx%d)",
    2467             :           mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height,
    2468             :           videoData->mDisplay.width, videoData->mDisplay.height);
    2469           0 :       mInfo.mVideo.mDisplay = videoData->mDisplay;
    2470             :     }
    2471           0 :     mVideo.ResolvePromise(videoData, __func__);
    2472             :   }
    2473           0 : }
    2474             : 
    2475             : size_t
    2476           0 : MediaFormatReader::SizeOfVideoQueueInFrames()
    2477             : {
    2478           0 :   return SizeOfQueue(TrackInfo::kVideoTrack);
    2479             : }
    2480             : 
    2481             : size_t
    2482           0 : MediaFormatReader::SizeOfAudioQueueInFrames()
    2483             : {
    2484           0 :   return SizeOfQueue(TrackInfo::kAudioTrack);
    2485             : }
    2486             : 
    2487             : size_t
    2488           0 : MediaFormatReader::SizeOfQueue(TrackType aTrack)
    2489             : {
    2490           0 :   auto& decoder = GetDecoderData(aTrack);
    2491           0 :   return decoder.mSizeOfQueue;
    2492             : }
    2493             : 
    2494             : RefPtr<MediaDecoderReader::WaitForDataPromise>
    2495           0 : MediaFormatReader::WaitForData(MediaData::Type aType)
    2496             : {
    2497           0 :   MOZ_ASSERT(OnTaskQueue());
    2498           0 :   TrackType trackType = aType == MediaData::VIDEO_DATA ?
    2499           0 :     TrackType::kVideoTrack : TrackType::kAudioTrack;
    2500           0 :   auto& decoder = GetDecoderData(trackType);
    2501           0 :   if (!decoder.IsWaiting()) {
    2502             :     // We aren't waiting for anything.
    2503           0 :     return WaitForDataPromise::CreateAndResolve(decoder.mType, __func__);
    2504             :   }
    2505           0 :   RefPtr<WaitForDataPromise> p = decoder.mWaitingPromise.Ensure(__func__);
    2506           0 :   ScheduleUpdate(trackType);
    2507           0 :   return p;
    2508             : }
    2509             : 
    2510             : nsresult
    2511           0 : MediaFormatReader::ResetDecode(TrackSet aTracks)
    2512             : {
    2513           0 :   MOZ_ASSERT(OnTaskQueue());
    2514           0 :   LOGV("");
    2515             : 
    2516           0 :   mSeekPromise.RejectIfExists(NS_OK, __func__);
    2517           0 :   mSkipRequest.DisconnectIfExists();
    2518             : 
    2519             :   // Do the same for any data wait promises.
    2520           0 :   if (aTracks.contains(TrackInfo::kAudioTrack)) {
    2521           0 :     mAudio.mWaitingPromise.RejectIfExists(
    2522           0 :         WaitForDataRejectValue(MediaData::AUDIO_DATA,
    2523           0 :                                WaitForDataRejectValue::CANCELED), __func__);
    2524             :   }
    2525             : 
    2526           0 :   if (aTracks.contains(TrackInfo::kVideoTrack)) {
    2527           0 :     mVideo.mWaitingPromise.RejectIfExists(
    2528           0 :         WaitForDataRejectValue(MediaData::VIDEO_DATA,
    2529           0 :                                WaitForDataRejectValue::CANCELED), __func__);
    2530             :   }
    2531             : 
    2532             :   // Reset miscellaneous seeking state.
    2533           0 :   mPendingSeekTime.reset();
    2534             : 
    2535           0 :   if (HasVideo() && aTracks.contains(TrackInfo::kVideoTrack)) {
    2536           0 :     mVideo.ResetDemuxer();
    2537           0 :     mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
    2538           0 :     Reset(TrackInfo::kVideoTrack);
    2539           0 :     if (mVideo.HasPromise()) {
    2540           0 :       mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    2541             :     }
    2542             :   }
    2543             : 
    2544           0 :   if (HasAudio() && aTracks.contains(TrackInfo::kAudioTrack)) {
    2545           0 :     mAudio.ResetDemuxer();
    2546           0 :     mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
    2547           0 :     Reset(TrackInfo::kAudioTrack);
    2548           0 :     if (mAudio.HasPromise()) {
    2549           0 :       mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    2550             :     }
    2551             :   }
    2552             : 
    2553           0 :   return MediaDecoderReader::ResetDecode(aTracks);
    2554             : }
    2555             : 
    2556             : void
    2557           0 : MediaFormatReader::Reset(TrackType aTrack)
    2558             : {
    2559           0 :   MOZ_ASSERT(OnTaskQueue());
    2560           0 :   LOG("Reset(%s) BEGIN", TrackTypeToStr(aTrack));
    2561             : 
    2562           0 :   auto& decoder = GetDecoderData(aTrack);
    2563             : 
    2564           0 :   decoder.ResetState();
    2565           0 :   decoder.Flush();
    2566             : 
    2567           0 :   LOG("Reset(%s) END", TrackTypeToStr(aTrack));
    2568           0 : }
    2569             : 
    2570             : void
    2571           0 : MediaFormatReader::DropDecodedSamples(TrackType aTrack)
    2572             : {
    2573           0 :   MOZ_ASSERT(OnTaskQueue());
    2574           0 :   auto& decoder = GetDecoderData(aTrack);
    2575           0 :   size_t lengthDecodedQueue = decoder.mOutput.Length();
    2576           0 :   if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) {
    2577           0 :     auto time = decoder.mOutput.LastElement()->mTime;
    2578           0 :     if (time >= decoder.mTimeThreshold.ref().Time()) {
    2579             :       // We would have reached our internal seek target.
    2580           0 :       decoder.mTimeThreshold.reset();
    2581             :     }
    2582             :   }
    2583           0 :   decoder.mOutput.Clear();
    2584           0 :   decoder.mSizeOfQueue -= lengthDecodedQueue;
    2585           0 :   if (aTrack == TrackInfo::kVideoTrack && mDecoder) {
    2586           0 :     mDecoder->NotifyDecodedFrames({ 0, 0, lengthDecodedQueue });
    2587             :   }
    2588           0 : }
    2589             : 
    2590             : void
    2591           0 : MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold)
    2592             : {
    2593           0 :   MOZ_ASSERT(OnTaskQueue());
    2594           0 :   LOG("Skipping up to %" PRId64, aTimeThreshold.ToMicroseconds());
    2595             : 
    2596             :   // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late.
    2597             :   // As such we can drop all already decoded samples and discard all pending
    2598             :   // samples.
    2599           0 :   DropDecodedSamples(TrackInfo::kVideoTrack);
    2600             : 
    2601           0 :   mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
    2602           0 :     ->Then(OwnerThread(), __func__, this,
    2603             :            &MediaFormatReader::OnVideoSkipCompleted,
    2604             :            &MediaFormatReader::OnVideoSkipFailed)
    2605           0 :     ->Track(mSkipRequest);
    2606           0 :   return;
    2607             : }
    2608             : 
    2609             : void
    2610           0 : MediaFormatReader::VideoSkipReset(uint32_t aSkipped)
    2611             : {
    2612           0 :   MOZ_ASSERT(OnTaskQueue());
    2613             : 
    2614             :   // Some frames may have been output by the decoder since we initiated the
    2615             :   // videoskip process and we know they would be late.
    2616           0 :   DropDecodedSamples(TrackInfo::kVideoTrack);
    2617             :   // Report the pending frames as dropped.
    2618           0 :   if (mDecoder) {
    2619           0 :     mDecoder->NotifyDecodedFrames({ 0, 0, SizeOfVideoQueueInFrames() });
    2620             :   }
    2621             : 
    2622             :   // Cancel any pending demux request and pending demuxed samples.
    2623           0 :   mVideo.mDemuxRequest.DisconnectIfExists();
    2624           0 :   Reset(TrackType::kVideoTrack);
    2625             : 
    2626           0 :   if (mDecoder) {
    2627           0 :     mDecoder->NotifyDecodedFrames({ aSkipped, 0, aSkipped });
    2628             :   }
    2629             : 
    2630           0 :   mVideo.mNumSamplesSkippedTotal += aSkipped;
    2631           0 : }
    2632             : 
    2633             : void
    2634           0 : MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped)
    2635             : {
    2636           0 :   MOZ_ASSERT(OnTaskQueue());
    2637           0 :   LOG("Skipping succeeded, skipped %u frames", aSkipped);
    2638           0 :   mSkipRequest.Complete();
    2639             : 
    2640           0 :   VideoSkipReset(aSkipped);
    2641             : 
    2642           0 :   ScheduleUpdate(TrackInfo::kVideoTrack);
    2643           0 : }
    2644             : 
    2645             : void
    2646           0 : MediaFormatReader::OnVideoSkipFailed(
    2647             :   MediaTrackDemuxer::SkipFailureHolder aFailure)
    2648             : {
    2649           0 :   MOZ_ASSERT(OnTaskQueue());
    2650           0 :   LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
    2651           0 :   mSkipRequest.Complete();
    2652             : 
    2653           0 :   switch (aFailure.mFailure.Code()) {
    2654             :     case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
    2655             :     case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
    2656             :       // Some frames may have been output by the decoder since we initiated the
    2657             :       // videoskip process and we know they would be late.
    2658           0 :       DropDecodedSamples(TrackInfo::kVideoTrack);
    2659             :       // We can't complete the skip operation, will just service a video frame
    2660             :       // normally.
    2661           0 :       ScheduleUpdate(TrackInfo::kVideoTrack);
    2662           0 :       break;
    2663             :     case NS_ERROR_DOM_MEDIA_CANCELED:
    2664           0 :       if (mVideo.HasPromise()) {
    2665           0 :         mVideo.RejectPromise(aFailure.mFailure, __func__);
    2666             :       }
    2667           0 :       break;
    2668             :     default:
    2669           0 :       NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
    2670           0 :       break;
    2671             :   }
    2672           0 : }
    2673             : 
    2674             : RefPtr<MediaDecoderReader::SeekPromise>
    2675           0 : MediaFormatReader::Seek(const SeekTarget& aTarget)
    2676             : {
    2677           0 :   MOZ_ASSERT(OnTaskQueue());
    2678             : 
    2679           0 :   LOG("aTarget=(%" PRId64 ")", aTarget.GetTime().ToMicroseconds());
    2680             : 
    2681           0 :   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
    2682           0 :   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
    2683           0 :   MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() || !mAudio.HasPromise());
    2684           0 :   MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing());
    2685           0 :   MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
    2686           0 :   MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly()
    2687             :                         || mAudio.mTimeThreshold.isNothing());
    2688             : 
    2689           0 :   if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
    2690           0 :     LOG("Seek() END (Unseekable)");
    2691           0 :     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
    2692             :   }
    2693             : 
    2694           0 :   if (mShutdown) {
    2695           0 :     return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
    2696             :   }
    2697             : 
    2698           0 :   SetSeekTarget(aTarget);
    2699             : 
    2700           0 :   RefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
    2701             : 
    2702           0 :   ScheduleSeek();
    2703             : 
    2704           0 :   return p;
    2705             : }
    2706             : 
    2707             : void
    2708           0 : MediaFormatReader::SetSeekTarget(const SeekTarget& aTarget)
    2709             : {
    2710           0 :   MOZ_ASSERT(OnTaskQueue());
    2711             : 
    2712           0 :   mOriginalSeekTarget = aTarget;
    2713           0 :   mFallbackSeekTime = mPendingSeekTime = Some(aTarget.GetTime());
    2714           0 : }
    2715             : 
    2716             : void
    2717           0 : MediaFormatReader::ScheduleSeek()
    2718             : {
    2719           0 :   if (mSeekScheduled) {
    2720           0 :     return;
    2721             :   }
    2722           0 :   mSeekScheduled = true;
    2723           0 :   OwnerThread()->Dispatch(NewRunnableMethod(
    2724           0 :     "MediaFormatReader::AttemptSeek", this, &MediaFormatReader::AttemptSeek));
    2725             : }
    2726             : 
    2727             : void
    2728           0 : MediaFormatReader::AttemptSeek()
    2729             : {
    2730           0 :   MOZ_ASSERT(OnTaskQueue());
    2731             : 
    2732           0 :   mSeekScheduled = false;
    2733             : 
    2734           0 :   if (mPendingSeekTime.isNothing()) {
    2735           0 :     return;
    2736             :   }
    2737             : 
    2738           0 :   if (HasVideo()) {
    2739           0 :     mVideo.ResetDemuxer();
    2740           0 :     mVideo.ResetState();
    2741             :   }
    2742             : 
    2743             :   // Don't reset the audio demuxer not state when seeking video only
    2744             :   // as it will cause the audio to seek back to the beginning
    2745             :   // resulting in out-of-sync audio from video.
    2746           0 :   if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
    2747           0 :     mAudio.ResetDemuxer();
    2748           0 :     mAudio.ResetState();
    2749             :   }
    2750             : 
    2751           0 :   if (HasVideo()) {
    2752           0 :     DoVideoSeek();
    2753           0 :   } else if (HasAudio()) {
    2754           0 :     DoAudioSeek();
    2755             :   } else {
    2756           0 :     MOZ_CRASH();
    2757             :   }
    2758             : }
    2759             : 
    2760             : void
    2761           0 : MediaFormatReader::OnSeekFailed(TrackType aTrack, const MediaResult& aError)
    2762             : {
    2763           0 :   MOZ_ASSERT(OnTaskQueue());
    2764           0 :   LOGV("%s failure:%" PRIu32, TrackTypeToStr(aTrack), static_cast<uint32_t>(aError.Code()));
    2765           0 :   if (aTrack == TrackType::kVideoTrack) {
    2766           0 :     mVideo.mSeekRequest.Complete();
    2767             :   } else {
    2768           0 :     mAudio.mSeekRequest.Complete();
    2769             :   }
    2770             : 
    2771           0 :   if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
    2772           0 :     if (HasVideo()
    2773           0 :         && aTrack == TrackType::kAudioTrack
    2774           0 :         && mFallbackSeekTime.isSome()
    2775           0 :         && mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
    2776             :       // We have failed to seek audio where video seeked to earlier.
    2777             :       // Attempt to seek instead to the closest point that we know we have in
    2778             :       // order to limit A/V sync discrepency.
    2779             : 
    2780             :       // Ensure we have the most up to date buffered ranges.
    2781           0 :       UpdateReceivedNewData(TrackType::kAudioTrack);
    2782           0 :       Maybe<TimeUnit> nextSeekTime;
    2783             :       // Find closest buffered time found after video seeked time.
    2784           0 :       for (const auto& timeRange : mAudio.mTimeRanges) {
    2785           0 :         if (timeRange.mStart >= mPendingSeekTime.ref()) {
    2786           0 :           nextSeekTime.emplace(timeRange.mStart);
    2787           0 :           break;
    2788             :         }
    2789             :       }
    2790           0 :       if (nextSeekTime.isNothing()
    2791           0 :           || nextSeekTime.ref() > mFallbackSeekTime.ref()) {
    2792           0 :         nextSeekTime = Some(mFallbackSeekTime.ref());
    2793           0 :         LOG("Unable to seek audio to video seek time. A/V sync may be broken");
    2794             :       } else {
    2795           0 :         mFallbackSeekTime.reset();
    2796             :       }
    2797           0 :       mPendingSeekTime = nextSeekTime;
    2798           0 :       DoAudioSeek();
    2799           0 :       return;
    2800             :     }
    2801           0 :     NotifyWaitingForData(aTrack);
    2802             :   }
    2803           0 :   MOZ_ASSERT(!mVideo.mSeekRequest.Exists() && !mAudio.mSeekRequest.Exists());
    2804           0 :   mPendingSeekTime.reset();
    2805             : 
    2806           0 :   auto type = aTrack == TrackType::kAudioTrack ? MediaData::AUDIO_DATA
    2807           0 :                                                : MediaData::VIDEO_DATA;
    2808           0 :   mSeekPromise.Reject(SeekRejectValue(type, aError), __func__);
    2809             : }
    2810             : 
    2811             : void
    2812           0 : MediaFormatReader::DoVideoSeek()
    2813             : {
    2814           0 :   MOZ_ASSERT(mPendingSeekTime.isSome());
    2815           0 :   LOGV("Seeking video to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
    2816           0 :   auto seekTime = mPendingSeekTime.ref();
    2817           0 :   mVideo.mTrackDemuxer->Seek(seekTime)
    2818           0 :     ->Then(OwnerThread(), __func__, this,
    2819             :            &MediaFormatReader::OnVideoSeekCompleted,
    2820             :            &MediaFormatReader::OnVideoSeekFailed)
    2821           0 :     ->Track(mVideo.mSeekRequest);
    2822           0 : }
    2823             : 
    2824             : void
    2825           0 : MediaFormatReader::OnVideoSeekCompleted(TimeUnit aTime)
    2826             : {
    2827           0 :   MOZ_ASSERT(OnTaskQueue());
    2828           0 :   LOGV("Video seeked to %" PRId64, aTime.ToMicroseconds());
    2829           0 :   mVideo.mSeekRequest.Complete();
    2830             : 
    2831           0 :   mVideo.mFirstFrameTime = Some(aTime);
    2832           0 :   mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
    2833             : 
    2834           0 :   SetVideoDecodeThreshold();
    2835             : 
    2836           0 :   if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
    2837           0 :     MOZ_ASSERT(mPendingSeekTime.isSome());
    2838           0 :     if (mOriginalSeekTarget.IsFast()) {
    2839             :       // We are performing a fast seek. We need to seek audio to where the
    2840             :       // video seeked to, to ensure proper A/V sync once playback resume.
    2841           0 :       mPendingSeekTime = Some(aTime);
    2842             :     }
    2843           0 :     DoAudioSeek();
    2844             :   } else {
    2845           0 :     mPendingSeekTime.reset();
    2846           0 :     mSeekPromise.Resolve(aTime, __func__);
    2847             :   }
    2848           0 : }
    2849             : 
    2850             : void
    2851           0 : MediaFormatReader::OnVideoSeekFailed(const MediaResult& aError)
    2852             : {
    2853           0 :   mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
    2854           0 :   OnSeekFailed(TrackType::kVideoTrack, aError);
    2855           0 : }
    2856             : 
    2857             : void
    2858           0 : MediaFormatReader::SetVideoDecodeThreshold()
    2859             : {
    2860           0 :   MOZ_ASSERT(OnTaskQueue());
    2861             : 
    2862           0 :   if (!HasVideo() || !mVideo.mDecoder) {
    2863           0 :     return;
    2864             :   }
    2865             : 
    2866           0 :   if (!mVideo.mTimeThreshold && !IsSeeking()) {
    2867           0 :     return;
    2868             :   }
    2869             : 
    2870           0 :   TimeUnit threshold;
    2871           0 :   if (mVideo.mTimeThreshold) {
    2872             :     // For internalSeek.
    2873           0 :     threshold = mVideo.mTimeThreshold.ref().Time();
    2874           0 :   } else if (IsSeeking()) {
    2875             :     // If IsSeeking() is true, then video seek must have completed already.
    2876           0 :     TimeUnit keyframe;
    2877           0 :     if (NS_FAILED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&keyframe))) {
    2878           0 :       return;
    2879             :     }
    2880             : 
    2881             :     // If the key frame is invalid/infinite, it means the target position is
    2882             :     // closing to end of stream. We don't want to skip any frame at this point.
    2883           0 :     if (!keyframe.IsValid() || keyframe.IsInfinite()) {
    2884           0 :       return;
    2885             :     }
    2886           0 :     threshold = mOriginalSeekTarget.GetTime();
    2887             :   } else {
    2888           0 :     return;
    2889             :   }
    2890             : 
    2891           0 :   LOG("Set seek threshold to %" PRId64, threshold.ToMicroseconds());
    2892           0 :   mVideo.mDecoder->SetSeekThreshold(threshold);
    2893             : }
    2894             : 
    2895             : void
    2896           0 : MediaFormatReader::DoAudioSeek()
    2897             : {
    2898           0 :   MOZ_ASSERT(mPendingSeekTime.isSome());
    2899           0 :   LOGV("Seeking audio to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
    2900           0 :   auto seekTime = mPendingSeekTime.ref();
    2901           0 :   mAudio.mTrackDemuxer->Seek(seekTime)
    2902           0 :     ->Then(OwnerThread(), __func__, this,
    2903             :            &MediaFormatReader::OnAudioSeekCompleted,
    2904             :            &MediaFormatReader::OnAudioSeekFailed)
    2905           0 :     ->Track(mAudio.mSeekRequest);
    2906           0 : }
    2907             : 
    2908             : void
    2909           0 : MediaFormatReader::OnAudioSeekCompleted(TimeUnit aTime)
    2910             : {
    2911           0 :   MOZ_ASSERT(OnTaskQueue());
    2912           0 :   LOGV("Audio seeked to %" PRId64, aTime.ToMicroseconds());
    2913           0 :   mAudio.mSeekRequest.Complete();
    2914           0 :   mAudio.mFirstFrameTime = Some(aTime);
    2915           0 :   mPendingSeekTime.reset();
    2916           0 :   mSeekPromise.Resolve(aTime, __func__);
    2917           0 : }
    2918             : 
    2919             : void
    2920           0 : MediaFormatReader::OnAudioSeekFailed(const MediaResult& aError)
    2921             : {
    2922           0 :   OnSeekFailed(TrackType::kAudioTrack, aError);
    2923           0 : }
    2924             : 
    2925           0 : void MediaFormatReader::ReleaseResources()
    2926             : {
    2927           0 :   LOGV("");
    2928           0 :   if (mShutdown) {
    2929           0 :     return;
    2930             :   }
    2931           0 :   ShutdownDecoder(TrackInfo::kAudioTrack);
    2932           0 :   ShutdownDecoder(TrackInfo::kVideoTrack);
    2933             : }
    2934             : 
    2935             : bool
    2936           0 : MediaFormatReader::VideoIsHardwareAccelerated() const
    2937             : {
    2938           0 :   return mVideo.mIsHardwareAccelerated;
    2939             : }
    2940             : 
    2941             : void
    2942           0 : MediaFormatReader::NotifyTrackDemuxers()
    2943             : {
    2944           0 :   MOZ_ASSERT(OnTaskQueue());
    2945             : 
    2946           0 :   LOGV("");
    2947             : 
    2948           0 :   if (!mInitDone) {
    2949           0 :     return;
    2950             :   }
    2951             : 
    2952           0 :   if (HasVideo()) {
    2953           0 :     mVideo.mReceivedNewData = true;
    2954           0 :     ScheduleUpdate(TrackType::kVideoTrack);
    2955             :   }
    2956           0 :   if (HasAudio()) {
    2957           0 :     mAudio.mReceivedNewData = true;
    2958           0 :     ScheduleUpdate(TrackType::kAudioTrack);
    2959             :   }
    2960             : }
    2961             : 
    2962             : void
    2963           0 : MediaFormatReader::NotifyDataArrived()
    2964             : {
    2965           0 :   MOZ_ASSERT(OnTaskQueue());
    2966             : 
    2967           0 :   if (mShutdown || !mDemuxer || !mDemuxerInitDone) {
    2968           0 :     return;
    2969             :   }
    2970             : 
    2971           0 :   if (mNotifyDataArrivedPromise.Exists()) {
    2972             :     // Already one in progress. Set the dirty flag so we can process it later.
    2973           0 :     mPendingNotifyDataArrived = true;
    2974           0 :     return;
    2975             :   }
    2976             : 
    2977           0 :   RefPtr<MediaFormatReader> self = this;
    2978           0 :   mDemuxer->NotifyDataArrived()
    2979           0 :     ->Then(OwnerThread(), __func__,
    2980           0 :            [self]() {
    2981           0 :              self->mNotifyDataArrivedPromise.Complete();
    2982           0 :              self->UpdateBuffered();
    2983           0 :              self->NotifyTrackDemuxers();
    2984           0 :              if (self->mPendingNotifyDataArrived) {
    2985           0 :                self->mPendingNotifyDataArrived = false;
    2986           0 :                self->NotifyDataArrived();
    2987             :              }
    2988           0 :            },
    2989           0 :            [self]() { self->mNotifyDataArrivedPromise.Complete(); })
    2990           0 :     ->Track(mNotifyDataArrivedPromise);
    2991             : }
    2992             : 
    2993             : void
    2994           0 : MediaFormatReader::UpdateBuffered()
    2995             : {
    2996           0 :   MOZ_ASSERT(OnTaskQueue());
    2997             : 
    2998           0 :   if (mShutdown) {
    2999           0 :     return;
    3000             :   }
    3001             : 
    3002           0 :   if (!mInitDone || !mHasStartTime) {
    3003           0 :     mBuffered = TimeIntervals();
    3004           0 :     return;
    3005             :   }
    3006             : 
    3007           0 :   if (HasVideo()) {
    3008           0 :     mVideo.mTimeRanges = mVideo.mTrackDemuxer->GetBuffered();
    3009             :     bool hasLastEnd;
    3010           0 :     auto lastEnd = mVideo.mTimeRanges.GetEnd(&hasLastEnd);
    3011           0 :     if (hasLastEnd) {
    3012           0 :       if (mVideo.mLastTimeRangesEnd
    3013           0 :           && mVideo.mLastTimeRangesEnd.ref() < lastEnd) {
    3014             :         // New data was added after our previous end, we can clear the EOS flag.
    3015           0 :         mVideo.mDemuxEOS = false;
    3016           0 :         ScheduleUpdate(TrackInfo::kVideoTrack);
    3017             :       }
    3018           0 :       mVideo.mLastTimeRangesEnd = Some(lastEnd);
    3019             :     }
    3020             :   }
    3021           0 :   if (HasAudio()) {
    3022           0 :     mAudio.mTimeRanges = mAudio.mTrackDemuxer->GetBuffered();
    3023             :     bool hasLastEnd;
    3024           0 :     auto lastEnd = mAudio.mTimeRanges.GetEnd(&hasLastEnd);
    3025           0 :     if (hasLastEnd) {
    3026           0 :       if (mAudio.mLastTimeRangesEnd
    3027           0 :           && mAudio.mLastTimeRangesEnd.ref() < lastEnd) {
    3028             :         // New data was added after our previous end, we can clear the EOS flag.
    3029           0 :         mAudio.mDemuxEOS = false;
    3030           0 :         ScheduleUpdate(TrackInfo::kAudioTrack);
    3031             :       }
    3032           0 :       mAudio.mLastTimeRangesEnd = Some(lastEnd);
    3033             :     }
    3034             :   }
    3035             : 
    3036           0 :   media::TimeIntervals intervals;
    3037           0 :   if (HasAudio() && HasVideo()) {
    3038           0 :     intervals = media::Intersection(mVideo.mTimeRanges, mAudio.mTimeRanges);
    3039           0 :   } else if (HasAudio()) {
    3040           0 :     intervals = mAudio.mTimeRanges;
    3041           0 :   } else if (HasVideo()) {
    3042           0 :     intervals = mVideo.mTimeRanges;
    3043             :   }
    3044             : 
    3045           0 :   if (!intervals.Length()
    3046           0 :       || intervals.GetStart() == TimeUnit::Zero()) {
    3047             :     // IntervalSet already starts at 0 or is empty, nothing to shift.
    3048           0 :     mBuffered = intervals;
    3049             :   } else {
    3050             :     mBuffered =
    3051           0 :       intervals.Shift(TimeUnit::Zero() - mInfo.mStartTime);
    3052             :   }
    3053             : }
    3054             : 
    3055             : layers::ImageContainer*
    3056           0 : MediaFormatReader::GetImageContainer()
    3057             : {
    3058           0 :   return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer()
    3059           0 :                               : nullptr;
    3060             : }
    3061             : 
    3062             : void
    3063           0 : MediaFormatReader::GetMozDebugReaderData(nsACString& aString)
    3064             : {
    3065           0 :   nsAutoCString result;
    3066           0 :   const char* audioName = "unavailable";
    3067           0 :   const char* videoName = audioName;
    3068             : 
    3069           0 :   if (HasAudio()) {
    3070           0 :     MutexAutoLock lock(mAudio.mMutex);
    3071           0 :     audioName = mAudio.mDescription;
    3072             :   }
    3073           0 :   if (HasVideo()) {
    3074           0 :     MutexAutoLock mon(mVideo.mMutex);
    3075           0 :     videoName = mVideo.mDescription;
    3076             :   }
    3077             : 
    3078           0 :   result += nsPrintfCString("Audio Decoder: %s\n", audioName);
    3079           0 :   result += nsPrintfCString("Audio Frames Decoded: %" PRIu64 "\n",
    3080           0 :                             mAudio.mNumSamplesOutputTotal);
    3081           0 :   if (HasAudio()) {
    3082           0 :     result += nsPrintfCString(
    3083             :       "Audio State: ni=%d no=%d wp=%d demuxr=%d demuxq=%u decoder=%d tt=%.1f "
    3084             :       "tths=%d in=%" PRIu64 " out=%" PRIu64
    3085             :       " qs=%u pending=%u wfd=%d eos=%d ds=%d wfk=%d sid=%u\n",
    3086           0 :       NeedInput(mAudio),
    3087           0 :       mAudio.HasPromise(),
    3088           0 :       !mAudio.mWaitingPromise.IsEmpty(),
    3089           0 :       mAudio.mDemuxRequest.Exists(),
    3090           0 :       uint32_t(mAudio.mQueuedSamples.Length()),
    3091           0 :       mAudio.mDecodeRequest.Exists(),
    3092           0 :       mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().Time().ToSeconds()
    3093           0 :                             : -1.0,
    3094           0 :       mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().mHasSeeked : -1,
    3095             :       mAudio.mNumSamplesInput,
    3096             :       mAudio.mNumSamplesOutput,
    3097           0 :       unsigned(size_t(mAudio.mSizeOfQueue)),
    3098           0 :       unsigned(mAudio.mOutput.Length()),
    3099           0 :       mAudio.mWaitingForData,
    3100           0 :       mAudio.mDemuxEOS,
    3101           0 :       int32_t(mAudio.mDrainState),
    3102           0 :       mAudio.mWaitingForKey,
    3103           0 :       mAudio.mLastStreamSourceID);
    3104             :   }
    3105           0 :   result += nsPrintfCString("Video Decoder: %s\n", videoName);
    3106             :   result +=
    3107           0 :     nsPrintfCString("Hardware Video Decoding: %s\n",
    3108           0 :                     VideoIsHardwareAccelerated() ? "enabled" : "disabled");
    3109             :   result +=
    3110           0 :     nsPrintfCString("Video Frames Decoded: %" PRIu64 " (skipped=%" PRIu64 ")\n",
    3111             :                     mVideo.mNumSamplesOutputTotal,
    3112           0 :                     mVideo.mNumSamplesSkippedTotal);
    3113           0 :   if (HasVideo()) {
    3114           0 :     result += nsPrintfCString(
    3115             :       "Video State: ni=%d no=%d wp=%d demuxr=%d demuxq=%u decoder=%d tt=%.1f "
    3116             :       "tths=%d in=%" PRIu64 " out=%" PRIu64
    3117             :       " qs=%u pending:%u wfd=%d eos=%d ds=%d wfk=%d sid=%u\n",
    3118           0 :       NeedInput(mVideo),
    3119           0 :       mVideo.HasPromise(),
    3120           0 :       !mVideo.mWaitingPromise.IsEmpty(),
    3121           0 :       mVideo.mDemuxRequest.Exists(),
    3122           0 :       uint32_t(mVideo.mQueuedSamples.Length()),
    3123           0 :       mVideo.mDecodeRequest.Exists(),
    3124           0 :       mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().Time().ToSeconds()
    3125           0 :                             : -1.0,
    3126           0 :       mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().mHasSeeked : -1,
    3127             :       mVideo.mNumSamplesInput,
    3128             :       mVideo.mNumSamplesOutput,
    3129           0 :       unsigned(size_t(mVideo.mSizeOfQueue)),
    3130           0 :       unsigned(mVideo.mOutput.Length()),
    3131           0 :       mVideo.mWaitingForData,
    3132           0 :       mVideo.mDemuxEOS,
    3133           0 :       int32_t(mVideo.mDrainState),
    3134           0 :       mVideo.mWaitingForKey,
    3135           0 :       mVideo.mLastStreamSourceID);
    3136             :   }
    3137           0 :   aString += result;
    3138           0 : }
    3139             : 
    3140             : void
    3141           0 : MediaFormatReader::SetVideoNullDecode(bool aIsNullDecode)
    3142             : {
    3143           0 :   MOZ_ASSERT(OnTaskQueue());
    3144           0 :   return SetNullDecode(TrackType::kVideoTrack, aIsNullDecode);
    3145             : }
    3146             : 
    3147             : void
    3148           0 : MediaFormatReader::SetNullDecode(TrackType aTrack, bool aIsNullDecode)
    3149             : {
    3150           0 :   MOZ_ASSERT(OnTaskQueue());
    3151             : 
    3152           0 :   auto& decoder = GetDecoderData(aTrack);
    3153           0 :   if (decoder.mIsNullDecode == aIsNullDecode) {
    3154           0 :     return;
    3155             :   }
    3156             : 
    3157           0 :   LOG("%s, decoder.mIsNullDecode = %d => aIsNullDecode = %d",
    3158             :       TrackTypeToStr(aTrack), decoder.mIsNullDecode, aIsNullDecode);
    3159             : 
    3160           0 :   decoder.mIsNullDecode = aIsNullDecode;
    3161           0 :   ShutdownDecoder(aTrack);
    3162             : }
    3163             : 
    3164             : void
    3165           0 : MediaFormatReader::OnFirstDemuxCompleted(
    3166             :   TrackInfo::TrackType aType, RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
    3167             : {
    3168           0 :   MOZ_ASSERT(OnTaskQueue());
    3169             : 
    3170           0 :   if (mShutdown) {
    3171           0 :     return;
    3172             :   }
    3173             : 
    3174           0 :   auto& decoder = GetDecoderData(aType);
    3175           0 :   MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
    3176           0 :   decoder.mFirstDemuxedSampleTime.emplace(aSamples->mSamples[0]->mTime);
    3177           0 :   MaybeResolveMetadataPromise();
    3178             : }
    3179             : 
    3180             : void
    3181           0 : MediaFormatReader::OnFirstDemuxFailed(TrackInfo::TrackType aType,
    3182             :                                       const MediaResult& aError)
    3183             : {
    3184           0 :   MOZ_ASSERT(OnTaskQueue());
    3185             : 
    3186           0 :   if (mShutdown) {
    3187           0 :     return;
    3188             :   }
    3189             : 
    3190           0 :   auto& decoder = GetDecoderData(aType);
    3191           0 :   MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
    3192           0 :   decoder.mFirstDemuxedSampleTime.emplace(TimeUnit::FromInfinity());
    3193           0 :   MaybeResolveMetadataPromise();
    3194             : }
    3195             : 
    3196             : } // namespace mozilla
    3197             : 
    3198             : #undef NS_DispatchToMainThread

Generated by: LCOV version 1.13