tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaFormatReader.cpp (132978B)


      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 <algorithm>
     10 #include <queue>
     11 
     12 #include "AllocationPolicy.h"
     13 #ifdef MOZ_AV1
     14 #  include "AOMDecoder.h"
     15 #endif
     16 #include "MP4Decoder.h"
     17 #include "MediaData.h"
     18 #include "MediaDataDecoderProxy.h"
     19 #include "MediaInfo.h"
     20 #include "PDMFactory.h"
     21 #include "PerformanceRecorder.h"
     22 #include "VPXDecoder.h"
     23 #include "VideoFrameContainer.h"
     24 #include "VideoUtils.h"
     25 #include "mozilla/AbstractThread.h"
     26 #include "mozilla/CDMProxy.h"
     27 #include "mozilla/ClearOnShutdown.h"
     28 #include "mozilla/NotNull.h"
     29 #include "mozilla/Preferences.h"
     30 #include "mozilla/ProfilerLabels.h"
     31 #include "mozilla/ProfilerMarkers.h"
     32 #include "mozilla/SharedThreadPool.h"
     33 #include "mozilla/StaticPrefs_media.h"
     34 #include "mozilla/TaskQueue.h"
     35 #include "mozilla/glean/DomMediaMetrics.h"
     36 #include "nsContentUtils.h"
     37 #include "nsLiteralString.h"
     38 #include "nsPrintfCString.h"
     39 #include "nsTHashSet.h"
     40 
     41 using namespace mozilla::media;
     42 
     43 static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
     44 
     45 #define LOG(arg, ...)                                                  \
     46  DDMOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, "::%s: " arg, \
     47            __func__, ##__VA_ARGS__)
     48 #define LOGV(arg, ...)                                                   \
     49  DDMOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, "::%s: " arg, \
     50            __func__, ##__VA_ARGS__)
     51 
     52 #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
     53 
     54 namespace mozilla {
     55 
     56 using MediaDataDecoderID = void*;
     57 
     58 /**
     59 * This class tracks shutdown promises to ensure all decoders are shut down
     60 * completely before MFR continues the rest of the shutdown procedure.
     61 */
     62 class MediaFormatReader::ShutdownPromisePool {
     63 public:
     64  ShutdownPromisePool()
     65      : mOnShutdownComplete(new ShutdownPromise::Private(__func__)) {}
     66 
     67  // Return a promise which will be resolved when all the tracking promises
     68  // are resolved. Note no more promises should be added for tracking once
     69  // this function is called.
     70  RefPtr<ShutdownPromise> Shutdown();
     71 
     72  // Track a shutdown promise.
     73  void Track(const RefPtr<ShutdownPromise>& aPromise);
     74 
     75  // Shut down a decoder and track its shutdown promise.
     76  void ShutdownDecoder(already_AddRefed<MediaDataDecoder> aDecoder) {
     77    Track(RefPtr<MediaDataDecoder>(aDecoder)->Shutdown());
     78  }
     79 
     80 private:
     81  bool mShutdown = false;
     82  const RefPtr<ShutdownPromise::Private> mOnShutdownComplete;
     83  nsTHashSet<RefPtr<ShutdownPromise>> mPromises;
     84 };
     85 
     86 RefPtr<ShutdownPromise> MediaFormatReader::ShutdownPromisePool::Shutdown() {
     87  MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
     88  mShutdown = true;
     89  if (mPromises.Count() == 0) {
     90    mOnShutdownComplete->Resolve(true, __func__);
     91  }
     92  return mOnShutdownComplete;
     93 }
     94 
     95 void MediaFormatReader::ShutdownPromisePool::Track(
     96    const RefPtr<ShutdownPromise>& aPromise) {
     97  MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
     98  MOZ_DIAGNOSTIC_ASSERT(!mPromises.Contains(aPromise));
     99  mPromises.Insert(aPromise);
    100  aPromise->Then(AbstractThread::GetCurrent(), __func__, [aPromise, this]() {
    101    MOZ_DIAGNOSTIC_ASSERT(mPromises.Contains(aPromise));
    102    mPromises.Remove(aPromise);
    103    if (mShutdown && mPromises.Count() == 0) {
    104      mOnShutdownComplete->Resolve(true, __func__);
    105    }
    106  });
    107 }
    108 
    109 void MediaFormatReader::DecoderData::ShutdownDecoder() {
    110  MOZ_ASSERT(mOwner->OnTaskQueue());
    111 
    112  MutexAutoLock lock(mMutex);
    113 
    114  if (!mDecoder) {
    115    // No decoder to shut down.
    116    return;
    117  }
    118 
    119  if (mFlushing) {
    120    // Flush is is in action. Shutdown will be initiated after flush completes.
    121    MOZ_DIAGNOSTIC_ASSERT(mShutdownPromise);
    122    mOwner->mShutdownPromisePool->Track(mShutdownPromise->Ensure(__func__));
    123    // The order of decoder creation and shutdown is handled by LocalAllocPolicy
    124    // and ShutdownPromisePool. MFR can now reset these members to a fresh state
    125    // and be ready to create new decoders again without explicitly waiting for
    126    // flush/shutdown to complete.
    127    mShutdownPromise = nullptr;
    128    mFlushing = false;
    129  } else {
    130    // No flush is in action. We can shut down the decoder now.
    131    mOwner->mShutdownPromisePool->Track(mDecoder->Shutdown());
    132  }
    133 
    134  // mShutdownPromisePool will handle the order of decoder shutdown so
    135  // we can forget mDecoder and be ready to create a new one.
    136  mDecoder = nullptr;
    137  mDescription = "shutdown"_ns;
    138  mHasReportedVideoHardwareSupportTelemtry = false;
    139  mOwner->ScheduleUpdate(mType == MediaData::Type::AUDIO_DATA
    140                             ? TrackType::kAudioTrack
    141                             : TrackType::kVideoTrack);
    142 }
    143 
    144 void MediaFormatReader::DecoderData::Flush() {
    145  AUTO_PROFILER_LABEL("MediaFormatReader::Flush", MEDIA_PLAYBACK);
    146  MOZ_ASSERT(mOwner->OnTaskQueue());
    147 
    148  if (mFlushing || mFlushed) {
    149    // Flush still pending or already flushed, nothing more to do.
    150    return;
    151  }
    152  mDecodeRequest.DisconnectIfExists();
    153  mDrainRequest.DisconnectIfExists();
    154  mDrainState = DrainState::None;
    155  CancelWaitingForKey();
    156  mOutput.Clear();
    157  mNumSamplesInput = 0;
    158  mNumSamplesOutput = 0;
    159  mSizeOfQueue = 0;
    160  if (mDecoder) {
    161    TrackType type = mType == MediaData::Type::AUDIO_DATA
    162                         ? TrackType::kAudioTrack
    163                         : TrackType::kVideoTrack;
    164    mFlushing = true;
    165    MOZ_DIAGNOSTIC_ASSERT(!mShutdownPromise);
    166    mShutdownPromise = new SharedShutdownPromiseHolder();
    167    RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
    168    RefPtr<MediaDataDecoder> d = mDecoder;
    169    DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
    170             "flushing", DDNoValue{});
    171    mDecoder->Flush()->Then(
    172        mOwner->OwnerThread(), __func__,
    173        [type, this, p, d]() {
    174          AUTO_PROFILER_LABEL("MediaFormatReader::Flush:Resolved",
    175                              MEDIA_PLAYBACK);
    176          DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
    177                   "flushed", DDNoValue{});
    178          if (!p->IsEmpty()) {
    179            // Shutdown happened before flush completes.
    180            // Let's continue to shut down the decoder. Note
    181            // we don't access |this| because this decoder
    182            // is no longer managed by MFR::DecoderData.
    183            d->Shutdown()->ChainTo(p->Steal(), __func__);
    184            return;
    185          }
    186          mFlushing = false;
    187          mShutdownPromise = nullptr;
    188          mOwner->ScheduleUpdate(type);
    189        },
    190        [type, this, p, d](const MediaResult& aError) {
    191          AUTO_PROFILER_LABEL("MediaFormatReader::Flush:Rejected",
    192                              MEDIA_PLAYBACK);
    193          DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
    194                   "flush_error", aError);
    195          if (!p->IsEmpty()) {
    196            d->Shutdown()->ChainTo(p->Steal(), __func__);
    197            return;
    198          }
    199          mFlushing = false;
    200          mShutdownPromise = nullptr;
    201          mOwner->NotifyError(type, aError);
    202        });
    203  }
    204  mFlushed = true;
    205 }
    206 
    207 void MediaFormatReader::DecoderData::RequestDrain() {
    208  LOG("");
    209  MOZ_RELEASE_ASSERT(mDrainState == DrainState::None);
    210  mDrainState = DrainState::DrainRequested;
    211 }
    212 
    213 class MediaFormatReader::DecoderFactory {
    214  using InitPromise = MediaDataDecoder::InitPromise;
    215  using TokenPromise = AllocPolicy::Promise;
    216  using Token = AllocPolicy::Token;
    217  using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
    218 
    219 public:
    220  explicit DecoderFactory(MediaFormatReader* aOwner)
    221      : mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread()),
    222        mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread()),
    223        mOwner(WrapNotNull(aOwner)) {
    224    DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderFactory",
    225                                         this);
    226    DecoderDoctorLogger::LinkParentAndChild(
    227        aOwner, "decoder factory", "MediaFormatReader::DecoderFactory", this);
    228  }
    229 
    230  ~DecoderFactory() {
    231    DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderFactory",
    232                                        this);
    233  }
    234 
    235  void CreateDecoder(TrackType aTrack);
    236 
    237  // Shutdown any decoder pending initialization and reset mAudio/mVideo to its
    238  // pristine state so CreateDecoder() is ready to be called again immediately.
    239  void ShutdownDecoder(TrackType aTrack) {
    240    MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
    241               aTrack == TrackInfo::kVideoTrack);
    242    auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
    243    data.mPolicy->Cancel();
    244    data.mTokenRequest.DisconnectIfExists();
    245    if (data.mLiveToken) {
    246      // We haven't completed creation of the decoder, and it hasn't been
    247      // initialised yet.
    248      data.mLiveToken = nullptr;
    249      // The decoder will be shutdown as soon as it's available and tracked by
    250      // the ShutdownPromisePool.
    251      mOwner->mShutdownPromisePool->Track(data.mCreateDecoderPromise->Then(
    252          mOwner->mTaskQueue, __func__,
    253          [](CreateDecoderPromise::ResolveOrRejectValue&& aResult) {
    254            if (aResult.IsReject()) {
    255              return ShutdownPromise::CreateAndResolve(true, __func__);
    256            }
    257            return aResult.ResolveValue()->Shutdown();
    258          }));
    259      // Free the token to leave room for a new decoder.
    260      data.mToken = nullptr;
    261    }
    262    data.mInitRequest.DisconnectIfExists();
    263    if (data.mDecoder) {
    264      mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
    265    }
    266    data.mStage = Stage::None;
    267    MOZ_ASSERT(!data.mToken);
    268  }
    269 
    270 private:
    271  enum class Stage : int8_t { None, WaitForToken, CreateDecoder, WaitForInit };
    272 
    273  struct Data {
    274    Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
    275        : mOwnerData(aOwnerData),
    276          mTrack(aTrack),
    277          mPolicy(new SingleAllocPolicy(aTrack, aThread)) {}
    278    DecoderData& mOwnerData;
    279    const TrackType mTrack;
    280    RefPtr<SingleAllocPolicy> mPolicy;
    281    Stage mStage = Stage::None;
    282    RefPtr<Token> mToken;
    283    RefPtr<MediaDataDecoder> mDecoder;
    284    MozPromiseRequestHolder<TokenPromise> mTokenRequest;
    285    struct DecoderCancelled : public SupportsWeakPtr {
    286      NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(DecoderCancelled)
    287     private:
    288      ~DecoderCancelled() = default;
    289    };
    290    // Set when decoder is about to be created. If cleared before the decoder
    291    // creation promise is resolved; it indicates that Shutdown() was called and
    292    // further processing such as initialization should stop.
    293    RefPtr<DecoderCancelled> mLiveToken;
    294    RefPtr<CreateDecoderPromise> mCreateDecoderPromise;
    295    MozPromiseRequestHolder<InitPromise> mInitRequest;
    296  } mAudio, mVideo;
    297 
    298  void RunStage(Data& aData);
    299  void DoCreateDecoder(Data& aData);
    300  void DoInitDecoder(Data& aData);
    301 
    302  // guaranteed to be valid by the owner.
    303  const NotNull<MediaFormatReader*> mOwner;
    304 };
    305 
    306 void MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack) {
    307  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
    308             aTrack == TrackInfo::kVideoTrack);
    309  Data& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
    310  MOZ_DIAGNOSTIC_ASSERT_IF(mOwner->GetDecoderData(data.mTrack).IsEncrypted(),
    311                           mOwner->mCDMProxy);
    312  RunStage(data);
    313 }
    314 
    315 void MediaFormatReader::DecoderFactory::RunStage(Data& aData) {
    316  switch (aData.mStage) {
    317    case Stage::None: {
    318      MOZ_DIAGNOSTIC_ASSERT(!aData.mToken);
    319      aData.mPolicy->Alloc()
    320          ->Then(
    321              mOwner->OwnerThread(), __func__,
    322              [this, &aData](RefPtr<Token> aToken) {
    323                aData.mTokenRequest.Complete();
    324                aData.mToken = std::move(aToken);
    325                aData.mStage = Stage::CreateDecoder;
    326                RunStage(aData);
    327              },
    328              [&aData]() {
    329                aData.mTokenRequest.Complete();
    330                aData.mStage = Stage::None;
    331              })
    332          ->Track(aData.mTokenRequest);
    333      aData.mStage = Stage::WaitForToken;
    334      break;
    335    }
    336 
    337    case Stage::WaitForToken: {
    338      MOZ_DIAGNOSTIC_ASSERT(!aData.mToken);
    339      MOZ_DIAGNOSTIC_ASSERT(aData.mTokenRequest.Exists());
    340      break;
    341    }
    342 
    343    case Stage::CreateDecoder: {
    344      MOZ_DIAGNOSTIC_ASSERT(aData.mToken);
    345      MOZ_DIAGNOSTIC_ASSERT(!aData.mDecoder);
    346      MOZ_DIAGNOSTIC_ASSERT(!aData.mInitRequest.Exists());
    347 
    348      DoCreateDecoder(aData);
    349      aData.mStage = Stage::WaitForInit;
    350      break;
    351    }
    352 
    353    case Stage::WaitForInit: {
    354      MOZ_DIAGNOSTIC_ASSERT((aData.mDecoder && aData.mInitRequest.Exists()) ||
    355                            aData.mLiveToken);
    356      break;
    357    }
    358  }
    359 }
    360 
    361 void MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
    362  AUTO_PROFILER_LABEL("DecoderFactory::DoCreateDecoder", MEDIA_PLAYBACK);
    363  auto& ownerData = aData.mOwnerData;
    364  auto& decoder = mOwner->GetDecoderData(aData.mTrack);
    365 
    366  RefPtr<PDMFactory> platform = new PDMFactory();
    367  if (decoder.IsEncrypted()) {
    368    MOZ_DIAGNOSTIC_ASSERT(mOwner->mCDMProxy);
    369    platform->SetCDMProxy(mOwner->mCDMProxy);
    370  }
    371 
    372  RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
    373  MediaFormatReader* owner = mOwner;
    374  auto onWaitingForKeyEvent =
    375      [owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)]() {
    376        RefPtr<MediaFormatReader> mfr(owner);
    377        MOZ_DIAGNOSTIC_ASSERT(mfr, "The MediaFormatReader didn't wait for us");
    378        return mfr ? &mfr->OnTrackWaitingForKeyProducer() : nullptr;
    379      };
    380 
    381  switch (aData.mTrack) {
    382    case TrackInfo::kAudioTrack: {
    383      p = platform->CreateDecoder(
    384          {*ownerData.GetCurrentInfo()->GetAsAudioInfo(), mOwner->mCrashHelper,
    385           CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
    386           TrackInfo::kAudioTrack, std::move(onWaitingForKeyEvent),
    387           mOwner->mMediaEngineId, mOwner->mTrackingId,
    388           mOwner->mEncryptedCustomIdent
    389               ? CreateDecoderParams::EncryptedCustomIdent::True
    390               : CreateDecoderParams::EncryptedCustomIdent::False});
    391      break;
    392    }
    393 
    394    case TrackType::kVideoTrack: {
    395      // Decoders use the layers backend to decide if they can use hardware
    396      // decoding, so specify LAYERS_NONE if we want to forcibly disable it.
    397      using Option = CreateDecoderParams::Option;
    398      using OptionSet = CreateDecoderParams::OptionSet;
    399 
    400      p = platform->CreateDecoder(
    401          {*ownerData.GetCurrentInfo()->GetAsVideoInfo(),
    402           mOwner->mKnowsCompositor, mOwner->GetImageContainer(),
    403           mOwner->mCrashHelper,
    404           CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
    405           TrackType::kVideoTrack, std::move(onWaitingForKeyEvent),
    406           CreateDecoderParams::VideoFrameRate(ownerData.mMeanRate.Mean()),
    407           OptionSet(ownerData.mHardwareDecodingDisabled
    408                         ? Option::HardwareDecoderNotAllowed
    409                         : Option::Default,
    410                     mOwner->mVideoFrameContainer->SupportsOnly8BitImage()
    411                         ? Option::Output8BitPerChannel
    412                         : Option::Default),
    413           mOwner->mMediaEngineId, mOwner->mTrackingId,
    414           mOwner->mEncryptedCustomIdent
    415               ? CreateDecoderParams::EncryptedCustomIdent::True
    416               : CreateDecoderParams::EncryptedCustomIdent::False});
    417      break;
    418    }
    419 
    420    default:
    421      p = PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
    422          NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
    423  }
    424 
    425  aData.mLiveToken = MakeRefPtr<Data::DecoderCancelled>();
    426 
    427  aData.mCreateDecoderPromise = p->Then(
    428      mOwner->OwnerThread(), __func__,
    429      [this, &aData, &ownerData, live = WeakPtr{aData.mLiveToken},
    430       owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)](
    431          RefPtr<MediaDataDecoder>&& aDecoder) {
    432        if (!live) {
    433          return CreateDecoderPromise::CreateAndResolve(std::move(aDecoder),
    434                                                        __func__);
    435        }
    436        aData.mLiveToken = nullptr;
    437        aData.mDecoder = new MediaDataDecoderProxy(
    438            aDecoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
    439        aData.mDecoder = new AllocationWrapper(aData.mDecoder.forget(),
    440                                               aData.mToken.forget());
    441        DecoderDoctorLogger::LinkParentAndChild(
    442            aData.mDecoder.get(), "decoder",
    443            "MediaFormatReader::DecoderFactory", this);
    444 
    445        DoInitDecoder(aData);
    446 
    447        return CreateDecoderPromise::CreateAndResolve(aData.mDecoder, __func__);
    448      },
    449      [this, &aData,
    450       live = WeakPtr{aData.mLiveToken}](const MediaResult& aError) {
    451        NS_WARNING("Error constructing decoders");
    452        if (!live) {
    453          return CreateDecoderPromise::CreateAndReject(aError, __func__);
    454        }
    455        aData.mLiveToken = nullptr;
    456        aData.mToken = nullptr;
    457        aData.mStage = Stage::None;
    458        aData.mOwnerData.mDescription = aError.Description();
    459        DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
    460                 "create_decoder_error", aError);
    461        mOwner->NotifyError(aData.mTrack, aError);
    462 
    463        return CreateDecoderPromise::CreateAndReject(aError, __func__);
    464      });
    465 }
    466 
    467 void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {
    468  AUTO_PROFILER_LABEL("DecoderFactory::DoInitDecoder", MEDIA_PLAYBACK);
    469  auto& ownerData = aData.mOwnerData;
    470 
    471  DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
    472           "initialize_decoder", DDNoValue{});
    473  aData.mDecoder->Init()
    474      ->Then(
    475          mOwner->OwnerThread(), __func__,
    476          [this, &aData, &ownerData](TrackType aTrack) {
    477            AUTO_PROFILER_LABEL("DecoderFactory::DoInitDecoder:Resolved",
    478                                MEDIA_PLAYBACK);
    479            aData.mInitRequest.Complete();
    480            aData.mStage = Stage::None;
    481            MutexAutoLock lock(ownerData.mMutex);
    482            ownerData.mDecoder = std::move(aData.mDecoder);
    483            ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
    484            DDLOGEX2("MediaFormatReader::DecoderFactory", this,
    485                     DDLogCategory::Log, "decoder_initialized", DDNoValue{});
    486            DecoderDoctorLogger::LinkParentAndChild(
    487                "MediaFormatReader::DecoderData", &ownerData, "decoder",
    488                ownerData.mDecoder.get());
    489            mOwner->SetVideoDecodeThreshold();
    490            mOwner->ScheduleUpdate(aTrack);
    491            if (aTrack == TrackInfo::kAudioTrack) {
    492              ownerData.mProcessName = ownerData.mDecoder->GetProcessName();
    493              ownerData.mCodecName = ownerData.mDecoder->GetCodecName();
    494            }
    495            nsCString needsConversion;
    496            switch (ownerData.mDecoder->NeedsConversion()) {
    497              case MediaDataDecoder::ConversionRequired::kNeedNone:
    498                needsConversion = "false";
    499                break;
    500              case MediaDataDecoder::ConversionRequired::kNeedAVCC:
    501                needsConversion = "AVCC";
    502                break;
    503              case MediaDataDecoder::ConversionRequired::kNeedAnnexB:
    504                needsConversion = "AnnexB";
    505                break;
    506              default:
    507                needsConversion = "Unknown";
    508            }
    509            nsCString dummy;
    510            MOZ_LOG_FMT(sFormatDecoderLog, mozilla::LogLevel::Debug,
    511                        "Decoder init finished for "
    512                        "{} codec: \"{}\", "
    513                        "description: \"{}\", "
    514                        "process: \"{}\", "
    515                        "hw: \"{}\", "
    516                        "needs conversion: \"{}\"",
    517                        (aTrack == TrackInfo::kVideoTrack) ? "video" : "audio",
    518                        ownerData.mDecoder->GetCodecName(),
    519                        ownerData.mDecoder->GetDescriptionName(),
    520                        ownerData.mDecoder->GetProcessName(),
    521                        ownerData.mDecoder->IsHardwareAccelerated(dummy),
    522                        needsConversion);
    523          },
    524          [this, &aData, &ownerData](const MediaResult& aError) {
    525            AUTO_PROFILER_LABEL("DecoderFactory::DoInitDecoder:Rejected",
    526                                MEDIA_PLAYBACK);
    527            aData.mInitRequest.Complete();
    528            MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
    529                               "Can't have a decoder already set");
    530            aData.mStage = Stage::None;
    531            mOwner->mShutdownPromisePool->ShutdownDecoder(
    532                aData.mDecoder.forget());
    533            DDLOGEX2("MediaFormatReader::DecoderFactory", this,
    534                     DDLogCategory::Log, "initialize_decoder_error", aError);
    535            mOwner->NotifyError(aData.mTrack, aError);
    536          })
    537      ->Track(aData.mInitRequest);
    538 }
    539 
    540 // DemuxerProxy ensures that the original main demuxer is only ever accessed
    541 // via its own dedicated task queue.
    542 // This ensure that the reader's taskqueue will never blocked while a demuxer
    543 // is itself blocked attempting to access the MediaCache or the MediaResource.
    544 class MediaFormatReader::DemuxerProxy {
    545  using TrackType = TrackInfo::TrackType;
    546  class Wrapper;
    547 
    548 public:
    549  explicit DemuxerProxy(MediaDataDemuxer* aDemuxer)
    550      : mTaskQueue(TaskQueue::Create(
    551            GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
    552            "DemuxerProxy::mTaskQueue")),
    553        mData(new Data(aDemuxer)) {
    554    MOZ_COUNT_CTOR(DemuxerProxy);
    555  }
    556 
    557  MOZ_COUNTED_DTOR(DemuxerProxy)
    558 
    559  RefPtr<ShutdownPromise> Shutdown() {
    560    RefPtr<Data> data = std::move(mData);
    561    return InvokeAsync(mTaskQueue, __func__, [data]() {
    562      // We need to clear our reference to the demuxer now. So that in the event
    563      // the init promise wasn't resolved, such as what can happen with the
    564      // mediasource demuxer that is waiting on more data, it will force the
    565      // init promise to be rejected.
    566      data->mDemuxer = nullptr;
    567      data->mAudioDemuxer = nullptr;
    568      data->mVideoDemuxer = nullptr;
    569      return ShutdownPromise::CreateAndResolve(true, __func__);
    570    });
    571  }
    572 
    573  RefPtr<MediaDataDemuxer::InitPromise> Init();
    574 
    575  Wrapper* GetTrackDemuxer(TrackType aTrack, uint32_t aTrackNumber) {
    576    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    577 
    578    switch (aTrack) {
    579      case TrackInfo::kAudioTrack:
    580        return mData->mAudioDemuxer;
    581      case TrackInfo::kVideoTrack:
    582        return mData->mVideoDemuxer;
    583      default:
    584        return nullptr;
    585    }
    586  }
    587 
    588  uint32_t GetNumberTracks(TrackType aTrack) const {
    589    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    590 
    591    switch (aTrack) {
    592      case TrackInfo::kAudioTrack:
    593        return mData->mNumAudioTrack;
    594      case TrackInfo::kVideoTrack:
    595        return mData->mNumVideoTrack;
    596      default:
    597        return 0;
    598    }
    599  }
    600 
    601  bool IsSeekable() const {
    602    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    603 
    604    return mData->mSeekable;
    605  }
    606 
    607  bool IsSeekableOnlyInBufferedRanges() const {
    608    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    609 
    610    return mData->mSeekableOnlyInBufferedRange;
    611  }
    612 
    613  UniquePtr<EncryptionInfo> GetCrypto() const {
    614    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    615 
    616    if (!mData->mCrypto) {
    617      return nullptr;
    618    }
    619    auto crypto = MakeUnique<EncryptionInfo>();
    620    *crypto = *mData->mCrypto;
    621    return crypto;
    622  }
    623 
    624  RefPtr<NotifyDataArrivedPromise> NotifyDataArrived();
    625 
    626  bool ShouldComputeStartTime() const {
    627    MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
    628 
    629    return mData->mShouldComputeStartTime;
    630  }
    631 
    632 private:
    633  const RefPtr<TaskQueue> mTaskQueue;
    634  struct Data {
    635    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Data)
    636 
    637    explicit Data(MediaDataDemuxer* aDemuxer)
    638        : mInitDone(false), mDemuxer(aDemuxer) {}
    639 
    640    Atomic<bool> mInitDone;
    641    // Only ever accessed over mTaskQueue once.
    642    RefPtr<MediaDataDemuxer> mDemuxer;
    643    // Only accessed once InitPromise has been resolved and immutable after.
    644    // So we can safely access them without the use of the mutex.
    645    uint32_t mNumAudioTrack = 0;
    646    RefPtr<Wrapper> mAudioDemuxer;
    647    uint32_t mNumVideoTrack = 0;
    648    RefPtr<Wrapper> mVideoDemuxer;
    649    bool mSeekable = false;
    650    bool mSeekableOnlyInBufferedRange = false;
    651    bool mShouldComputeStartTime = true;
    652    UniquePtr<EncryptionInfo> mCrypto;
    653 
    654   private:
    655    ~Data() = default;
    656  };
    657  RefPtr<Data> mData;
    658 };
    659 
    660 class MediaFormatReader::DemuxerProxy::Wrapper : public MediaTrackDemuxer {
    661 public:
    662  Wrapper(MediaTrackDemuxer* aTrackDemuxer, TaskQueue* aTaskQueue)
    663      : mMutex("TrackDemuxer Mutex"),
    664        mTaskQueue(aTaskQueue),
    665        mGetSamplesMayBlock(aTrackDemuxer->GetSamplesMayBlock()),
    666        mInfo(aTrackDemuxer->GetInfo()),
    667        mTrackDemuxer(aTrackDemuxer) {
    668    DecoderDoctorLogger::LogConstructionAndBase(
    669        "MediaFormatReader::DemuxerProxy::Wrapper", this,
    670        static_cast<const MediaTrackDemuxer*>(this));
    671    DecoderDoctorLogger::LinkParentAndChild(
    672        "MediaFormatReader::DemuxerProxy::Wrapper", this, "track demuxer",
    673        aTrackDemuxer);
    674  }
    675 
    676  UniquePtr<TrackInfo> GetInfo() const override {
    677    if (!mInfo) {
    678      return nullptr;
    679    }
    680    return mInfo->Clone();
    681  }
    682 
    683  RefPtr<SeekPromise> Seek(const TimeUnit& aTime) override {
    684    RefPtr<Wrapper> self = this;
    685    return InvokeAsync(
    686               mTaskQueue, __func__,
    687               [self, aTime]() { return self->mTrackDemuxer->Seek(aTime); })
    688        ->Then(
    689            mTaskQueue, __func__,
    690            [self](const TimeUnit& aTime) {
    691              self->UpdateRandomAccessPoint();
    692              return SeekPromise::CreateAndResolve(aTime, __func__);
    693            },
    694            [self](const MediaResult& aError) {
    695              self->UpdateRandomAccessPoint();
    696              return SeekPromise::CreateAndReject(aError, __func__);
    697            });
    698  }
    699 
    700  RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override {
    701    RefPtr<Wrapper> self = this;
    702    return InvokeAsync(mTaskQueue, __func__,
    703                       [self, aNumSamples]() {
    704                         return self->mTrackDemuxer->GetSamples(aNumSamples);
    705                       })
    706        ->Then(
    707            mTaskQueue, __func__,
    708            [self](RefPtr<SamplesHolder> aSamples) {
    709              self->UpdateRandomAccessPoint();
    710              return SamplesPromise::CreateAndResolve(aSamples.forget(),
    711                                                      __func__);
    712            },
    713            [self](const MediaResult& aError) {
    714              self->UpdateRandomAccessPoint();
    715              return SamplesPromise::CreateAndReject(aError, __func__);
    716            });
    717  }
    718 
    719  bool GetSamplesMayBlock() const override { return mGetSamplesMayBlock; }
    720 
    721  void Reset() override {
    722    RefPtr<Wrapper> self = this;
    723    nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
    724        "MediaFormatReader::DemuxerProxy::Wrapper::Reset",
    725        [self]() { self->mTrackDemuxer->Reset(); }));
    726    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    727    (void)rv;
    728  }
    729 
    730  nsresult GetNextRandomAccessPoint(TimeUnit* aTime) override {
    731    MutexAutoLock lock(mMutex);
    732    if (NS_SUCCEEDED(mNextRandomAccessPointResult)) {
    733      *aTime = mNextRandomAccessPoint;
    734    }
    735    return mNextRandomAccessPointResult;
    736  }
    737 
    738  RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
    739      const TimeUnit& aTimeThreshold) override {
    740    RefPtr<Wrapper> self = this;
    741    return InvokeAsync(
    742               mTaskQueue, __func__,
    743               [self, aTimeThreshold]() {
    744                 return self->mTrackDemuxer->SkipToNextRandomAccessPoint(
    745                     aTimeThreshold);
    746               })
    747        ->Then(
    748            mTaskQueue, __func__,
    749            [self](uint32_t aVal) {
    750              self->UpdateRandomAccessPoint();
    751              return SkipAccessPointPromise::CreateAndResolve(aVal, __func__);
    752            },
    753            [self](const SkipFailureHolder& aError) {
    754              self->UpdateRandomAccessPoint();
    755              return SkipAccessPointPromise::CreateAndReject(aError, __func__);
    756            });
    757  }
    758 
    759  TimeIntervals GetBuffered() override {
    760    MutexAutoLock lock(mMutex);
    761    return mBuffered;
    762  }
    763 
    764  void BreakCycles() override {}
    765 
    766 private:
    767  Mutex mMutex MOZ_UNANNOTATED;
    768  const RefPtr<TaskQueue> mTaskQueue;
    769  const bool mGetSamplesMayBlock;
    770  const UniquePtr<TrackInfo> mInfo;
    771  // mTrackDemuxer is only ever accessed on demuxer's task queue.
    772  RefPtr<MediaTrackDemuxer> mTrackDemuxer;
    773  // All following members are protected by mMutex
    774  nsresult mNextRandomAccessPointResult = NS_OK;
    775  TimeUnit mNextRandomAccessPoint;
    776  TimeIntervals mBuffered;
    777  friend class DemuxerProxy;
    778 
    779  ~Wrapper() {
    780    RefPtr<MediaTrackDemuxer> trackDemuxer = std::move(mTrackDemuxer);
    781    nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
    782        "MediaFormatReader::DemuxerProxy::Wrapper::~Wrapper",
    783        [trackDemuxer]() { trackDemuxer->BreakCycles(); }));
    784    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    785    (void)rv;
    786    DecoderDoctorLogger::LogDestruction(
    787        "MediaFormatReader::DemuxerProxy::Wrapper", this);
    788  }
    789 
    790  void UpdateRandomAccessPoint() {
    791    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
    792    if (!mTrackDemuxer) {
    793      // Detached.
    794      return;
    795    }
    796    MutexAutoLock lock(mMutex);
    797    mNextRandomAccessPointResult =
    798        mTrackDemuxer->GetNextRandomAccessPoint(&mNextRandomAccessPoint);
    799  }
    800 
    801  void UpdateBuffered() {
    802    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
    803    if (!mTrackDemuxer) {
    804      // Detached.
    805      return;
    806    }
    807    MutexAutoLock lock(mMutex);
    808    mBuffered = mTrackDemuxer->GetBuffered();
    809  }
    810 };
    811 
    812 RefPtr<MediaDataDemuxer::InitPromise> MediaFormatReader::DemuxerProxy::Init() {
    813  AUTO_PROFILER_LABEL("DemuxerProxy::Init", MEDIA_PLAYBACK);
    814  using InitPromise = MediaDataDemuxer::InitPromise;
    815 
    816  RefPtr<Data> data = mData;
    817  RefPtr<TaskQueue> taskQueue = mTaskQueue;
    818  return InvokeAsync(mTaskQueue, __func__,
    819                     [data, taskQueue]() {
    820                       if (!data->mDemuxer) {
    821                         return InitPromise::CreateAndReject(
    822                             NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    823                       }
    824                       return data->mDemuxer->Init();
    825                     })
    826      ->Then(
    827          taskQueue, __func__,
    828          [data, taskQueue]() {
    829            AUTO_PROFILER_LABEL("DemuxerProxy::Init:Resolved", MEDIA_PLAYBACK);
    830            if (!data->mDemuxer) {  // Was shutdown.
    831              return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
    832                                                  __func__);
    833            }
    834            data->mNumAudioTrack =
    835                data->mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
    836            if (data->mNumAudioTrack) {
    837              RefPtr<MediaTrackDemuxer> d =
    838                  data->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
    839              if (d) {
    840                RefPtr<Wrapper> wrapper =
    841                    new DemuxerProxy::Wrapper(d, taskQueue);
    842                wrapper->UpdateBuffered();
    843                data->mAudioDemuxer = wrapper;
    844                DecoderDoctorLogger::LinkParentAndChild(
    845                    data->mDemuxer.get(), "decoder factory wrapper",
    846                    "MediaFormatReader::DecoderFactory::Wrapper",
    847                    wrapper.get());
    848              }
    849            }
    850            data->mNumVideoTrack =
    851                data->mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
    852            if (data->mNumVideoTrack) {
    853              RefPtr<MediaTrackDemuxer> d =
    854                  data->mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
    855              if (d) {
    856                RefPtr<Wrapper> wrapper =
    857                    new DemuxerProxy::Wrapper(d, taskQueue);
    858                wrapper->UpdateBuffered();
    859                data->mVideoDemuxer = wrapper;
    860                DecoderDoctorLogger::LinkParentAndChild(
    861                    data->mDemuxer.get(), "decoder factory wrapper",
    862                    "MediaFormatReader::DecoderFactory::Wrapper",
    863                    wrapper.get());
    864              }
    865            }
    866            data->mCrypto = data->mDemuxer->GetCrypto();
    867            data->mSeekable = data->mDemuxer->IsSeekable();
    868            data->mSeekableOnlyInBufferedRange =
    869                data->mDemuxer->IsSeekableOnlyInBufferedRanges();
    870            data->mShouldComputeStartTime =
    871                data->mDemuxer->ShouldComputeStartTime();
    872            data->mInitDone = true;
    873            return InitPromise::CreateAndResolve(NS_OK, __func__);
    874          },
    875          [](const MediaResult& aError) {
    876            return InitPromise::CreateAndReject(aError, __func__);
    877          });
    878 }
    879 
    880 RefPtr<MediaFormatReader::NotifyDataArrivedPromise>
    881 MediaFormatReader::DemuxerProxy::NotifyDataArrived() {
    882  RefPtr<Data> data = mData;
    883  return InvokeAsync(mTaskQueue, __func__, [data]() {
    884    if (!data->mDemuxer) {
    885      // Was shutdown.
    886      return NotifyDataArrivedPromise::CreateAndReject(
    887          NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    888    }
    889    data->mDemuxer->NotifyDataArrived();
    890    if (data->mAudioDemuxer) {
    891      data->mAudioDemuxer->UpdateBuffered();
    892    }
    893    if (data->mVideoDemuxer) {
    894      data->mVideoDemuxer->UpdateBuffered();
    895    }
    896    return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
    897  });
    898 }
    899 
    900 MediaFormatReader::MediaFormatReader(MediaFormatReaderInit& aInit,
    901                                     MediaDataDemuxer* aDemuxer)
    902    : mTaskQueue(
    903          TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
    904                            "MediaFormatReader::mTaskQueue",
    905                            /* aSupportsTailDispatch = */ true)),
    906      mAudio(this, MediaData::Type::AUDIO_DATA,
    907             StaticPrefs::media_audio_max_decode_error()),
    908      mVideo(this, MediaData::Type::VIDEO_DATA,
    909             StaticPrefs::media_video_max_decode_error()),
    910      mWorkingInfoChanged(false, "MediaFormatReader::mWorkingInfoChanged"),
    911      mWatchManager(this, OwnerThread()),
    912      mIsWatchingWorkingInfo(false),
    913      mDemuxer(new DemuxerProxy(aDemuxer)),
    914      mDemuxerInitDone(false),
    915      mPendingNotifyDataArrived(false),
    916      mLastReportedNumDecodedFrames(0),
    917      mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe),
    918      mKnowsCompositor(aInit.mKnowsCompositor),
    919      mInitDone(false),
    920      mTrackDemuxersMayBlock(false),
    921      mSeekScheduled(false),
    922      mVideoFrameContainer(aInit.mVideoFrameContainer),
    923      mCrashHelper(aInit.mCrashHelper),
    924      mDecoderFactory(new DecoderFactory(this)),
    925      mShutdownPromisePool(new ShutdownPromisePool()),
    926      mBuffered(mTaskQueue, TimeIntervals(),
    927                "MediaFormatReader::mBuffered (Canonical)"),
    928      mFrameStats(aInit.mFrameStats),
    929      mMediaDecoderOwnerID(aInit.mMediaDecoderOwnerID),
    930      mTrackingId(std::move(aInit.mTrackingId)),
    931      mReadMetadataStartTime(Nothing()),
    932      mReadMetaDataTime(TimeDuration::Zero()),
    933      mTotalWaitingForVideoDataTime(TimeDuration::Zero()),
    934      mEncryptedCustomIdent(false) {
    935  MOZ_ASSERT(aDemuxer);
    936  MOZ_COUNT_CTOR(MediaFormatReader);
    937  DDLINKCHILD("audio decoder data", "MediaFormatReader::DecoderDataWithPromise",
    938              &mAudio);
    939  DDLINKCHILD("video decoder data", "MediaFormatReader::DecoderDataWithPromise",
    940              &mVideo);
    941  DDLINKCHILD("demuxer", aDemuxer);
    942  mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
    943      mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
    944 }
    945 
    946 MediaFormatReader::~MediaFormatReader() {
    947  MOZ_COUNT_DTOR(MediaFormatReader);
    948  MOZ_ASSERT(mShutdown);
    949 }
    950 
    951 RefPtr<ShutdownPromise> MediaFormatReader::Shutdown() {
    952  MOZ_ASSERT(OnTaskQueue());
    953  LOG("");
    954 
    955  mDemuxerInitRequest.DisconnectIfExists();
    956  mNotifyDataArrivedPromise.DisconnectIfExists();
    957  mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    958  mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    959  mSkipRequest.DisconnectIfExists();
    960  mSetCDMPromise.RejectIfExists(
    961      MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
    962                  "MediaFormatReader is shutting down"),
    963      __func__);
    964 
    965  if (mIsWatchingWorkingInfo) {
    966    mWatchManager.Unwatch(mWorkingInfoChanged,
    967                          &MediaFormatReader::NotifyTrackInfoUpdated);
    968  }
    969  mWatchManager.Shutdown();
    970 
    971  if (mAudio.HasPromise()) {
    972    mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    973  }
    974  if (mVideo.HasPromise()) {
    975    mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    976  }
    977 
    978  if (HasAudio()) {
    979    mAudio.ResetDemuxer();
    980    mAudio.mTrackDemuxer->BreakCycles();
    981    {
    982      MutexAutoLock lock(mAudio.mMutex);
    983      mAudio.mTrackDemuxer = nullptr;
    984    }
    985    mAudio.ResetState();
    986    ShutdownDecoder(TrackInfo::kAudioTrack);
    987  }
    988 
    989  if (HasVideo()) {
    990    mVideo.ResetDemuxer();
    991    mVideo.mTrackDemuxer->BreakCycles();
    992    {
    993      MutexAutoLock lock(mVideo.mMutex);
    994      mVideo.mTrackDemuxer = nullptr;
    995    }
    996    mVideo.ResetState();
    997    ShutdownDecoder(TrackInfo::kVideoTrack);
    998  }
    999 
   1000  mShutdownPromisePool->Track(mDemuxer->Shutdown());
   1001  mDemuxer = nullptr;
   1002 
   1003  mOnTrackWaitingForKeyListener.Disconnect();
   1004 
   1005  mShutdown = true;
   1006  return mShutdownPromisePool->Shutdown()->Then(
   1007      OwnerThread(), __func__, this, &MediaFormatReader::TearDownDecoders,
   1008      &MediaFormatReader::TearDownDecoders);
   1009 }
   1010 
   1011 void MediaFormatReader::ShutdownDecoder(TrackType aTrack) {
   1012  LOGV("%s", TrackTypeToStr(aTrack));
   1013 
   1014  // Shut down the pending decoder if any.
   1015  mDecoderFactory->ShutdownDecoder(aTrack);
   1016 
   1017  auto& decoder = GetDecoderData(aTrack);
   1018  // Flush the decoder if necessary.
   1019  decoder.Flush();
   1020 
   1021  // Shut down the decoder if any.
   1022  decoder.ShutdownDecoder();
   1023 }
   1024 
   1025 void MediaFormatReader::NotifyTrackInfoUpdated() {
   1026  MOZ_ASSERT(OnTaskQueue());
   1027  if (mWorkingInfoChanged) {
   1028    mWorkingInfoChanged = false;
   1029 
   1030    VideoInfo videoInfo;
   1031    AudioInfo audioInfo;
   1032    {
   1033      MutexAutoLock lock(mVideo.mMutex);
   1034      if (HasVideo()) {
   1035        videoInfo = *mVideo.GetWorkingInfo()->GetAsVideoInfo();
   1036      }
   1037    }
   1038    {
   1039      MutexAutoLock lock(mAudio.mMutex);
   1040      if (HasAudio()) {
   1041        audioInfo = *mAudio.GetWorkingInfo()->GetAsAudioInfo();
   1042      }
   1043    }
   1044 
   1045    mTrackInfoUpdatedEvent.Notify(videoInfo, audioInfo);
   1046  }
   1047 }
   1048 
   1049 RefPtr<ShutdownPromise> MediaFormatReader::TearDownDecoders() {
   1050  if (mAudio.mTaskQueue) {
   1051    mAudio.mTaskQueue->BeginShutdown();
   1052    mAudio.mTaskQueue->AwaitShutdownAndIdle();
   1053    mAudio.mTaskQueue = nullptr;
   1054  }
   1055  if (mVideo.mTaskQueue) {
   1056    mVideo.mTaskQueue->BeginShutdown();
   1057    mVideo.mTaskQueue->AwaitShutdownAndIdle();
   1058    mVideo.mTaskQueue = nullptr;
   1059  }
   1060 
   1061  mDecoderFactory = nullptr;
   1062  mVideoFrameContainer = nullptr;
   1063 
   1064  ReleaseResources();
   1065  mBuffered.DisconnectAll();
   1066  return mTaskQueue->BeginShutdown();
   1067 }
   1068 
   1069 nsresult MediaFormatReader::Init() {
   1070  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   1071 
   1072  mAudio.mTaskQueue =
   1073      TaskQueue::Create(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
   1074                        "MFR::mAudio::mTaskQueue");
   1075 
   1076  mVideo.mTaskQueue =
   1077      TaskQueue::Create(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
   1078                        "MFR::mVideo::mTaskQueue");
   1079 
   1080  return NS_OK;
   1081 }
   1082 
   1083 bool MediaFormatReader::ResolveSetCDMPromiseIfDone(TrackType aTrack) {
   1084  // When a CDM proxy is set, MFR would shutdown the existing MediaDataDecoder
   1085  // and would create new one for specific track in the next Update.
   1086  MOZ_ASSERT(OnTaskQueue());
   1087 
   1088  if (mSetCDMPromise.IsEmpty()) {
   1089    return true;
   1090  }
   1091 
   1092  MOZ_ASSERT(mCDMProxy);
   1093  if (mSetCDMForTracks.contains(aTrack)) {
   1094    mSetCDMForTracks -= aTrack;
   1095  }
   1096 
   1097  if (mSetCDMForTracks.isEmpty()) {
   1098    LOGV("%s : Done ", __func__);
   1099    mSetCDMPromise.Resolve(/* aResolveValue = */ true, __func__);
   1100    if (HasAudio()) {
   1101      ScheduleUpdate(TrackInfo::kAudioTrack);
   1102    }
   1103    if (HasVideo()) {
   1104      ScheduleUpdate(TrackInfo::kVideoTrack);
   1105    }
   1106    return true;
   1107  }
   1108  LOGV("%s : %s track is ready.", __func__, TrackTypeToStr(aTrack));
   1109  return false;
   1110 }
   1111 
   1112 void MediaFormatReader::PrepareToSetCDMForTrack(TrackType aTrack) {
   1113  MOZ_ASSERT(OnTaskQueue());
   1114  LOGV("%s : %s", __func__, TrackTypeToStr(aTrack));
   1115 
   1116  mSetCDMForTracks += aTrack;
   1117  if (mCDMProxy) {
   1118    // An old cdm proxy exists, so detaching old cdm proxy by shutting down
   1119    // MediaDataDecoder.
   1120    ShutdownDecoder(aTrack);
   1121  }
   1122  ScheduleUpdate(aTrack);
   1123 }
   1124 
   1125 bool MediaFormatReader::IsDecoderWaitingForCDM(TrackType aTrack) {
   1126  MOZ_ASSERT(OnTaskQueue());
   1127  return GetDecoderData(aTrack).IsEncrypted() &&
   1128         mSetCDMForTracks.contains(aTrack) && !mCDMProxy;
   1129 }
   1130 
   1131 RefPtr<SetCDMPromise> MediaFormatReader::SetCDMProxy(CDMProxy* aProxy) {
   1132  MOZ_ASSERT(OnTaskQueue());
   1133  LOGV("SetCDMProxy (%p)", aProxy);
   1134 
   1135  if (mShutdown) {
   1136    return SetCDMPromise::CreateAndReject(
   1137        MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
   1138                    "MediaFormatReader is shutting down"),
   1139        __func__);
   1140  }
   1141 
   1142  mSetCDMPromise.RejectIfExists(
   1143      MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
   1144                  "Another new CDM proxy is being set."),
   1145      __func__);
   1146 
   1147  // Shutdown all decoders as switching CDM proxy indicates that it's
   1148  // inappropriate for the existing decoders to continue decoding via the old
   1149  // CDM proxy.
   1150  if (HasAudio()) {
   1151    PrepareToSetCDMForTrack(TrackInfo::kAudioTrack);
   1152  }
   1153  if (HasVideo()) {
   1154    PrepareToSetCDMForTrack(TrackInfo::kVideoTrack);
   1155  }
   1156 
   1157  mCDMProxy = aProxy;
   1158 
   1159  if (!mInitDone || mSetCDMForTracks.isEmpty() || !mCDMProxy) {
   1160    // 1) MFR is not initialized yet or
   1161    // 2) Demuxer is initialized without active audio and video or
   1162    // 3) A null cdm proxy is set
   1163    // the promise can be resolved directly.
   1164    mSetCDMForTracks.clear();
   1165    return SetCDMPromise::CreateAndResolve(/* aResolveValue = */ true,
   1166                                           __func__);
   1167  }
   1168 
   1169  RefPtr<SetCDMPromise> p = mSetCDMPromise.Ensure(__func__);
   1170  return p;
   1171 }
   1172 
   1173 bool MediaFormatReader::IsWaitingOnCDMResource() {
   1174  MOZ_ASSERT(OnTaskQueue());
   1175  return IsEncrypted() && !mCDMProxy;
   1176 }
   1177 
   1178 RefPtr<MediaFormatReader::MetadataPromise>
   1179 MediaFormatReader::AsyncReadMetadata() {
   1180  AUTO_PROFILER_LABEL("MediaFormatReader::AsyncReadMetadata", MEDIA_PLAYBACK);
   1181  MOZ_ASSERT(OnTaskQueue());
   1182 
   1183  MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
   1184 
   1185  if (mInitDone) {
   1186    // We are returning from dormant.
   1187    MetadataHolder metadata;
   1188    metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
   1189    return MetadataPromise::CreateAndResolve(std::move(metadata), __func__);
   1190  }
   1191 
   1192  if (!mReadMetadataStartTime) {
   1193    mReadMetadataStartTime = Some(TimeStamp::Now());
   1194  }
   1195 
   1196  RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
   1197 
   1198  mDemuxer->Init()
   1199      ->Then(OwnerThread(), __func__, this,
   1200             &MediaFormatReader::OnDemuxerInitDone,
   1201             &MediaFormatReader::OnDemuxerInitFailed)
   1202      ->Track(mDemuxerInitRequest);
   1203  return p;
   1204 }
   1205 
   1206 void MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult) {
   1207  AUTO_PROFILER_LABEL("MediaFormatReader::OnDemuxerInitDone", MEDIA_PLAYBACK);
   1208  MOZ_ASSERT(OnTaskQueue());
   1209  mDemuxerInitRequest.Complete();
   1210 
   1211  if (NS_FAILED(aResult) && StaticPrefs::media_playback_warnings_as_errors()) {
   1212    mMetadataPromise.Reject(aResult, __func__);
   1213    return;
   1214  }
   1215 
   1216  mDemuxerInitDone = true;
   1217 
   1218  UniquePtr<MetadataTags> tags(MakeUnique<MetadataTags>());
   1219 
   1220  RefPtr<PDMFactory> platform;
   1221  if (!IsWaitingOnCDMResource()) {
   1222    platform = new PDMFactory();
   1223  }
   1224 
   1225  // To decode, we need valid video and a place to put it.
   1226  bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) &&
   1227                     GetImageContainer();
   1228 
   1229  if (videoActive) {
   1230    // We currently only handle the first video track.
   1231    MutexAutoLock lock(mVideo.mMutex);
   1232    mVideo.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
   1233    if (!mVideo.mTrackDemuxer) {
   1234      LOG("No video track demuxer");
   1235      mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
   1236      return;
   1237    }
   1238 
   1239    UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
   1240    videoActive = videoInfo && videoInfo->IsValid();
   1241    if (videoActive) {
   1242      if (platform &&
   1243          platform->SupportsMimeType(videoInfo->mMimeType).isEmpty()) {
   1244        // We have no decoder for this track. Error.
   1245        LOG("No supported decoder for video track (%s)",
   1246            videoInfo->mMimeType.get());
   1247        if (!videoInfo->mMimeType.IsEmpty()) {
   1248          mozilla::glean::media_playback::not_supported_video_per_mime_type
   1249              .Get(videoInfo->mMimeType)
   1250              .Add(1);
   1251        }
   1252        mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
   1253        return;
   1254      }
   1255      mInfo.mVideo = *videoInfo->GetAsVideoInfo();
   1256      mVideo.mWorkingInfo = MakeUnique<VideoInfo>(mInfo.mVideo);
   1257      for (const MetadataTag& tag : videoInfo->mTags) {
   1258        tags->InsertOrUpdate(tag.mKey, tag.mValue);
   1259      }
   1260      mWorkingInfoChanged = true;
   1261      mVideo.mOriginalInfo = std::move(videoInfo);
   1262      mTrackDemuxersMayBlock |= mVideo.mTrackDemuxer->GetSamplesMayBlock();
   1263    } else {
   1264      mVideo.mTrackDemuxer->BreakCycles();
   1265      mVideo.mTrackDemuxer = nullptr;
   1266    }
   1267  }
   1268 
   1269  bool audioActive = !!mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
   1270  if (audioActive) {
   1271    MutexAutoLock lock(mAudio.mMutex);
   1272    mAudio.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
   1273    if (!mAudio.mTrackDemuxer) {
   1274      LOG("No audio track demuxer");
   1275      mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
   1276      return;
   1277    }
   1278 
   1279    UniquePtr<TrackInfo> audioInfo = mAudio.mTrackDemuxer->GetInfo();
   1280    // We actively ignore audio tracks that we know we can't play.
   1281    audioActive = audioInfo && audioInfo->IsValid() &&
   1282                  (!platform ||
   1283                   !platform->SupportsMimeType(audioInfo->mMimeType).isEmpty());
   1284 
   1285    if (audioActive) {
   1286      mInfo.mAudio = *audioInfo->GetAsAudioInfo();
   1287      mAudio.mWorkingInfo = MakeUnique<AudioInfo>(mInfo.mAudio);
   1288      for (const MetadataTag& tag : audioInfo->mTags) {
   1289        tags->InsertOrUpdate(tag.mKey, tag.mValue);
   1290      }
   1291      mWorkingInfoChanged = true;
   1292      mAudio.mOriginalInfo = std::move(audioInfo);
   1293      mTrackDemuxersMayBlock |= mAudio.mTrackDemuxer->GetSamplesMayBlock();
   1294    } else {
   1295      mAudio.mTrackDemuxer->BreakCycles();
   1296      mAudio.mTrackDemuxer = nullptr;
   1297    }
   1298  }
   1299 
   1300  UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
   1301  if (crypto && crypto->IsEncrypted()) {
   1302    // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
   1303    for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
   1304      mOnEncrypted.Notify(crypto->mInitDatas[i].mInitData,
   1305                          crypto->mInitDatas[i].mType);
   1306    }
   1307    mInfo.mCrypto = *crypto;
   1308  }
   1309 
   1310  auto videoDuration = HasVideo() ? mInfo.mVideo.mDuration : TimeUnit::Zero();
   1311  auto audioDuration = HasAudio() ? mInfo.mAudio.mDuration : TimeUnit::Zero();
   1312 
   1313  // If the duration is 0 on both audio and video, it mMetadataDuration is to be
   1314  // Nothing(). Duration will use buffered ranges.
   1315  LOG("videoDuration=%" PRId64 ", audioDuration=%" PRId64,
   1316      videoDuration.ToMicroseconds(), audioDuration.ToMicroseconds());
   1317  if (videoDuration.IsPositive() || audioDuration.IsPositive()) {
   1318    auto duration = std::max(videoDuration, audioDuration);
   1319    LOG("Determine mMetadataDuration=%" PRId64, duration.ToMicroseconds());
   1320    mInfo.mMetadataDuration = Some(duration);
   1321  }
   1322 
   1323  mInfo.mMediaSeekable = mDemuxer->IsSeekable();
   1324  mInfo.mMediaSeekableOnlyInBufferedRanges =
   1325      mDemuxer->IsSeekableOnlyInBufferedRanges();
   1326 
   1327  if (!videoActive && !audioActive) {
   1328    LOG("No active audio or video track");
   1329    mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
   1330    return;
   1331  }
   1332 
   1333  mTags = std::move(tags);
   1334  mInitDone = true;
   1335 
   1336  // Try to get the start time.
   1337  // For MSE case, the start time of each track is assumed to be 0.
   1338  // For others, we must demux the first sample to know the start time for each
   1339  // track.
   1340  if (!mDemuxer->ShouldComputeStartTime()) {
   1341    mAudio.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
   1342    mVideo.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
   1343  } else {
   1344    if (HasAudio()) {
   1345      RequestDemuxSamples(TrackInfo::kAudioTrack);
   1346    }
   1347 
   1348    if (HasVideo()) {
   1349      RequestDemuxSamples(TrackInfo::kVideoTrack);
   1350    }
   1351  }
   1352 
   1353  if (aResult != NS_OK) {
   1354    mOnDecodeWarning.Notify(aResult);
   1355  }
   1356 
   1357  MaybeResolveMetadataPromise();
   1358 }
   1359 
   1360 void MediaFormatReader::MaybeResolveMetadataPromise() {
   1361  MOZ_ASSERT(OnTaskQueue());
   1362 
   1363  if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing()) ||
   1364      (HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
   1365    return;
   1366  }
   1367 
   1368  TimeUnit startTime =
   1369      std::min(mAudio.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()),
   1370               mVideo.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()));
   1371 
   1372  if (!startTime.IsInfinite()) {
   1373    mInfo.mStartTime = startTime;  // mInfo.mStartTime is initialized to 0.
   1374    LOG("Set start time=%s", mInfo.mStartTime.ToString().get());
   1375  }
   1376 
   1377  MetadataHolder metadata;
   1378  metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
   1379  metadata.mTags = mTags->Count() ? std::move(mTags) : nullptr;
   1380 
   1381  // We now have all the informations required to calculate the initial buffered
   1382  // range.
   1383  mHasStartTime = true;
   1384  UpdateBuffered();
   1385 
   1386  mWatchManager.Watch(mWorkingInfoChanged,
   1387                      &MediaFormatReader::NotifyTrackInfoUpdated);
   1388  mIsWatchingWorkingInfo = true;
   1389 
   1390  if (mReadMetadataStartTime) {
   1391    mReadMetaDataTime = TimeStamp::Now() - *mReadMetadataStartTime;
   1392    mReadMetadataStartTime.reset();
   1393  }
   1394 
   1395  mMetadataPromise.Resolve(std::move(metadata), __func__);
   1396 }
   1397 
   1398 bool MediaFormatReader::IsEncrypted() const {
   1399  return (HasAudio() && mAudio.GetCurrentInfo()->mCrypto.IsEncrypted()) ||
   1400         (HasVideo() && mVideo.GetCurrentInfo()->mCrypto.IsEncrypted());
   1401 }
   1402 
   1403 void MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError) {
   1404  mDemuxerInitRequest.Complete();
   1405  mMetadataPromise.Reject(aError, __func__);
   1406 }
   1407 
   1408 void MediaFormatReader::ReadUpdatedMetadata(MediaInfo* aInfo) {
   1409  // Called on the MDSM's TaskQueue.
   1410  {
   1411    MutexAutoLock lock(mVideo.mMutex);
   1412    if (HasVideo()) {
   1413      aInfo->mVideo = *mVideo.GetWorkingInfo()->GetAsVideoInfo();
   1414    }
   1415  }
   1416  {
   1417    MutexAutoLock lock(mAudio.mMutex);
   1418    if (HasAudio()) {
   1419      aInfo->mAudio = *mAudio.GetWorkingInfo()->GetAsAudioInfo();
   1420    }
   1421  }
   1422 }
   1423 
   1424 MediaFormatReader::DecoderData& MediaFormatReader::GetDecoderData(
   1425    TrackType aTrack) {
   1426  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
   1427             aTrack == TrackInfo::kVideoTrack);
   1428  if (aTrack == TrackInfo::kAudioTrack) {
   1429    return mAudio;
   1430  }
   1431  return mVideo;
   1432 }
   1433 
   1434 Maybe<TimeUnit> MediaFormatReader::ShouldSkip(TimeUnit aTimeThreshold,
   1435                                              bool aRequestNextVideoKeyFrame) {
   1436  MOZ_ASSERT(OnTaskQueue());
   1437  MOZ_ASSERT(HasVideo());
   1438 
   1439  if (!StaticPrefs::media_decoder_skip_to_next_key_frame_enabled()) {
   1440    return Nothing();
   1441  }
   1442 
   1443  // Ensure we have no pending seek going as skip-to-keyframe could return out
   1444  // of date information.
   1445  if (mVideo.HasInternalSeekPending()) {
   1446    return Nothing();
   1447  }
   1448 
   1449  TimeUnit nextKeyframe;
   1450  nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
   1451  if (NS_FAILED(rv)) {
   1452    // Only OggTrackDemuxer with video type gets into here.
   1453    // We don't support skip-to-next-frame for this case.
   1454    return Nothing();
   1455  }
   1456 
   1457  const bool isNextKeyframeValid =
   1458      nextKeyframe.ToMicroseconds() >= 0 && !nextKeyframe.IsInfinite();
   1459  // If we request the next keyframe, only return times greater than
   1460  // aTimeThreshold. Otherwise, data will be already behind the threshold and
   1461  // will be eventually discarded somewhere in the media pipeline.
   1462  if (aRequestNextVideoKeyFrame && isNextKeyframeValid &&
   1463      nextKeyframe > aTimeThreshold) {
   1464    return Some(nextKeyframe);
   1465  }
   1466 
   1467  const bool isNextVideoBehindTheThreshold =
   1468      (isNextKeyframeValid && nextKeyframe <= aTimeThreshold) ||
   1469      GetInternalSeekTargetEndTime() < aTimeThreshold;
   1470  return isNextVideoBehindTheThreshold ? Some(aTimeThreshold) : Nothing();
   1471 }
   1472 
   1473 RefPtr<MediaFormatReader::VideoDataPromise> MediaFormatReader::RequestVideoData(
   1474    const TimeUnit& aTimeThreshold, bool aRequestNextVideoKeyFrame) {
   1475  MOZ_ASSERT(OnTaskQueue());
   1476  MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
   1477  // Requesting video can be done independently from audio, even during audio
   1478  // seeking. But it shouldn't happen if we're doing video seek.
   1479  if (!IsAudioOnlySeeking()) {
   1480    MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
   1481                          "No sample requests allowed while seeking");
   1482    MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
   1483                          mVideo.mTimeThreshold.isSome());
   1484    MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
   1485  }
   1486  LOGV("RequestVideoData(%" PRId64 "), requestNextKeyFrame=%d",
   1487       aTimeThreshold.ToMicroseconds(), aRequestNextVideoKeyFrame);
   1488 
   1489  if (!HasVideo()) {
   1490    LOG("called with no video track");
   1491    return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
   1492                                             __func__);
   1493  }
   1494 
   1495  if (IsSeeking()) {
   1496    LOG("called mid-seek. Rejecting.");
   1497    return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
   1498                                             __func__);
   1499  }
   1500 
   1501  if (mShutdown) {
   1502    NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
   1503    return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
   1504                                             __func__);
   1505  }
   1506 
   1507  if (Maybe<TimeUnit> target =
   1508          ShouldSkip(aTimeThreshold, aRequestNextVideoKeyFrame)) {
   1509    PROFILER_MARKER_UNTYPED("RequestVideoData SkipVideoDemuxToNextKeyFrame",
   1510                            MEDIA_PLAYBACK);
   1511    RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
   1512    SkipVideoDemuxToNextKeyFrame(*target);
   1513    return p;
   1514  }
   1515 
   1516  RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
   1517  ScheduleUpdate(TrackInfo::kVideoTrack);
   1518 
   1519  return p;
   1520 }
   1521 
   1522 void MediaFormatReader::OnDemuxFailed(TrackType aTrack,
   1523                                      const MediaResult& aError) {
   1524  AUTO_PROFILER_LABEL("MediaFormatReader::OnDemuxFailed", MEDIA_PLAYBACK);
   1525  MOZ_ASSERT(OnTaskQueue());
   1526  LOG("Failed to demux %s, failure:%s",
   1527      aTrack == TrackType::kVideoTrack ? "video" : "audio",
   1528      aError.ErrorName().get());
   1529  auto& decoder = GetDecoderData(aTrack);
   1530  decoder.mDemuxRequest.Complete();
   1531  switch (aError.Code()) {
   1532    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
   1533      DDLOG(DDLogCategory::Log,
   1534            aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
   1535                                             : "audio_demux_interruption",
   1536            aError);
   1537      if (!decoder.mWaitingForDataStartTime) {
   1538        decoder.RequestDrain();
   1539      }
   1540      NotifyEndOfStream(aTrack);
   1541      break;
   1542    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
   1543      DDLOG(DDLogCategory::Log,
   1544            aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
   1545                                             : "audio_demux_interruption",
   1546            aError);
   1547      if (!decoder.mWaitingForDataStartTime) {
   1548        decoder.RequestDrain();
   1549      } else {
   1550        // mWaitingForDataStartTime was already set.  The decoder is being
   1551        // primed after an internal seek.  A drain has already been performed.
   1552        MOZ_ASSERT(decoder.mTimeThreshold.isSome() ||
   1553                   decoder.mNumSamplesInput == decoder.mNumSamplesOutput);
   1554      }
   1555      NotifyWaitingForData(aTrack);
   1556      break;
   1557    case NS_ERROR_DOM_MEDIA_CANCELED:
   1558      DDLOG(DDLogCategory::Log,
   1559            aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
   1560                                             : "audio_demux_interruption",
   1561            aError);
   1562      if (decoder.HasPromise()) {
   1563        decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   1564      }
   1565      break;
   1566    default:
   1567      DDLOG(DDLogCategory::Log,
   1568            aTrack == TrackType::kVideoTrack ? "video_demux_error"
   1569                                             : "audio_demux_error",
   1570            aError);
   1571      NotifyError(aTrack, aError);
   1572      break;
   1573  }
   1574 }
   1575 
   1576 void MediaFormatReader::DoDemuxVideo() {
   1577  AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxVideo", MEDIA_PLAYBACK);
   1578  using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
   1579 
   1580  DDLOG(DDLogCategory::Log, "video_demuxing", DDNoValue{});
   1581  PerformanceRecorder<PlaybackStage> perfRecorder(
   1582      MediaStage::RequestDemux,
   1583      mVideo.GetCurrentInfo()->GetAsVideoInfo()->mImage.height);
   1584  auto p = mVideo.mTrackDemuxer->GetSamples(1);
   1585 
   1586  RefPtr<MediaFormatReader> self = this;
   1587  if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
   1588    p = p->Then(
   1589        OwnerThread(), __func__,
   1590        [self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
   1591          AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxVideo:Resolved",
   1592                              MEDIA_PLAYBACK);
   1593          DDLOGEX(self.get(), DDLogCategory::Log, "video_first_demuxed",
   1594                  DDNoValue{});
   1595          self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
   1596          return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
   1597        },
   1598        [self](const MediaResult& aError) {
   1599          AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxVideo:Rejected",
   1600                              MEDIA_PLAYBACK);
   1601          DDLOGEX(self.get(), DDLogCategory::Log, "video_first_demuxing_error",
   1602                  aError);
   1603          self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
   1604          return SamplesPromise::CreateAndReject(aError, __func__);
   1605        });
   1606  }
   1607 
   1608  p->Then(
   1609       OwnerThread(), __func__,
   1610       [self, perfRecorder(std::move(perfRecorder))](
   1611           const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples) mutable {
   1612         perfRecorder.Record();
   1613         self->OnVideoDemuxCompleted(aSamples);
   1614       },
   1615       [self](const MediaResult& aError) { self->OnVideoDemuxFailed(aError); })
   1616      ->Track(mVideo.mDemuxRequest);
   1617 }
   1618 
   1619 void MediaFormatReader::OnVideoDemuxCompleted(
   1620    const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples) {
   1621  AUTO_PROFILER_LABEL("MediaFormatReader::OnVideoDemuxCompleted",
   1622                      MEDIA_PLAYBACK);
   1623  LOGV("%zu video samples demuxed (sid:%d)", aSamples->GetSamples().Length(),
   1624       aSamples->GetSamples()[0]->mTrackInfo
   1625           ? aSamples->GetSamples()[0]->mTrackInfo->GetID()
   1626           : 0);
   1627  DDLOG(DDLogCategory::Log, "video_demuxed_samples",
   1628        uint64_t(aSamples->GetSamples().Length()));
   1629  mVideo.mDemuxRequest.Complete();
   1630  MOZ_ASSERT(mVideo.mQueuedSamples.IsEmpty());
   1631  mVideo.mQueuedSamples = aSamples->GetMovableSamples();
   1632  ScheduleUpdate(TrackInfo::kVideoTrack);
   1633 }
   1634 
   1635 RefPtr<MediaFormatReader::AudioDataPromise>
   1636 MediaFormatReader::RequestAudioData() {
   1637  MOZ_ASSERT(OnTaskQueue());
   1638  MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
   1639  // Requesting audio can be done independently from video, even during video
   1640  // seeking. But it shouldn't happen if we're doing audio seek.
   1641  if (!IsVideoOnlySeeking()) {
   1642    MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
   1643                          "No sample requests allowed while seeking");
   1644    MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists() ||
   1645                          mAudio.mTimeThreshold.isSome());
   1646    MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
   1647  }
   1648  LOGV("");
   1649 
   1650  if (!HasAudio()) {
   1651    LOG("called with no audio track");
   1652    return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
   1653                                             __func__);
   1654  }
   1655 
   1656  if (IsSeeking()) {
   1657    LOG("called mid-seek. Rejecting.");
   1658    return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
   1659                                             __func__);
   1660  }
   1661 
   1662  if (mShutdown) {
   1663    NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
   1664    return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
   1665                                             __func__);
   1666  }
   1667 
   1668  RefPtr<AudioDataPromise> p = mAudio.EnsurePromise(__func__);
   1669  ScheduleUpdate(TrackInfo::kAudioTrack);
   1670 
   1671  return p;
   1672 }
   1673 
   1674 void MediaFormatReader::DoDemuxAudio() {
   1675  AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxAudio", MEDIA_PLAYBACK);
   1676  using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
   1677 
   1678  DDLOG(DDLogCategory::Log, "audio_demuxing", DDNoValue{});
   1679  PerformanceRecorder<PlaybackStage> perfRecorder(MediaStage::RequestDemux);
   1680  auto p = mAudio.mTrackDemuxer->GetSamples(1);
   1681 
   1682  RefPtr<MediaFormatReader> self = this;
   1683  if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
   1684    p = p->Then(
   1685        OwnerThread(), __func__,
   1686        [self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
   1687          AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxAudio:Resolved",
   1688                              MEDIA_PLAYBACK);
   1689          DDLOGEX(self.get(), DDLogCategory::Log, "audio_first_demuxed",
   1690                  DDNoValue{});
   1691          self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
   1692          return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
   1693        },
   1694        [self](const MediaResult& aError) {
   1695          AUTO_PROFILER_LABEL("MediaFormatReader::DoDemuxAudio:Rejected",
   1696                              MEDIA_PLAYBACK);
   1697          DDLOGEX(self.get(), DDLogCategory::Log, "audio_first_demuxing_error",
   1698                  aError);
   1699          self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
   1700          return SamplesPromise::CreateAndReject(aError, __func__);
   1701        });
   1702  }
   1703 
   1704  p->Then(
   1705       OwnerThread(), __func__,
   1706       [self, perfRecorder(std::move(perfRecorder))](
   1707           const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples) mutable {
   1708         perfRecorder.Record();
   1709         self->OnAudioDemuxCompleted(aSamples);
   1710       },
   1711       [self](const MediaResult& aError) { self->OnAudioDemuxFailed(aError); })
   1712      ->Track(mAudio.mDemuxRequest);
   1713 }
   1714 
   1715 void MediaFormatReader::OnAudioDemuxCompleted(
   1716    const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples) {
   1717  LOGV("%zu audio samples demuxed (sid:%d)", aSamples->GetSamples().Length(),
   1718       aSamples->GetSamples()[0]->mTrackInfo
   1719           ? aSamples->GetSamples()[0]->mTrackInfo->GetID()
   1720           : 0);
   1721  DDLOG(DDLogCategory::Log, "audio_demuxed_samples",
   1722        uint64_t(aSamples->GetSamples().Length()));
   1723  mAudio.mDemuxRequest.Complete();
   1724  MOZ_ASSERT(mAudio.mQueuedSamples.IsEmpty());
   1725  mAudio.mQueuedSamples = aSamples->GetMovableSamples();
   1726  ScheduleUpdate(TrackInfo::kAudioTrack);
   1727 }
   1728 
   1729 void MediaFormatReader::NotifyNewOutput(
   1730    TrackType aTrack, MediaDataDecoder::DecodedData&& aResults) {
   1731  AUTO_PROFILER_LABEL("MediaFormatReader::NotifyNewOutput", MEDIA_PLAYBACK);
   1732  MOZ_ASSERT(OnTaskQueue());
   1733  auto& decoder = GetDecoderData(aTrack);
   1734  if (aResults.IsEmpty()) {
   1735    DDLOG(DDLogCategory::Log,
   1736          aTrack == TrackInfo::kAudioTrack ? "decoded_audio" : "decoded_video",
   1737          "no output samples");
   1738  } else {
   1739    for (auto&& sample : aResults) {
   1740      if (DecoderDoctorLogger::IsDDLoggingEnabled()) {
   1741        switch (sample->mType) {
   1742          case MediaData::Type::AUDIO_DATA:
   1743            DDLOGPR(DDLogCategory::Log,
   1744                    aTrack == TrackInfo::kAudioTrack ? "decoded_audio"
   1745                                                     : "decoded_got_audio!?",
   1746                    "{\"type\":\"AudioData\", \"offset\":%" PRIi64
   1747                    ", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
   1748                    ", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
   1749                    ", \"channels\":%" PRIu32 ", \"rate\":%" PRIu32
   1750                    ", \"bytes\":%zu}",
   1751                    sample->mOffset, sample->mTime.ToMicroseconds(),
   1752                    sample->mTimecode.ToMicroseconds(),
   1753                    sample->mDuration.ToMicroseconds(),
   1754                    sample->As<AudioData>()->Frames(),
   1755                    sample->As<AudioData>()->mChannels,
   1756                    sample->As<AudioData>()->mRate,
   1757                    sample->As<AudioData>()->Data().Length());
   1758            break;
   1759          case MediaData::Type::VIDEO_DATA:
   1760            DDLOGPR(DDLogCategory::Log,
   1761                    aTrack == TrackInfo::kVideoTrack ? "decoded_video"
   1762                                                     : "decoded_got_video!?",
   1763                    "{\"type\":\"VideoData\", \"offset\":%" PRIi64
   1764                    ", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
   1765                    ", \"duration_us\":%" PRIi64
   1766                    ", \"kf\":%s, \"size\":[%" PRIi32 ",%" PRIi32 "]}",
   1767                    sample->mOffset, sample->mTime.ToMicroseconds(),
   1768                    sample->mTimecode.ToMicroseconds(),
   1769                    sample->mDuration.ToMicroseconds(),
   1770                    sample->mKeyframe ? "true" : "false",
   1771                    sample->As<VideoData>()->mDisplay.width,
   1772                    sample->As<VideoData>()->mDisplay.height);
   1773            break;
   1774          case MediaData::Type::RAW_DATA:
   1775            DDLOGPR(DDLogCategory::Log,
   1776                    aTrack == TrackInfo::kAudioTrack   ? "decoded_audio"
   1777                    : aTrack == TrackInfo::kVideoTrack ? "decoded_video"
   1778                                                       : "decoded_?",
   1779                    "{\"type\":\"RawData\", \"offset\":%" PRIi64
   1780                    " \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
   1781                    ", \"duration_us\":%" PRIi64 ", \"kf\":%s}",
   1782                    sample->mOffset, sample->mTime.ToMicroseconds(),
   1783                    sample->mTimecode.ToMicroseconds(),
   1784                    sample->mDuration.ToMicroseconds(),
   1785                    sample->mKeyframe ? "true" : "false");
   1786            break;
   1787          case MediaData::Type::NULL_DATA:
   1788            DDLOGPR(DDLogCategory::Log,
   1789                    aTrack == TrackInfo::kAudioTrack   ? "decoded_audio"
   1790                    : aTrack == TrackInfo::kVideoTrack ? "decoded_video"
   1791                                                       : "decoded_?",
   1792                    "{\"type\":\"NullData\", \"offset\":%" PRIi64
   1793                    " \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
   1794                    ", \"duration_us\":%" PRIi64 ", \"kf\":%s}",
   1795                    sample->mOffset, sample->mTime.ToMicroseconds(),
   1796                    sample->mTimecode.ToMicroseconds(),
   1797                    sample->mDuration.ToMicroseconds(),
   1798                    sample->mKeyframe ? "true" : "false");
   1799            break;
   1800        }
   1801      }
   1802      LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
   1803           TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(),
   1804           sample->mDuration.ToMicroseconds());
   1805      decoder.mOutput.AppendElement(sample);
   1806      decoder.mNumSamplesOutput++;
   1807      decoder.mNumOfConsecutiveDecodingError = 0;
   1808      decoder.mNumOfConsecutiveRDDOrGPUCrashes = 0;
   1809      if (aTrack == TrackInfo::kAudioTrack) {
   1810        decoder.mNumOfConsecutiveUtilityCrashes = 0;
   1811      }
   1812      if (sample->mType == MediaData::Type::VIDEO_DATA) {
   1813        nsCString dummy;
   1814        bool wasHardwareAccelerated = decoder.mIsHardwareAccelerated;
   1815        decoder.mIsHardwareAccelerated =
   1816            mVideo.mDecoder->IsHardwareAccelerated(dummy);
   1817        if (!decoder.mHasReportedVideoHardwareSupportTelemtry ||
   1818            wasHardwareAccelerated != decoder.mIsHardwareAccelerated) {
   1819          decoder.mHasReportedVideoHardwareSupportTelemtry = true;
   1820          VideoData* videoData = sample->As<VideoData>();
   1821          glean::media::video_hardware_decoding_support
   1822              .Get(decoder.GetCurrentInfo()->mMimeType)
   1823              .Set(!!decoder.mIsHardwareAccelerated);
   1824          static constexpr gfx::IntSize HD_VIDEO_SIZE{1280, 720};
   1825          if (videoData->mDisplay.width >= HD_VIDEO_SIZE.Width() &&
   1826              videoData->mDisplay.height >= HD_VIDEO_SIZE.Height()) {
   1827            glean::media::video_hd_hardware_decoding_support
   1828                .Get(decoder.GetCurrentInfo()->mMimeType)
   1829                .Set(!!decoder.mIsHardwareAccelerated);
   1830          }
   1831        }
   1832        // As the real video decoder creation might be delayed, we want to
   1833        // update the decoder name again, instead of using the wrong name.
   1834        if (decoder.mNumSamplesOutput == 1) {
   1835          decoder.mDescription = mVideo.mDecoder->GetDescriptionName();
   1836          decoder.LoadDecodeProperties();
   1837        }
   1838      }
   1839      decoder.mDecodePerfRecorder->Record(
   1840          sample->mTime.ToMicroseconds(),
   1841          [startTime = sample->mTime.ToMicroseconds(),
   1842           endTime = sample->GetEndTime().ToMicroseconds(),
   1843           flag =
   1844               sample->mType == MediaData::Type::VIDEO_DATA &&
   1845                       decoder.mIsHardwareAccelerated
   1846                   ? MediaInfoFlag::HardwareDecoding
   1847                   : MediaInfoFlag::SoftwareDecoding](PlaybackStage& aStage) {
   1848            aStage.SetStartTimeAndEndTime(startTime, endTime);
   1849            aStage.AddFlag(flag);
   1850          });
   1851    }
   1852  }
   1853  LOG("Done processing new %s samples", TrackTypeToStr(aTrack));
   1854 
   1855  if (!aResults.IsEmpty()) {
   1856    // We have decoded our first frame, we can now starts to skip future errors.
   1857    decoder.mFirstFrameTime.reset();
   1858  }
   1859  ScheduleUpdate(aTrack);
   1860 }
   1861 
   1862 void MediaFormatReader::NotifyError(TrackType aTrack,
   1863                                    const MediaResult& aError) {
   1864  MOZ_ASSERT(OnTaskQueue());
   1865  NS_WARNING(aError.Description().get());
   1866  LOG("%s Decoding error: %s", TrackTypeToStr(aTrack),
   1867      aError.Description().get());
   1868  auto& decoder = GetDecoderData(aTrack);
   1869  decoder.mError = decoder.HasFatalError() ? decoder.mError : Some(aError);
   1870 
   1871  ScheduleUpdate(aTrack);
   1872 }
   1873 
   1874 void MediaFormatReader::NotifyWaitingForData(TrackType aTrack) {
   1875  MOZ_ASSERT(OnTaskQueue());
   1876  LOGV("%s", TrackTypeToStr(aTrack));
   1877  auto& decoder = GetDecoderData(aTrack);
   1878  // mWaitingForDataStartTime may have already been set before draining the
   1879  // decoder.
   1880  if (!decoder.mWaitingForDataStartTime) {
   1881    decoder.mWaitingForDataStartTime.emplace(TimeStamp::Now());
   1882  }
   1883  if (decoder.mTimeThreshold) {
   1884    // An InternalSeek() is in progress, which might be performed while
   1885    // mWaitingForDataStartTime is set, such as when priming the decoder after
   1886    // a drain.  Set mWaiting to indicate that the internal seek cannot make
   1887    // progress.
   1888    decoder.mTimeThreshold.ref().mWaiting = true;
   1889  }
   1890  ScheduleUpdate(aTrack);
   1891 }
   1892 
   1893 void MediaFormatReader::NotifyWaitingForKey(TrackType aTrack) {
   1894  MOZ_ASSERT(OnTaskQueue());
   1895  auto& decoder = GetDecoderData(aTrack);
   1896  mOnWaitingForKey.Notify();
   1897  if (!decoder.mDecodeRequest.Exists()) {
   1898    LOGV("WaitingForKey received while no pending decode. Ignoring");
   1899    return;
   1900  }
   1901  decoder.mWaitingForKey = true;
   1902  ScheduleUpdate(aTrack);
   1903 }
   1904 
   1905 void MediaFormatReader::NotifyEndOfStream(TrackType aTrack) {
   1906  MOZ_ASSERT(OnTaskQueue());
   1907  auto& decoder = GetDecoderData(aTrack);
   1908  decoder.mDemuxEOS = true;
   1909  ScheduleUpdate(aTrack);
   1910 }
   1911 
   1912 bool MediaFormatReader::NeedInput(DecoderData& aDecoder) {
   1913  // The decoder will not be fed a new raw sample until the current decoding
   1914  // requests has completed.
   1915  return (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome()) &&
   1916         !aDecoder.HasPendingDrain() && !aDecoder.HasFatalError() &&
   1917         !aDecoder.mDemuxRequest.Exists() && !aDecoder.mOutput.Length() &&
   1918         !aDecoder.HasInternalSeekPending() &&
   1919         !aDecoder.mDecodeRequest.Exists();
   1920 }
   1921 
   1922 void MediaFormatReader::ScheduleUpdate(TrackType aTrack) {
   1923  MOZ_ASSERT(OnTaskQueue());
   1924  if (mShutdown) {
   1925    return;
   1926  }
   1927  auto& decoder = GetDecoderData(aTrack);
   1928  MOZ_RELEASE_ASSERT(decoder.GetCurrentInfo(),
   1929                     "Can only schedule update when track exists");
   1930 
   1931  if (decoder.mUpdateScheduled) {
   1932    return;
   1933  }
   1934  LOGV("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
   1935  decoder.mUpdateScheduled = true;
   1936  RefPtr<nsIRunnable> task(NewRunnableMethod<TrackType>(
   1937      "MediaFormatReader::Update", this, &MediaFormatReader::Update, aTrack));
   1938  nsresult rv = OwnerThread()->Dispatch(task.forget());
   1939  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
   1940  (void)rv;
   1941 }
   1942 
   1943 bool MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) {
   1944  MOZ_ASSERT(OnTaskQueue());
   1945  auto& decoder = GetDecoderData(aTrack);
   1946 
   1947  if (!decoder.mReceivedNewData) {
   1948    LOGV("!decoder.mReceivedNewData");
   1949    return false;
   1950  }
   1951 
   1952  // We do not want to clear mWaitingForDataStartTime while there are pending
   1953  // demuxing or seeking operations that could affect the value of this flag.
   1954  // This is in order to ensure that we will retry once they complete as we may
   1955  // now have new data that could potentially allow those operations to
   1956  // successfully complete if tried again.
   1957  LOGV("%s", TrackTypeToStr(aTrack));
   1958  if (decoder.mSeekRequest.Exists()) {
   1959    // Nothing more to do until this operation complete.
   1960    return true;
   1961  }
   1962 
   1963  if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
   1964    LOGV("Skipping in progress, nothing more to do");
   1965    return true;
   1966  }
   1967 
   1968  if (decoder.mDemuxRequest.Exists()) {
   1969    LOGV("decoder.mDemuxRequest.Exists()");
   1970    // We may have pending operations to process, so we want to continue
   1971    // after UpdateReceivedNewData returns.
   1972    return false;
   1973  }
   1974 
   1975  if (decoder.HasPendingDrain()) {
   1976    LOGV("decoder.HasPendingDrain()");
   1977    // We do not want to clear mWaitingForDataStartTime or mDemuxEOS while
   1978    // a drain is in progress in order to properly complete the operation.
   1979    // The drain may provide more frames that should be returned before
   1980    // rejection of a MediaData promise.
   1981    return false;
   1982  }
   1983 
   1984  decoder.mReceivedNewData = false;
   1985  if (decoder.mTimeThreshold) {
   1986    decoder.mTimeThreshold.ref().mWaiting = false;
   1987  }
   1988  if (aTrack == TrackType::kVideoTrack && decoder.mWaitingForDataStartTime) {
   1989    mTotalWaitingForVideoDataTime +=
   1990        TimeStamp::Now() - *decoder.mWaitingForDataStartTime;
   1991  }
   1992  decoder.mWaitingForDataStartTime.reset();
   1993 
   1994  if (decoder.HasFatalError()) {
   1995    LOGV("decoder.HasFatalError()");
   1996    return false;
   1997  }
   1998 
   1999  if (!mSeekPromise.IsEmpty() &&
   2000      (!IsVideoOnlySeeking() || aTrack == TrackInfo::kVideoTrack)) {
   2001    MOZ_ASSERT(!decoder.HasPromise());
   2002    MOZ_DIAGNOSTIC_ASSERT(
   2003        (IsVideoOnlySeeking() || !mAudio.mTimeThreshold) &&
   2004            !mVideo.mTimeThreshold,
   2005        "InternalSeek must have been aborted when Seek was first called");
   2006    MOZ_DIAGNOSTIC_ASSERT(
   2007        (IsVideoOnlySeeking() || !mAudio.HasWaitingPromise()) &&
   2008            !mVideo.HasWaitingPromise(),
   2009        "Waiting promises must have been rejected when Seek was first called");
   2010    if (mVideo.mSeekRequest.Exists() ||
   2011        (!IsVideoOnlySeeking() && mAudio.mSeekRequest.Exists())) {
   2012      // Already waiting for a seek to complete. Nothing more to do.
   2013      return true;
   2014    }
   2015    LOG("Attempting Seek");
   2016    ScheduleSeek();
   2017    return true;
   2018  }
   2019  if (decoder.HasInternalSeekPending() || decoder.HasWaitingPromise()) {
   2020    if (decoder.HasInternalSeekPending()) {
   2021      LOG("Attempting Internal Seek");
   2022      InternalSeek(aTrack, decoder.mTimeThreshold.ref());
   2023    }
   2024    if (decoder.HasWaitingPromise() && !decoder.IsWaitingForKey()) {
   2025      MOZ_ASSERT(!decoder.HasPromise());
   2026      LOG("We have new data. Resolving WaitingPromise");
   2027      decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
   2028      MOZ_ASSERT(!decoder.IsWaitingForData());
   2029    }
   2030    return true;
   2031  }
   2032  return false;
   2033 }
   2034 
   2035 void MediaFormatReader::RequestDemuxSamples(TrackType aTrack) {
   2036  MOZ_ASSERT(OnTaskQueue());
   2037  auto& decoder = GetDecoderData(aTrack);
   2038  MOZ_ASSERT(!decoder.mDemuxRequest.Exists());
   2039 
   2040  if (!decoder.mQueuedSamples.IsEmpty()) {
   2041    // No need to demux new samples.
   2042    return;
   2043  }
   2044 
   2045  if (decoder.mDemuxEOS) {
   2046    // Nothing left to demux.
   2047    // We do not want to attempt to demux while in waiting for data mode
   2048    // as it would retrigger an unnecessary drain.
   2049    return;
   2050  }
   2051 
   2052  LOGV("Requesting extra demux %s", TrackTypeToStr(aTrack));
   2053  if (aTrack == TrackInfo::kVideoTrack) {
   2054    DoDemuxVideo();
   2055  } else {
   2056    DoDemuxAudio();
   2057  }
   2058 }
   2059 
   2060 void MediaFormatReader::DecoderData::StartRecordDecodingPerf(
   2061    const TrackType aTrack, const MediaRawData* aSample) {
   2062  if (!mDecodePerfRecorder) {
   2063    mDecodePerfRecorder.reset(new PerformanceRecorderMulti<PlaybackStage>());
   2064  }
   2065  const int32_t height = aTrack == TrackInfo::kVideoTrack
   2066                             ? GetCurrentInfo()->GetAsVideoInfo()->mImage.height
   2067                             : 0;
   2068  MediaInfoFlag flag = MediaInfoFlag::None;
   2069  flag |=
   2070      aSample->mKeyframe ? MediaInfoFlag::KeyFrame : MediaInfoFlag::NonKeyFrame;
   2071  if (aTrack == TrackInfo::kVideoTrack) {
   2072    const nsCString& mimeType = GetCurrentInfo()->mMimeType;
   2073    if (MP4Decoder::IsH264(mimeType)) {
   2074      flag |= MediaInfoFlag::VIDEO_H264;
   2075    } else if (VPXDecoder::IsVPX(mimeType, VPXDecoder::VP8)) {
   2076      flag |= MediaInfoFlag::VIDEO_VP8;
   2077    } else if (VPXDecoder::IsVPX(mimeType, VPXDecoder::VP9)) {
   2078      flag |= MediaInfoFlag::VIDEO_VP9;
   2079    } else if (MP4Decoder::IsHEVC(mimeType)) {
   2080      flag |= MediaInfoFlag::VIDEO_HEVC;
   2081    }
   2082 #ifdef MOZ_AV1
   2083    else if (AOMDecoder::IsAV1(mimeType)) {
   2084      flag |= MediaInfoFlag::VIDEO_AV1;
   2085    }
   2086 #endif
   2087  }
   2088  mDecodePerfRecorder->Start(aSample->mTime.ToMicroseconds(),
   2089                             MediaStage::RequestDecode, height, flag);
   2090 }
   2091 
   2092 void MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
   2093                                             MediaRawData* aSample) {
   2094  MOZ_ASSERT(OnTaskQueue());
   2095  auto& decoder = GetDecoderData(aTrack);
   2096  RefPtr<MediaFormatReader> self = this;
   2097  decoder.mFlushed = false;
   2098  DDLOGPR(DDLogCategory::Log,
   2099          aTrack == TrackInfo::kAudioTrack   ? "decode_audio"
   2100          : aTrack == TrackInfo::kVideoTrack ? "decode_video"
   2101                                             : "decode_?",
   2102          "{\"type\":\"MediaRawData\", \"offset\":%" PRIi64
   2103          ", \"bytes\":%zu, \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
   2104          ", \"duration_us\":%" PRIi64 ",%s%s}",
   2105          aSample->mOffset, aSample->Size(), aSample->mTime.ToMicroseconds(),
   2106          aSample->mTimecode.ToMicroseconds(),
   2107          aSample->mDuration.ToMicroseconds(), aSample->mKeyframe ? " kf" : "",
   2108          aSample->mEOS ? " eos" : "");
   2109 
   2110  decoder.StartRecordDecodingPerf(aTrack, aSample);
   2111  if (aSample->mCrypto.IsEncrypted() &&
   2112      (mMediaEngineId || (mCDMProxy && !!mCDMProxy->AsRemoteCDMChild()))) {
   2113    aSample->mShouldCopyCryptoToRemoteRawData = true;
   2114  }
   2115  decoder.mDecoder->Decode(aSample)
   2116      ->Then(
   2117          mTaskQueue, __func__,
   2118          [self, aTrack,
   2119           &decoder](MediaDataDecoder::DecodedData&& aResults) mutable {
   2120            decoder.mDecodeRequest.Complete();
   2121            self->NotifyNewOutput(aTrack, std::move(aResults));
   2122          },
   2123          [self, aTrack, &decoder](const MediaResult& aError) {
   2124            decoder.mDecodeRequest.Complete();
   2125            self->NotifyError(aTrack, aError);
   2126          })
   2127      ->Track(decoder.mDecodeRequest);
   2128 }
   2129 
   2130 void MediaFormatReader::HandleDemuxedSamples(
   2131    TrackType aTrack, FrameStatistics::AutoNotifyDecoded& aA) {
   2132  MOZ_ASSERT(OnTaskQueue());
   2133 
   2134  auto& decoder = GetDecoderData(aTrack);
   2135 
   2136  if (decoder.mFlushing) {
   2137    LOGV("Decoder operation in progress, let it complete.");
   2138    return;
   2139  }
   2140 
   2141  if (decoder.mQueuedSamples.IsEmpty()) {
   2142    return;
   2143  }
   2144 
   2145  RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
   2146  const RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
   2147 
   2148  if (info && decoder.mLastStreamSourceID != info->GetID()) {
   2149    nsTArray<RefPtr<MediaRawData>> samples;
   2150    if (decoder.mDecoder) {
   2151      bool recyclable =
   2152          StaticPrefs::media_decoder_recycle_enabled() &&
   2153          decoder.mDecoder->SupportDecoderRecycling() &&
   2154          (*info)->mCrypto.mCryptoScheme ==
   2155              decoder.GetCurrentInfo()->mCrypto.mCryptoScheme &&
   2156          (*info)->mMimeType == decoder.GetCurrentInfo()->mMimeType;
   2157      LOG("%s stream id has changed from:%d to:%d, recyclable=%d, "
   2158          "alwaysRecyle=%d",
   2159          TrackTypeToStr(aTrack), decoder.mLastStreamSourceID, info->GetID(),
   2160          recyclable, decoder.mDecoder->ShouldDecoderAlwaysBeRecycled());
   2161      recyclable |= decoder.mDecoder->ShouldDecoderAlwaysBeRecycled();
   2162      if (!recyclable && decoder.mTimeThreshold.isNothing() &&
   2163          (decoder.mNextStreamSourceID.isNothing() ||
   2164           decoder.mNextStreamSourceID.ref() != info->GetID())) {
   2165        LOG("draining decoder for stream id change.");
   2166        decoder.RequestDrain();
   2167        decoder.mNextStreamSourceID = Some(info->GetID());
   2168        ScheduleUpdate(aTrack);
   2169        return;
   2170      }
   2171 
   2172      // If flushing is required, it will clear our array of queued samples.
   2173      // So we may need to make a copy.
   2174      samples = decoder.mQueuedSamples.Clone();
   2175      if (!recyclable) {
   2176        LOG("Decoder does not support recycling, recreate decoder.");
   2177        ShutdownDecoder(aTrack);
   2178        // We're going to be using a new decoder following the change of content
   2179        // We can attempt to use hardware decoding again.
   2180        decoder.mHardwareDecodingDisabled = false;
   2181        decoder.mFirstFrameTime = Some(sample->mTime);
   2182      } else if (decoder.HasWaitingPromise()) {
   2183        decoder.Flush();
   2184      }
   2185    }
   2186 
   2187    nsPrintfCString markerString(
   2188        "%s stream id changed from:%" PRIu32 " to:%" PRIu32,
   2189        TrackTypeToStr(aTrack), decoder.mLastStreamSourceID, info->GetID());
   2190    PROFILER_MARKER_TEXT("StreamID Change", MEDIA_PLAYBACK, {}, markerString);
   2191    LOG("%s", markerString.get());
   2192 
   2193    decoder.mNextStreamSourceID.reset();
   2194    decoder.mLastStreamSourceID = info->GetID();
   2195    decoder.mInfo = info;
   2196    {
   2197      MutexAutoLock lock(decoder.mMutex);
   2198      if (aTrack == TrackInfo::kAudioTrack) {
   2199        decoder.mWorkingInfo = MakeUnique<AudioInfo>(*info->GetAsAudioInfo());
   2200      } else if (aTrack == TrackInfo::kVideoTrack) {
   2201        decoder.mWorkingInfo = MakeUnique<VideoInfo>(*info->GetAsVideoInfo());
   2202      }
   2203      mWorkingInfoChanged = true;
   2204    }
   2205 
   2206    decoder.mMeanRate.Reset();
   2207 
   2208    if (sample->mKeyframe) {
   2209      if (samples.Length()) {
   2210        decoder.mQueuedSamples = std::move(samples);
   2211      }
   2212    } else {
   2213      auto time = TimeInterval(sample->mTime, sample->GetEndTime());
   2214      InternalSeekTarget seekTarget =
   2215          decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
   2216      LOG("Stream change occurred on a non-keyframe. Seeking to:%" PRId64,
   2217          sample->mTime.ToMicroseconds());
   2218      InternalSeek(aTrack, seekTarget);
   2219      return;
   2220    }
   2221  }
   2222 
   2223  // Calculate the average frame rate. The first frame will be accounted
   2224  // for twice.
   2225  decoder.mMeanRate.Update(sample->mDuration);
   2226 
   2227  if (!decoder.mDecoder) {
   2228    // In Clear Lead situation, the `mInfo` could change from unencrypted to
   2229    // encrypted so we need to ensure the CDM proxy is ready before creating a
   2230    // decoder.
   2231    if (decoder.IsEncrypted() &&
   2232        (IsWaitingOnCDMResource() || !ResolveSetCDMPromiseIfDone(aTrack))) {
   2233      return;
   2234    }
   2235    mDecoderFactory->CreateDecoder(aTrack);
   2236    return;
   2237  }
   2238 
   2239  LOGV("%s Input:%" PRId64 " (dts:%" PRId64 " kf:%d)", TrackTypeToStr(aTrack),
   2240       sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(),
   2241       sample->mKeyframe);
   2242  decoder.mNumSamplesInput++;
   2243  decoder.mSizeOfQueue++;
   2244  if (aTrack == TrackInfo::kVideoTrack) {
   2245    aA.mStats.mParsedFrames++;
   2246  }
   2247 
   2248  DecodeDemuxedSamples(aTrack, sample);
   2249 
   2250  decoder.mQueuedSamples.RemoveElementAt(0);
   2251 }
   2252 
   2253 media::TimeUnit MediaFormatReader::GetInternalSeekTargetEndTime() const {
   2254  MOZ_ASSERT(OnTaskQueue());
   2255  return mVideo.mTimeThreshold ? mVideo.mTimeThreshold->EndTime()
   2256                               : TimeUnit::FromInfinity();
   2257 }
   2258 
   2259 void MediaFormatReader::InternalSeek(TrackType aTrack,
   2260                                     const InternalSeekTarget& aTarget) {
   2261  MOZ_ASSERT(OnTaskQueue());
   2262  LOG("%s internal seek to %f", TrackTypeToStr(aTrack),
   2263      aTarget.Time().ToSeconds());
   2264 
   2265  auto& decoder = GetDecoderData(aTrack);
   2266  decoder.Flush();
   2267  decoder.ResetDemuxer();
   2268  decoder.mTimeThreshold = Some(aTarget);
   2269  DDLOG(DDLogCategory::Log, "seeking", DDNoValue{});
   2270  RefPtr<MediaFormatReader> self = this;
   2271  decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
   2272      ->Then(
   2273          OwnerThread(), __func__,
   2274          [self, aTrack](TimeUnit aTime) {
   2275            DDLOGEX(self.get(), DDLogCategory::Log, "seeked", DDNoValue{});
   2276            auto& decoder = self->GetDecoderData(aTrack);
   2277            decoder.mSeekRequest.Complete();
   2278            MOZ_ASSERT(decoder.mTimeThreshold,
   2279                       "Seek promise must be disconnected when "
   2280                       "timethreshold is reset");
   2281            decoder.mTimeThreshold.ref().mHasSeeked = true;
   2282            self->SetVideoDecodeThreshold();
   2283            self->ScheduleUpdate(aTrack);
   2284          },
   2285          [self, aTrack](const MediaResult& aError) {
   2286            auto& decoder = self->GetDecoderData(aTrack);
   2287            decoder.mSeekRequest.Complete();
   2288            switch (aError.Code()) {
   2289              case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
   2290                DDLOGEX(self.get(), DDLogCategory::Log, "seeking_interrupted",
   2291                        aError);
   2292                self->NotifyWaitingForData(aTrack);
   2293                break;
   2294              case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
   2295                DDLOGEX(self.get(), DDLogCategory::Log, "seeking_interrupted",
   2296                        aError);
   2297                decoder.mTimeThreshold.reset();
   2298                self->NotifyEndOfStream(aTrack);
   2299                break;
   2300              case NS_ERROR_DOM_MEDIA_CANCELED:
   2301                DDLOGEX(self.get(), DDLogCategory::Log, "seeking_interrupted",
   2302                        aError);
   2303                decoder.mTimeThreshold.reset();
   2304                break;
   2305              default:
   2306                DDLOGEX(self.get(), DDLogCategory::Log, "seeking_error",
   2307                        aError);
   2308                decoder.mTimeThreshold.reset();
   2309                self->NotifyError(aTrack, aError);
   2310                break;
   2311            }
   2312          })
   2313      ->Track(decoder.mSeekRequest);
   2314 }
   2315 
   2316 void MediaFormatReader::DrainDecoder(TrackType aTrack) {
   2317  AUTO_PROFILER_LABEL("MediaFormatReader::DrainDecoder", MEDIA_PLAYBACK);
   2318  MOZ_ASSERT(OnTaskQueue());
   2319 
   2320  auto& decoder = GetDecoderData(aTrack);
   2321  if (decoder.mDrainState == DrainState::Draining) {
   2322    return;
   2323  }
   2324  if (!decoder.mDecoder ||
   2325      (decoder.mDrainState != DrainState::PartialDrainPending &&
   2326       decoder.mNumSamplesInput == decoder.mNumSamplesOutput)) {
   2327    // No frames to drain.
   2328    LOGV("Draining %s with nothing to drain", TrackTypeToStr(aTrack));
   2329    decoder.mDrainState = DrainState::DrainAborted;
   2330    ScheduleUpdate(aTrack);
   2331    return;
   2332  }
   2333 
   2334  decoder.mDrainState = DrainState::Draining;
   2335 
   2336  DDLOG(DDLogCategory::Log, "draining", DDNoValue{});
   2337  RefPtr<MediaFormatReader> self = this;
   2338  decoder.mDecoder->Drain()
   2339      ->Then(
   2340          mTaskQueue, __func__,
   2341          [this, self, aTrack,
   2342           &decoder](MediaDataDecoder::DecodedData&& aResults) {
   2343            decoder.mDrainRequest.Complete();
   2344            DDLOGEX(self.get(), DDLogCategory::Log, "drained", DDNoValue{});
   2345            if (aResults.IsEmpty()) {
   2346              LOG("DrainDecoder drained");
   2347              decoder.mDrainState = DrainState::DrainCompleted;
   2348            } else {
   2349              NotifyNewOutput(aTrack, std::move(aResults));
   2350              // Let's see if we have any more data available to drain.
   2351              decoder.mDrainState = DrainState::PartialDrainPending;
   2352            }
   2353            ScheduleUpdate(aTrack);
   2354          },
   2355          [self, aTrack, &decoder](const MediaResult& aError) {
   2356            decoder.mDrainRequest.Complete();
   2357            DDLOGEX(self.get(), DDLogCategory::Log, "draining_error", aError);
   2358            self->NotifyError(aTrack, aError);
   2359          })
   2360      ->Track(decoder.mDrainRequest);
   2361  LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
   2362 }
   2363 
   2364 // See https://firefox-source-docs.mozilla.org/media/MediaFormatReader.html
   2365 // for a state diagram overview.
   2366 void MediaFormatReader::Update(TrackType aTrack) {
   2367  AUTO_PROFILER_LABEL("MediaFormatReader::Update", MEDIA_PLAYBACK);
   2368  MOZ_ASSERT(OnTaskQueue());
   2369 
   2370  if (mShutdown) {
   2371    return;
   2372  }
   2373 
   2374  LOGV("Processing update for %s", TrackTypeToStr(aTrack));
   2375 
   2376  bool needOutput = false;
   2377  auto& decoder = GetDecoderData(aTrack);
   2378  decoder.mUpdateScheduled = false;
   2379 
   2380  if (!mInitDone) {
   2381    return;
   2382  }
   2383 
   2384  if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
   2385    LOGV("Skipping in progress, nothing more to do");
   2386    return;
   2387  }
   2388 
   2389  if (UpdateReceivedNewData(aTrack)) {
   2390    LOGV("Nothing more to do");
   2391    return;
   2392  }
   2393 
   2394  if (decoder.mSeekRequest.Exists()) {
   2395    LOGV("Seeking hasn't completed, nothing more to do");
   2396    return;
   2397  }
   2398 
   2399  MOZ_DIAGNOSTIC_ASSERT(
   2400      !decoder.HasInternalSeekPending() ||
   2401          (!decoder.mOutput.Length() && !decoder.mQueuedSamples.Length()),
   2402      "No frames can be demuxed or decoded while an internal seek is pending");
   2403 
   2404  // Record number of frames decoded and parsed. Automatically update the
   2405  // stats counters using the AutoNotifyDecoded stack-based class.
   2406  FrameStatistics::AutoNotifyDecoded a(mFrameStats);
   2407 
   2408  // Drop any frames found prior our internal seek target.
   2409  while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
   2410    RefPtr<MediaData>& output = decoder.mOutput[0];
   2411    InternalSeekTarget target = decoder.mTimeThreshold.ref();
   2412    auto time = output->mTime;
   2413    if (time >= target.Time()) {
   2414      // We have reached our internal seek target.
   2415      decoder.mTimeThreshold.reset();
   2416      // We might have dropped some keyframes.
   2417      if (aTrack == TrackType::kVideoTrack) {
   2418        mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
   2419      }
   2420    }
   2421    if (time < target.Time() || (target.mDropTarget && target.Contains(time))) {
   2422      LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
   2423           TrackTypeToStr(aTrack), output->mTime.ToSeconds(),
   2424           target.Time().ToSeconds(), output->mKeyframe);
   2425      decoder.mOutput.RemoveElementAt(0);
   2426      decoder.mSizeOfQueue -= 1;
   2427    }
   2428  }
   2429 
   2430  while (decoder.mOutput.Length() &&
   2431         decoder.mOutput[0]->mType == MediaData::Type::NULL_DATA) {
   2432    LOGV("Dropping null data. Time: %" PRId64,
   2433         decoder.mOutput[0]->mTime.ToMicroseconds());
   2434    decoder.mOutput.RemoveElementAt(0);
   2435    decoder.mSizeOfQueue -= 1;
   2436  }
   2437 
   2438  if (decoder.HasPromise()) {
   2439    needOutput = true;
   2440    if (decoder.mOutput.Length()) {
   2441      RefPtr<MediaData> output = decoder.mOutput[0];
   2442      decoder.mOutput.RemoveElementAt(0);
   2443      decoder.mSizeOfQueue -= 1;
   2444      decoder.mLastDecodedSampleTime =
   2445          Some(TimeInterval(output->mTime, output->GetEndTime()));
   2446      decoder.mNumSamplesOutputTotal++;
   2447      ReturnOutput(output, aTrack);
   2448      // We have a decoded sample ready to be returned.
   2449      if (aTrack == TrackType::kVideoTrack) {
   2450        uint64_t delta =
   2451            decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
   2452        a.mStats.mDecodedFrames = static_cast<uint32_t>(delta);
   2453        mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
   2454        if (output->mKeyframe) {
   2455          if (mPreviousDecodedKeyframeTime_us <
   2456              output->mTime.ToMicroseconds()) {
   2457            // There is a previous keyframe -> Record inter-keyframe stats.
   2458            uint64_t segment_us = output->mTime.ToMicroseconds() -
   2459                                  mPreviousDecodedKeyframeTime_us;
   2460            a.mStats.mInterKeyframeSum_us += segment_us;
   2461            a.mStats.mInterKeyframeCount += 1;
   2462            if (a.mStats.mInterKeyFrameMax_us < segment_us) {
   2463              a.mStats.mInterKeyFrameMax_us = segment_us;
   2464            }
   2465          }
   2466          mPreviousDecodedKeyframeTime_us = output->mTime.ToMicroseconds();
   2467        }
   2468      }
   2469    } else if (decoder.HasFatalError()) {
   2470      nsCString mimeType = decoder.GetCurrentInfo()->mMimeType;
   2471      if (!mimeType.IsEmpty()) {
   2472        glean::media_playback::DecodeErrorExtra extraData;
   2473        extraData.mimeType = Some(mimeType);
   2474        extraData.errorName = Some(decoder.mError->ErrorName());
   2475        if (mCDMProxy) {
   2476          extraData.keySystem =
   2477              Some(NS_ConvertUTF16toUTF8(mCDMProxy->KeySystem()));
   2478        }
   2479        extraData.decoderName = Some(decoder.mDescription);
   2480        extraData.isHardwareAccelerated = Some(decoder.mIsHardwareAccelerated);
   2481        glean::media_playback::decode_error.Record(Some(extraData));
   2482      }
   2483      LOG("Rejecting %s promise for %s : DECODE_ERROR", TrackTypeToStr(aTrack),
   2484          mimeType.get());
   2485      decoder.RejectPromise(decoder.mError.ref(), __func__);
   2486      return;
   2487    } else if (decoder.HasCompletedDrain()) {
   2488      if (decoder.mDemuxEOS) {
   2489        LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
   2490        decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
   2491      } else if (decoder.mWaitingForDataStartTime) {
   2492        if (decoder.mDrainState == DrainState::DrainCompleted &&
   2493            decoder.mLastDecodedSampleTime && !decoder.mNextStreamSourceID) {
   2494          // We have completed draining the decoder following WaitingForData.
   2495          // Prime the decoder so that it is ready to resume from the
   2496          // last sample decoded.
   2497          LOG("Seeking to last sample time: %" PRId64,
   2498              decoder.mLastDecodedSampleTime.ref().mStart.ToMicroseconds());
   2499          InternalSeek(aTrack, InternalSeekTarget(
   2500                                   decoder.mLastDecodedSampleTime.ref(), true));
   2501        }
   2502        if (!decoder.mReceivedNewData) {
   2503          LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
   2504          decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
   2505        }
   2506      }
   2507 
   2508      decoder.mDrainState = DrainState::None;
   2509 
   2510      // Now that draining has completed, we check if we have received
   2511      // new data again as the result may now be different from the earlier
   2512      // run.
   2513      if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) {
   2514        LOGV("Completed drain: Nothing more to do");
   2515        return;
   2516      }
   2517    } else if (decoder.IsWaitingForData() && !decoder.HasPendingDrain()) {
   2518      // This path is triggered when an internal seek request on mTrackDemuxer
   2519      // returns NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, in which case there is
   2520      // no drain.  No new output samples will be available until more data
   2521      // arrives.
   2522      MOZ_ASSERT(!decoder.mDemuxRequest.Exists());
   2523      MOZ_ASSERT(decoder.mQueuedSamples.IsEmpty());
   2524      // mReceivedNewData would have caused UpdateReceivedNewData() to clear
   2525      // mWaitingForDataStartTime.
   2526      MOZ_ASSERT(!decoder.mReceivedNewData);
   2527      LOG("Rejecting %s promise: WAITING_FOR_DATA during internal seek",
   2528          TrackTypeToStr(aTrack));
   2529      decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
   2530      // Wait until more data arrives.
   2531      return;
   2532    } else if (decoder.mDemuxEOS && !decoder.HasPendingDrain() &&
   2533               decoder.mQueuedSamples.IsEmpty()) {
   2534      // It is possible to transition from WAITING_FOR_DATA directly to EOS
   2535      // state during the internal seek; in which case no draining would occur.
   2536      // There is no more samples left to be decoded and we are already in
   2537      // EOS state. We can immediately reject the data promise.
   2538      LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
   2539      decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
   2540    } else if (decoder.mWaitingForKey) {
   2541      LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
   2542          TrackTypeToStr(aTrack));
   2543      decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
   2544    } else if (IsDecoderWaitingForCDM(aTrack)) {
   2545      // Rejecting the promise could lead to entering buffering state for MDSM,
   2546      // once a qualified(with the same key system and sessions created by the
   2547      // same InitData) new cdm proxy is set, decoding can be resumed.
   2548      LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for CDM",
   2549          TrackTypeToStr(aTrack));
   2550      decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
   2551    }
   2552  }
   2553 
   2554  if (decoder.mDrainState == DrainState::DrainRequested ||
   2555      decoder.mDrainState == DrainState::PartialDrainPending) {
   2556    if (decoder.mOutput.IsEmpty()) {
   2557      DrainDecoder(aTrack);
   2558    }
   2559    return;
   2560  }
   2561 
   2562  if (decoder.mError && !decoder.HasFatalError()) {
   2563    MOZ_RELEASE_ASSERT(!decoder.HasInternalSeekPending(),
   2564                       "No error can occur while an internal seek is pending");
   2565 
   2566    nsCString error;
   2567    bool firstFrameDecodingFailedWithHardware =
   2568        decoder.mFirstFrameTime &&
   2569        decoder.mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR &&
   2570        decoder.mDecoder && decoder.mDecoder->IsHardwareAccelerated(error) &&
   2571        !decoder.mHardwareDecodingDisabled;
   2572    bool needsNewDecoder =
   2573        decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER ||
   2574        firstFrameDecodingFailedWithHardware;
   2575    // Limit number of process restarts after crash
   2576    if ((decoder.mError.ref() ==
   2577             NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR &&
   2578         decoder.mNumOfConsecutiveRDDOrGPUCrashes++ <
   2579             decoder.mMaxConsecutiveRDDOrGPUCrashes) ||
   2580        (decoder.mError.ref() ==
   2581             NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR &&
   2582         decoder.mNumOfConsecutiveUtilityCrashes++ <
   2583             decoder.mMaxConsecutiveUtilityCrashes)) {
   2584      needsNewDecoder = true;
   2585    }
   2586    // For MF CDM crash, it needs to be handled differently. We need to shutdown
   2587    // current decoder and report that error to the state machine in order to
   2588    // let it to determine if playback can keep going or not.
   2589    if (decoder.mError.ref() == NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR) {
   2590      LOG("Error: notify MF CDM crash and shutdown %s decoder",
   2591          TrackTypeToStr(aTrack));
   2592      ShutdownDecoder(aTrack);
   2593      decoder.RejectPromise(decoder.mError.ref(), __func__);
   2594      decoder.mError.reset();
   2595      return;
   2596    }
   2597 #ifdef XP_LINUX
   2598    // We failed to decode on Linux with HW decoder,
   2599    // give it another try without HW decoder.
   2600    if (decoder.mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR &&
   2601        decoder.mDecoder->IsHardwareAccelerated(error)) {
   2602      LOG("Error: %s decode error, disable HW acceleration",
   2603          TrackTypeToStr(aTrack));
   2604      needsNewDecoder = true;
   2605      decoder.mHardwareDecodingDisabled = true;
   2606    }
   2607    // RDD process crashed on Linux, give it another try without HW decoder.
   2608    if (decoder.mError.ref() ==
   2609        NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR) {
   2610      LOG("Error: %s remote decoder crashed, disable HW acceleration",
   2611          TrackTypeToStr(aTrack));
   2612      decoder.mHardwareDecodingDisabled = true;
   2613    }
   2614 #endif
   2615    // We don't want to expose crash error so switch to
   2616    // NS_ERROR_DOM_MEDIA_DECODE_ERR.
   2617    if (decoder.mError.ref() ==
   2618            NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR ||
   2619        decoder.mError.ref() == NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR) {
   2620      decoder.mError = Some(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
   2621                                        RESULT_DETAIL("Unable to decode")));
   2622    }
   2623    if (!needsNewDecoder && ++decoder.mNumOfConsecutiveDecodingError >
   2624                                decoder.mMaxConsecutiveDecodingError) {
   2625      DDLOG(DDLogCategory::Log, "too_many_decode_errors", decoder.mError.ref());
   2626      NotifyError(aTrack, decoder.mError.ref());
   2627      return;
   2628    }
   2629 
   2630    if (firstFrameDecodingFailedWithHardware) {
   2631      decoder.mHardwareDecodingDisabled = true;
   2632    }
   2633    decoder.mError.reset();
   2634 
   2635    LOG("%s decoded error count %d RDD crashes count %d",
   2636        TrackTypeToStr(aTrack), decoder.mNumOfConsecutiveDecodingError,
   2637        decoder.mNumOfConsecutiveRDDOrGPUCrashes);
   2638 
   2639    if (needsNewDecoder) {
   2640      LOG("Error: %s needs a new decoder", TrackTypeToStr(aTrack));
   2641      ShutdownDecoder(aTrack);
   2642    }
   2643    if (decoder.mFirstFrameTime) {
   2644      TimeInterval seekInterval = TimeInterval(decoder.mFirstFrameTime.ref(),
   2645                                               decoder.mFirstFrameTime.ref());
   2646      InternalSeek(aTrack, InternalSeekTarget(seekInterval, false));
   2647      return;
   2648    }
   2649 
   2650    TimeUnit nextKeyframe;
   2651    if (aTrack == TrackType::kVideoTrack &&
   2652        NS_SUCCEEDED(
   2653            decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe)) &&
   2654        !nextKeyframe.IsInfinite()) {
   2655      SkipVideoDemuxToNextKeyFrame(
   2656          decoder.mLastDecodedSampleTime.refOr(TimeInterval()).Length());
   2657    } else if (aTrack == TrackType::kAudioTrack) {
   2658      decoder.Flush();
   2659    } else {
   2660      DDLOG(DDLogCategory::Log, "no_keyframe", NS_ERROR_DOM_MEDIA_FATAL_ERR);
   2661      // We can't recover from this error.
   2662      NotifyError(aTrack, NS_ERROR_DOM_MEDIA_FATAL_ERR);
   2663    }
   2664    return;
   2665  }
   2666 
   2667  bool needInput = NeedInput(decoder);
   2668 
   2669  LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
   2670       " qs=%u decoding:%d flushing:%d desc:%s pending:%u waiting:%d eos:%d "
   2671       "ds:%d sid:%u waitcdm:%d",
   2672       TrackTypeToStr(aTrack), needInput, needOutput, decoder.mNumSamplesInput,
   2673       decoder.mNumSamplesOutput, uint32_t(size_t(decoder.mSizeOfQueue)),
   2674       decoder.mDecodeRequest.Exists(), decoder.mFlushing,
   2675       decoder.mDescription.get(), uint32_t(decoder.mOutput.Length()),
   2676       !!decoder.mWaitingForDataStartTime, decoder.mDemuxEOS,
   2677       int32_t(decoder.mDrainState), decoder.mLastStreamSourceID,
   2678       IsDecoderWaitingForCDM(aTrack));
   2679 
   2680  if (IsWaitingOnCDMResource() || !ResolveSetCDMPromiseIfDone(aTrack)) {
   2681    // If the content is encrypted, MFR won't start to create decoder until
   2682    // CDMProxy is set.
   2683    return;
   2684  }
   2685 
   2686  if ((decoder.IsWaitingForData() &&
   2687       // If mTimeThreshold is set then more samples might need to be demuxed
   2688       // to advance from the random access point to the target, but if its
   2689       // mWaiting is set then demuxing would continue to fail.
   2690       (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) ||
   2691      (decoder.IsWaitingForKey())) {
   2692    // Nothing more we can do at present.
   2693    LOGV("Still waiting for data or key. data(%d)/key(%d)",
   2694         !!decoder.mWaitingForDataStartTime, decoder.mWaitingForKey);
   2695    return;
   2696  }
   2697 
   2698  if (decoder.CancelWaitingForKey()) {
   2699    LOGV("No longer waiting for key. Resolving waiting promise");
   2700    return;
   2701  }
   2702 
   2703  if (!needInput) {
   2704    LOGV("No need for additional input (pending:%u)",
   2705         uint32_t(decoder.mOutput.Length()));
   2706    return;
   2707  }
   2708 
   2709  // Demux samples if we don't have some.
   2710  RequestDemuxSamples(aTrack);
   2711 
   2712  HandleDemuxedSamples(aTrack, a);
   2713  // At least one of RequestDemuxSamples() or HandleDemuxedSamples() was a
   2714  // no-op, so only one operation is in progress at one time.
   2715  MOZ_ASSERT(!decoder.mDemuxRequest.Exists() ||
   2716             !decoder.mDecodeRequest.Exists());
   2717 }
   2718 
   2719 void MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack) {
   2720  AUTO_PROFILER_LABEL("MediaFormatReader::ReturnOutput", MEDIA_PLAYBACK);
   2721  MOZ_ASSERT(GetDecoderData(aTrack).HasPromise());
   2722  MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::Type::NULL_DATA);
   2723  LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]",
   2724      TrackTypeToStr(aTrack), aData->mTime.ToMicroseconds(),
   2725      aData->GetEndTime().ToMicroseconds());
   2726 
   2727  if (aTrack == TrackInfo::kAudioTrack) {
   2728    AudioData* audioData = aData->As<AudioData>();
   2729 
   2730    if (audioData->mChannels != mInfo.mAudio.mChannels ||
   2731        audioData->mRate != mInfo.mAudio.mRate) {
   2732      LOG("change of audio format (rate:%d->%d). "
   2733          "This is an unsupported configuration",
   2734          mInfo.mAudio.mRate, audioData->mRate);
   2735      mInfo.mAudio.mRate = audioData->mRate;
   2736      mInfo.mAudio.mChannels = audioData->mChannels;
   2737      MutexAutoLock lock(mAudio.mMutex);
   2738      mAudio.mWorkingInfo->GetAsAudioInfo()->mRate = audioData->mRate;
   2739      mAudio.mWorkingInfo->GetAsAudioInfo()->mChannels = audioData->mChannels;
   2740      mWorkingInfoChanged = true;
   2741    }
   2742    mAudio.ResolvePromise(audioData, __func__);
   2743  } else if (aTrack == TrackInfo::kVideoTrack) {
   2744    VideoData* videoData = aData->As<VideoData>();
   2745 
   2746    if (videoData->mDisplay != mInfo.mVideo.mDisplay) {
   2747      LOG("change of video display size (%dx%d->%dx%d)",
   2748          mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height,
   2749          videoData->mDisplay.width, videoData->mDisplay.height);
   2750      mInfo.mVideo.mDisplay = videoData->mDisplay;
   2751      MutexAutoLock lock(mVideo.mMutex);
   2752      mVideo.mWorkingInfo->GetAsVideoInfo()->mDisplay = videoData->mDisplay;
   2753      mWorkingInfoChanged = true;
   2754    }
   2755 
   2756    mozilla::gfx::ColorDepth colorDepth = videoData->GetColorDepth();
   2757    if (colorDepth != mInfo.mVideo.mColorDepth) {
   2758      LOG("change of video color depth (enum %u -> enum %u)",
   2759          (unsigned)mInfo.mVideo.mColorDepth, (unsigned)colorDepth);
   2760      mInfo.mVideo.mColorDepth = colorDepth;
   2761      MutexAutoLock lock(mVideo.mMutex);
   2762      mVideo.mWorkingInfo->GetAsVideoInfo()->mColorDepth = colorDepth;
   2763      mWorkingInfoChanged = true;
   2764    }
   2765 
   2766    TimeUnit nextKeyframe;
   2767    if (!mVideo.HasInternalSeekPending() &&
   2768        NS_SUCCEEDED(
   2769            mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) {
   2770      videoData->SetNextKeyFrameTime(nextKeyframe);
   2771    }
   2772 
   2773    mVideo.ResolvePromise(videoData, __func__);
   2774  }
   2775 }
   2776 
   2777 size_t MediaFormatReader::SizeOfVideoQueueInFrames() {
   2778  return SizeOfQueue(TrackInfo::kVideoTrack);
   2779 }
   2780 
   2781 size_t MediaFormatReader::SizeOfAudioQueueInFrames() {
   2782  return SizeOfQueue(TrackInfo::kAudioTrack);
   2783 }
   2784 
   2785 size_t MediaFormatReader::SizeOfQueue(TrackType aTrack) {
   2786  auto& decoder = GetDecoderData(aTrack);
   2787  return decoder.mSizeOfQueue;
   2788 }
   2789 
   2790 RefPtr<MediaFormatReader::WaitForDataPromise> MediaFormatReader::WaitForData(
   2791    MediaData::Type aType) {
   2792  MOZ_ASSERT(OnTaskQueue());
   2793  TrackType trackType = aType == MediaData::Type::VIDEO_DATA
   2794                            ? TrackType::kVideoTrack
   2795                            : TrackType::kAudioTrack;
   2796  auto& decoder = GetDecoderData(trackType);
   2797  if (!decoder.IsWaitingForData() && !decoder.IsWaitingForKey()) {
   2798    // We aren't waiting for anything.
   2799    LOGV("Not waiting. Returning resolved promise");
   2800    return WaitForDataPromise::CreateAndResolve(decoder.mType, __func__);
   2801  }
   2802  RefPtr<WaitForDataPromise> p = decoder.mWaitingPromise.Ensure(__func__);
   2803  ScheduleUpdate(trackType);
   2804  return p;
   2805 }
   2806 
   2807 nsresult MediaFormatReader::ResetDecode(const TrackSet& aTracks) {
   2808  AUTO_PROFILER_LABEL("MediaFormatReader::ResetDecode", MEDIA_PLAYBACK);
   2809  MOZ_ASSERT(OnTaskQueue());
   2810  LOGV("");
   2811 
   2812  mSeekPromise.RejectIfExists(NS_OK, __func__);
   2813  mSkipRequest.DisconnectIfExists();
   2814 
   2815  // Do the same for any data wait promises.
   2816  if (aTracks.contains(TrackInfo::kAudioTrack)) {
   2817    mAudio.mWaitingPromise.RejectIfExists(
   2818        WaitForDataRejectValue(MediaData::Type::AUDIO_DATA,
   2819                               WaitForDataRejectValue::CANCELED),
   2820        __func__);
   2821  }
   2822 
   2823  if (aTracks.contains(TrackInfo::kVideoTrack)) {
   2824    mVideo.mWaitingPromise.RejectIfExists(
   2825        WaitForDataRejectValue(MediaData::Type::VIDEO_DATA,
   2826                               WaitForDataRejectValue::CANCELED),
   2827        __func__);
   2828  }
   2829 
   2830  // Reset miscellaneous seeking state.
   2831  mPendingSeekTime.reset();
   2832 
   2833  if (HasVideo() && aTracks.contains(TrackInfo::kVideoTrack)) {
   2834    mVideo.ResetDemuxer();
   2835    mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
   2836    Reset(TrackInfo::kVideoTrack);
   2837    if (mVideo.HasPromise()) {
   2838      mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   2839    }
   2840  }
   2841 
   2842  if (HasAudio() && aTracks.contains(TrackInfo::kAudioTrack)) {
   2843    mAudio.ResetDemuxer();
   2844    mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
   2845    Reset(TrackInfo::kAudioTrack);
   2846    if (mAudio.HasPromise()) {
   2847      mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   2848    }
   2849  }
   2850 
   2851  return NS_OK;
   2852 }
   2853 
   2854 void MediaFormatReader::Reset(TrackType aTrack) {
   2855  MOZ_ASSERT(OnTaskQueue());
   2856  LOG("Reset(%s) BEGIN", TrackTypeToStr(aTrack));
   2857 
   2858  auto& decoder = GetDecoderData(aTrack);
   2859 
   2860  decoder.ResetState();
   2861  decoder.Flush();
   2862 
   2863  LOG("Reset(%s) END", TrackTypeToStr(aTrack));
   2864 }
   2865 
   2866 void MediaFormatReader::DropDecodedSamples(TrackType aTrack) {
   2867  MOZ_ASSERT(OnTaskQueue());
   2868  auto& decoder = GetDecoderData(aTrack);
   2869  size_t lengthDecodedQueue = decoder.mOutput.Length();
   2870  if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) {
   2871    auto time = decoder.mOutput.LastElement()->mTime;
   2872    if (time >= decoder.mTimeThreshold.ref().Time()) {
   2873      // We would have reached our internal seek target.
   2874      decoder.mTimeThreshold.reset();
   2875    }
   2876  }
   2877  decoder.mOutput.Clear();
   2878  decoder.mSizeOfQueue -= lengthDecodedQueue;
   2879  if (aTrack == TrackInfo::kVideoTrack && mFrameStats) {
   2880    mFrameStats->Accumulate({0, 0, 0, lengthDecodedQueue, 0, 0});
   2881  }
   2882 }
   2883 
   2884 void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold) {
   2885  AUTO_PROFILER_LABEL("MediaFormatReader::SkipVideoDemuxToNextKeyFrame",
   2886                      MEDIA_PLAYBACK);
   2887  MOZ_ASSERT(OnTaskQueue());
   2888  LOG("Skipping up to %" PRId64, aTimeThreshold.ToMicroseconds());
   2889 
   2890  // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late.
   2891  // As such we can drop all already decoded samples and discard all pending
   2892  // samples.
   2893  DropDecodedSamples(TrackInfo::kVideoTrack);
   2894 
   2895  mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
   2896      ->Then(OwnerThread(), __func__, this,
   2897             &MediaFormatReader::OnVideoSkipCompleted,
   2898             &MediaFormatReader::OnVideoSkipFailed)
   2899      ->Track(mSkipRequest);
   2900 }
   2901 
   2902 void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) {
   2903  PROFILER_MARKER_UNTYPED("SkippedVideoDecode", MEDIA_PLAYBACK);
   2904  MOZ_ASSERT(OnTaskQueue());
   2905 
   2906  // Some frames may have been output by the decoder since we initiated the
   2907  // videoskip process and we know they would be late.
   2908  DropDecodedSamples(TrackInfo::kVideoTrack);
   2909  // Report the pending frames as dropped.
   2910  if (mFrameStats) {
   2911    uint32_t droppedDecoderCount = SizeOfVideoQueueInFrames();
   2912    mFrameStats->Accumulate({0, 0, 0, droppedDecoderCount, 0, 0});
   2913  }
   2914 
   2915  // Cancel any pending demux request and pending demuxed samples.
   2916  mVideo.mDemuxRequest.DisconnectIfExists();
   2917  Reset(TrackType::kVideoTrack);
   2918 
   2919  if (mFrameStats) {
   2920    mFrameStats->Accumulate({aSkipped, 0, 0, aSkipped, 0, 0});
   2921  }
   2922 
   2923  mVideo.mNumSamplesSkippedTotal += aSkipped;
   2924 }
   2925 
   2926 void MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped) {
   2927  AUTO_PROFILER_LABEL("MediaFormatReader::OnVideoSkipCompleted",
   2928                      MEDIA_PLAYBACK);
   2929  MOZ_ASSERT(OnTaskQueue());
   2930  LOG("Skipping succeeded, skipped %u frames", aSkipped);
   2931  mSkipRequest.Complete();
   2932 
   2933  DDLOG(DDLogCategory::Log, "video_skipped", DDNoValue());
   2934 
   2935  VideoSkipReset(aSkipped);
   2936 
   2937  ScheduleUpdate(TrackInfo::kVideoTrack);
   2938 }
   2939 
   2940 void MediaFormatReader::OnVideoSkipFailed(
   2941    MediaTrackDemuxer::SkipFailureHolder aFailure) {
   2942  AUTO_PROFILER_LABEL("MediaFormatReader::OnVideoSkipFailed", MEDIA_PLAYBACK);
   2943  MOZ_ASSERT(OnTaskQueue());
   2944  LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
   2945  mSkipRequest.Complete();
   2946 
   2947  switch (aFailure.mFailure.Code()) {
   2948    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
   2949    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
   2950      DDLOG(DDLogCategory::Log, "video_skipping_interruption",
   2951            aFailure.mFailure);
   2952      // Some frames may have been output by the decoder since we initiated the
   2953      // videoskip process and we know they would be late.
   2954      DropDecodedSamples(TrackInfo::kVideoTrack);
   2955      // We can't complete the skip operation, will just service a video frame
   2956      // normally.
   2957      ScheduleUpdate(TrackInfo::kVideoTrack);
   2958      break;
   2959    case NS_ERROR_DOM_MEDIA_CANCELED:
   2960      DDLOG(DDLogCategory::Log, "video_skipping_interruption",
   2961            aFailure.mFailure);
   2962      if (mVideo.HasPromise()) {
   2963        mVideo.RejectPromise(aFailure.mFailure, __func__);
   2964      }
   2965      break;
   2966    default:
   2967      DDLOG(DDLogCategory::Log, "video_skipping_error", aFailure.mFailure);
   2968      NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
   2969      break;
   2970  }
   2971 }
   2972 
   2973 RefPtr<MediaFormatReader::SeekPromise> MediaFormatReader::Seek(
   2974    const SeekTarget& aTarget) {
   2975  AUTO_PROFILER_LABEL("MediaFormatReader::Seek", MEDIA_PLAYBACK);
   2976  MOZ_ASSERT(OnTaskQueue());
   2977 
   2978  LOG("aTarget=(%" PRId64 "), track=%s", aTarget.GetTime().ToMicroseconds(),
   2979      SeekTarget::EnumValueToString(aTarget.GetTrack()));
   2980 
   2981  MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
   2982  MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing());
   2983  // Should reset data request, and no pending internal seek.
   2984  if (aTarget.IsAllTracks()) {
   2985    MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
   2986    MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise());
   2987    MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
   2988    MOZ_DIAGNOSTIC_ASSERT(mAudio.mTimeThreshold.isNothing());
   2989  } else if (aTarget.IsVideoOnly()) {
   2990    MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
   2991    MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
   2992  } else if (aTarget.IsAudioOnly()) {
   2993    MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise());
   2994    MOZ_DIAGNOSTIC_ASSERT(mAudio.mTimeThreshold.isNothing());
   2995  }
   2996 
   2997  if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
   2998    LOG("Seek() END (Unseekable)");
   2999    return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   3000  }
   3001 
   3002  if (mShutdown) {
   3003    return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   3004  }
   3005 
   3006  SetSeekTarget(aTarget);
   3007 
   3008  RefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
   3009 
   3010  ScheduleSeek();
   3011 
   3012  return p;
   3013 }
   3014 
   3015 void MediaFormatReader::SetSeekTarget(const SeekTarget& aTarget) {
   3016  MOZ_ASSERT(OnTaskQueue());
   3017 
   3018  mOriginalSeekTarget = aTarget;
   3019  mFallbackSeekTime = mPendingSeekTime = Some(aTarget.GetTime());
   3020 }
   3021 
   3022 void MediaFormatReader::ScheduleSeek() {
   3023  if (mSeekScheduled) {
   3024    return;
   3025  }
   3026  mSeekScheduled = true;
   3027  nsresult rv = OwnerThread()->Dispatch(NewRunnableMethod(
   3028      "MediaFormatReader::AttemptSeek", this, &MediaFormatReader::AttemptSeek));
   3029  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
   3030  (void)rv;
   3031 }
   3032 
   3033 void MediaFormatReader::AttemptSeek() {
   3034  AUTO_PROFILER_LABEL("MediaFormatReader::AttemptSeek", MEDIA_PLAYBACK);
   3035  MOZ_ASSERT(OnTaskQueue());
   3036 
   3037  mSeekScheduled = false;
   3038 
   3039  if (mPendingSeekTime.isNothing()) {
   3040    LOGV("AttemptSeek, no pending seek time?");
   3041    return;
   3042  }
   3043 
   3044  // Only reset the demuxers targeted by this SeekTarget, to avoid A/V sync
   3045  // issues.
   3046  const bool isSeekingAudio = HasAudio() && !mOriginalSeekTarget.IsVideoOnly();
   3047  const bool isSeekingVideo = HasVideo() && !mOriginalSeekTarget.IsAudioOnly();
   3048  LOG("AttemptSeek, seekingAudio=%d, seekingVideo=%d", isSeekingAudio,
   3049      isSeekingVideo);
   3050  if (isSeekingVideo) {
   3051    mVideo.ResetDemuxer();
   3052    mVideo.ResetState();
   3053  }
   3054  if (isSeekingAudio) {
   3055    mAudio.ResetDemuxer();
   3056    mAudio.ResetState();
   3057  }
   3058 
   3059  // If seeking both tracks, seek the video track, and then the audio track when
   3060  // the video track seek has completed. Otherwise, only seek a specific track.
   3061  if (isSeekingVideo) {
   3062    DoVideoSeek();
   3063  } else if (isSeekingAudio) {
   3064    DoAudioSeek();
   3065  } else {
   3066    MOZ_CRASH();
   3067  }
   3068 }
   3069 
   3070 void MediaFormatReader::OnSeekFailed(TrackType aTrack,
   3071                                     const MediaResult& aError) {
   3072  AUTO_PROFILER_LABEL("MediaFormatReader::OnSeekFailed", MEDIA_PLAYBACK);
   3073  MOZ_ASSERT(OnTaskQueue());
   3074  LOGV("%s failure:%s", TrackTypeToStr(aTrack), aError.ErrorName().get());
   3075  if (aTrack == TrackType::kVideoTrack) {
   3076    mVideo.mSeekRequest.Complete();
   3077  } else {
   3078    mAudio.mSeekRequest.Complete();
   3079  }
   3080 
   3081  if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
   3082    if (HasVideo() && aTrack == TrackType::kAudioTrack &&
   3083        mFallbackSeekTime.isSome() &&
   3084        mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
   3085      // We have failed to seek audio where video seeked to earlier.
   3086      // Attempt to seek instead to the closest point that we know we have in
   3087      // order to limit A/V sync discrepency.
   3088 
   3089      // Ensure we have the most up to date buffered ranges.
   3090      UpdateReceivedNewData(TrackType::kAudioTrack);
   3091      Maybe<TimeUnit> nextSeekTime;
   3092      // Find closest buffered time found after video seeked time.
   3093      for (const auto& timeRange : mAudio.mTimeRanges) {
   3094        if (timeRange.mStart >= mPendingSeekTime.ref()) {
   3095          nextSeekTime.emplace(timeRange.mStart);
   3096          break;
   3097        }
   3098      }
   3099      if (nextSeekTime.isNothing() ||
   3100          nextSeekTime.ref() > mFallbackSeekTime.ref()) {
   3101        nextSeekTime = Some(mFallbackSeekTime.ref());
   3102        LOG("Unable to seek audio to video seek time. A/V sync may be broken");
   3103      } else {
   3104        mFallbackSeekTime.reset();
   3105      }
   3106      mPendingSeekTime = nextSeekTime;
   3107      DoAudioSeek();
   3108      return;
   3109    }
   3110    NotifyWaitingForData(aTrack);
   3111  }
   3112  MOZ_ASSERT(!mVideo.mSeekRequest.Exists() && !mAudio.mSeekRequest.Exists());
   3113  mPendingSeekTime.reset();
   3114 
   3115  auto type = aTrack == TrackType::kAudioTrack ? MediaData::Type::AUDIO_DATA
   3116                                               : MediaData::Type::VIDEO_DATA;
   3117  mSeekPromise.RejectIfExists(SeekRejectValue(type, aError), __func__);
   3118 }
   3119 
   3120 void MediaFormatReader::DoVideoSeek() {
   3121  AUTO_PROFILER_LABEL("MediaFormatReader::DoVideoSeek", MEDIA_PLAYBACK);
   3122  MOZ_ASSERT(mPendingSeekTime.isSome());
   3123  LOGV("Seeking video to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
   3124  MOZ_DIAGNOSTIC_ASSERT(!IsAudioOnlySeeking());
   3125  MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists());
   3126  auto seekTime = mPendingSeekTime.ref();
   3127  mVideo.mTrackDemuxer->Seek(seekTime)
   3128      ->Then(OwnerThread(), __func__, this,
   3129             &MediaFormatReader::OnVideoSeekCompleted,
   3130             &MediaFormatReader::OnVideoSeekFailed)
   3131      ->Track(mVideo.mSeekRequest);
   3132 }
   3133 
   3134 void MediaFormatReader::OnVideoSeekCompleted(TimeUnit aTime) {
   3135  AUTO_PROFILER_LABEL("MediaFormatReader::OnVideoSeekCompleted",
   3136                      MEDIA_PLAYBACK);
   3137  MOZ_ASSERT(OnTaskQueue());
   3138  LOGV("Video seeked to %" PRId64, aTime.ToMicroseconds());
   3139  mVideo.mSeekRequest.Complete();
   3140 
   3141  mVideo.mFirstFrameTime = Some(aTime);
   3142  mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
   3143 
   3144  SetVideoDecodeThreshold();
   3145 
   3146  if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
   3147    MOZ_ASSERT(mPendingSeekTime.isSome());
   3148    if (mOriginalSeekTarget.IsFast()) {
   3149      // We are performing a fast seek. We need to seek audio to where the
   3150      // video seeked to, to ensure proper A/V sync once playback resume.
   3151      mPendingSeekTime = Some(aTime);
   3152    }
   3153    DoAudioSeek();
   3154  } else {
   3155    mPendingSeekTime.reset();
   3156    mSeekPromise.ResolveIfExists(aTime, __func__);
   3157  }
   3158 }
   3159 
   3160 void MediaFormatReader::OnVideoSeekFailed(const MediaResult& aError) {
   3161  AUTO_PROFILER_LABEL("MediaFormatReader::OnVideoSeekFailed", MEDIA_PLAYBACK);
   3162  mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
   3163  OnSeekFailed(TrackType::kVideoTrack, aError);
   3164 }
   3165 
   3166 void MediaFormatReader::SetVideoDecodeThreshold() {
   3167  MOZ_ASSERT(OnTaskQueue());
   3168 
   3169  if (!HasVideo() || !mVideo.mDecoder) {
   3170    return;
   3171  }
   3172 
   3173  if (!mVideo.mTimeThreshold && !IsSeeking()) {
   3174    return;
   3175  }
   3176 
   3177  TimeUnit threshold;
   3178  if (mVideo.mTimeThreshold) {
   3179    // For internalSeek.
   3180    threshold = mVideo.mTimeThreshold.ref().Time();
   3181  } else if (IsSeeking()) {
   3182    // If IsSeeking() is true, then video seek must have completed already.
   3183    TimeUnit keyframe;
   3184    if (NS_FAILED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&keyframe))) {
   3185      return;
   3186    }
   3187 
   3188    // If the key frame is invalid/infinite, it means the target position is
   3189    // closing to end of stream. We don't want to skip any frame at this point.
   3190    threshold = keyframe.IsValid() && !keyframe.IsInfinite()
   3191                    ? mOriginalSeekTarget.GetTime()
   3192                    : TimeUnit::Invalid();
   3193  } else {
   3194    return;
   3195  }
   3196 
   3197  if (threshold.IsValid()) {
   3198    LOG("Set seek threshold to %" PRId64, threshold.ToMicroseconds());
   3199  } else {
   3200    LOG("Resetting seek threshold");
   3201  }
   3202  mVideo.mDecoder->SetSeekThreshold(threshold);
   3203 }
   3204 
   3205 void MediaFormatReader::DoAudioSeek() {
   3206  AUTO_PROFILER_LABEL("MediaFormatReader::DoAudioSeek", MEDIA_PLAYBACK);
   3207  MOZ_ASSERT(mPendingSeekTime.isSome());
   3208  LOGV("Seeking audio to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
   3209  MOZ_DIAGNOSTIC_ASSERT(!IsVideoOnlySeeking());
   3210  MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists());
   3211  auto seekTime = mPendingSeekTime.ref();
   3212  mAudio.mTrackDemuxer->Seek(seekTime)
   3213      ->Then(OwnerThread(), __func__, this,
   3214             &MediaFormatReader::OnAudioSeekCompleted,
   3215             &MediaFormatReader::OnAudioSeekFailed)
   3216      ->Track(mAudio.mSeekRequest);
   3217 }
   3218 
   3219 void MediaFormatReader::OnAudioSeekCompleted(TimeUnit aTime) {
   3220  MOZ_ASSERT(OnTaskQueue());
   3221  AUTO_PROFILER_LABEL("MediaFormatReader::OnAudioSeekCompleted",
   3222                      MEDIA_PLAYBACK);
   3223  LOGV("Audio seeked to %" PRId64, aTime.ToMicroseconds());
   3224  mAudio.mSeekRequest.Complete();
   3225  mAudio.mFirstFrameTime = Some(aTime);
   3226  mPendingSeekTime.reset();
   3227  mSeekPromise.ResolveIfExists(aTime, __func__);
   3228 }
   3229 
   3230 void MediaFormatReader::OnAudioSeekFailed(const MediaResult& aError) {
   3231  AUTO_PROFILER_LABEL("MediaFormatReader::OnAudioSeekFailed", MEDIA_PLAYBACK);
   3232  OnSeekFailed(TrackType::kAudioTrack, aError);
   3233 }
   3234 
   3235 void MediaFormatReader::ReleaseResources() {
   3236  LOGV("");
   3237  if (mShutdown) {
   3238    return;
   3239  }
   3240  ShutdownDecoder(TrackInfo::kAudioTrack);
   3241  ShutdownDecoder(TrackInfo::kVideoTrack);
   3242 }
   3243 
   3244 bool MediaFormatReader::VideoIsHardwareAccelerated() const {
   3245  return mVideo.mIsHardwareAccelerated;
   3246 }
   3247 
   3248 void MediaFormatReader::NotifyTrackDemuxers() {
   3249  MOZ_ASSERT(OnTaskQueue());
   3250 
   3251  LOGV("");
   3252 
   3253  if (!mInitDone) {
   3254    return;
   3255  }
   3256 
   3257  if (HasVideo()) {
   3258    mVideo.mReceivedNewData = true;
   3259    ScheduleUpdate(TrackType::kVideoTrack);
   3260  }
   3261  if (HasAudio()) {
   3262    mAudio.mReceivedNewData = true;
   3263    ScheduleUpdate(TrackType::kAudioTrack);
   3264  }
   3265 }
   3266 
   3267 void MediaFormatReader::NotifyDataArrived() {
   3268  AUTO_PROFILER_LABEL("MediaFormatReader::NotifyDataArrived", MEDIA_PLAYBACK);
   3269  MOZ_ASSERT(OnTaskQueue());
   3270 
   3271  if (mShutdown || !mDemuxer || !mDemuxerInitDone) {
   3272    return;
   3273  }
   3274 
   3275  if (mNotifyDataArrivedPromise.Exists()) {
   3276    // Already one in progress. Set the dirty flag so we can process it later.
   3277    mPendingNotifyDataArrived = true;
   3278    return;
   3279  }
   3280 
   3281  RefPtr<MediaFormatReader> self = this;
   3282  mDemuxer->NotifyDataArrived()
   3283      ->Then(
   3284          OwnerThread(), __func__,
   3285          [self]() {
   3286            AUTO_PROFILER_LABEL("MediaFormatReader::NotifyDataArrived:Resolved",
   3287                                MEDIA_PLAYBACK);
   3288            self->mNotifyDataArrivedPromise.Complete();
   3289            self->UpdateBuffered();
   3290            self->NotifyTrackDemuxers();
   3291            if (self->mPendingNotifyDataArrived) {
   3292              self->mPendingNotifyDataArrived = false;
   3293              self->NotifyDataArrived();
   3294            }
   3295          },
   3296          [self]() { self->mNotifyDataArrivedPromise.Complete(); })
   3297      ->Track(mNotifyDataArrivedPromise);
   3298 }
   3299 
   3300 void MediaFormatReader::UpdateMediaEngineId(uint64_t aMediaEngineId) {
   3301  LOG("Update external media engine Id %" PRIu64, aMediaEngineId);
   3302  mMediaEngineId = Some(aMediaEngineId);
   3303 }
   3304 
   3305 void MediaFormatReader::UpdateBuffered() {
   3306  AUTO_PROFILER_LABEL("MediaFormatReader::UpdateBuffered", MEDIA_PLAYBACK);
   3307  MOZ_ASSERT(OnTaskQueue());
   3308 
   3309  if (mShutdown) {
   3310    return;
   3311  }
   3312 
   3313  if (!mInitDone || !mHasStartTime) {
   3314    mBuffered = TimeIntervals();
   3315    return;
   3316  }
   3317 
   3318  if (HasVideo()) {
   3319    mVideo.mTimeRanges = mVideo.mTrackDemuxer->GetBuffered();
   3320    bool hasLastEnd;
   3321    auto lastEnd = mVideo.mTimeRanges.GetEnd(&hasLastEnd);
   3322    if (hasLastEnd) {
   3323      if (mVideo.mLastTimeRangesEnd &&
   3324          mVideo.mLastTimeRangesEnd.ref() < lastEnd) {
   3325        // New data was added after our previous end, we can clear the EOS flag.
   3326        mVideo.mDemuxEOS = false;
   3327        ScheduleUpdate(TrackInfo::kVideoTrack);
   3328      }
   3329      mVideo.mLastTimeRangesEnd = Some(lastEnd);
   3330    }
   3331  }
   3332  if (HasAudio()) {
   3333    mAudio.mTimeRanges = mAudio.mTrackDemuxer->GetBuffered();
   3334    bool hasLastEnd;
   3335    auto lastEnd = mAudio.mTimeRanges.GetEnd(&hasLastEnd);
   3336    if (hasLastEnd) {
   3337      if (mAudio.mLastTimeRangesEnd &&
   3338          mAudio.mLastTimeRangesEnd.ref() < lastEnd) {
   3339        // New data was added after our previous end, we can clear the EOS flag.
   3340        mAudio.mDemuxEOS = false;
   3341        ScheduleUpdate(TrackInfo::kAudioTrack);
   3342      }
   3343      mAudio.mLastTimeRangesEnd = Some(lastEnd);
   3344    }
   3345  }
   3346 
   3347  media::TimeIntervals intervals;
   3348  if (HasAudio() && HasVideo()) {
   3349    intervals = media::Intersection(mVideo.mTimeRanges, mAudio.mTimeRanges);
   3350  } else if (HasAudio()) {
   3351    intervals = mAudio.mTimeRanges;
   3352  } else if (HasVideo()) {
   3353    intervals = mVideo.mTimeRanges;
   3354  }
   3355 
   3356  if (intervals.IsEmpty() || intervals.GetStart() == TimeUnit::Zero()) {
   3357    // IntervalSet already starts at 0 or is empty, nothing to shift.
   3358    mBuffered = intervals;
   3359  } else {
   3360    LOG("Subtract start time for buffered range, startTime=%" PRId64,
   3361        mInfo.mStartTime.ToMicroseconds());
   3362    mBuffered = intervals.Shift(TimeUnit::Zero() - mInfo.mStartTime);
   3363  }
   3364 }
   3365 
   3366 layers::ImageContainer* MediaFormatReader::GetImageContainer() {
   3367  return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer()
   3368                              : nullptr;
   3369 }
   3370 
   3371 RefPtr<GenericPromise> MediaFormatReader::RequestDebugInfo(
   3372    dom::MediaFormatReaderDebugInfo& aInfo) {
   3373  if (!OnTaskQueue()) {
   3374    // Run the request on the task queue if it's not already.
   3375    return InvokeAsync(mTaskQueue, __func__,
   3376                       [this, self = RefPtr{this}, &aInfo] {
   3377                         return RequestDebugInfo(aInfo);
   3378                       });
   3379  }
   3380  GetDebugInfo(aInfo);
   3381  return GenericPromise::CreateAndResolve(true, __func__);
   3382 }
   3383 
   3384 void MediaFormatReader::GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo) {
   3385  MOZ_ASSERT(OnTaskQueue(),
   3386             "Don't call this off the task queue, it's going to touch a lot of "
   3387             "data members");
   3388  nsCString result;
   3389  nsAutoCString audioDecoderName("unavailable");
   3390  nsAutoCString videoDecoderName = audioDecoderName;
   3391  nsAutoCString audioType("none");
   3392  nsAutoCString videoType("none");
   3393 
   3394  AudioInfo audioInfo;
   3395  if (HasAudio()) {
   3396    audioInfo = *mAudio.GetWorkingInfo()->GetAsAudioInfo();
   3397    audioDecoderName = mAudio.mDecoder ? mAudio.mDecoder->GetDescriptionName()
   3398                                       : mAudio.mDescription;
   3399    audioType = audioInfo.mMimeType;
   3400    aInfo.mAudioState.mNeedInput = NeedInput(mAudio);
   3401    aInfo.mAudioState.mHasPromise = mAudio.HasPromise();
   3402    aInfo.mAudioState.mWaitingPromise = !mAudio.mWaitingPromise.IsEmpty();
   3403    aInfo.mAudioState.mHasDemuxRequest = mAudio.mDemuxRequest.Exists();
   3404    aInfo.mAudioState.mDemuxQueueSize = mAudio.mQueuedSamples.Length();
   3405    aInfo.mAudioState.mHasDecoder = mAudio.mDecodeRequest.Exists();
   3406    aInfo.mAudioState.mTimeTreshold =
   3407        mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().Time().ToSeconds()
   3408                              : -1.0;
   3409    aInfo.mAudioState.mTimeTresholdHasSeeked =
   3410        mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().mHasSeeked : false;
   3411    aInfo.mAudioState.mNumSamplesInput = mAudio.mNumSamplesInput;
   3412    aInfo.mAudioState.mNumSamplesOutput = mAudio.mNumSamplesOutput;
   3413    aInfo.mAudioState.mQueueSize = mAudio.mSizeOfQueue;
   3414    aInfo.mAudioState.mPending = mAudio.mOutput.Length();
   3415    aInfo.mAudioState.mWaitingForData = !!mAudio.mWaitingForDataStartTime;
   3416    aInfo.mAudioState.mDemuxEOS = mAudio.mDemuxEOS;
   3417    aInfo.mAudioState.mDrainState = int32_t(mAudio.mDrainState);
   3418    aInfo.mAudioState.mWaitingForKey = mAudio.mWaitingForKey;
   3419    aInfo.mAudioState.mLastStreamSourceID = mAudio.mLastStreamSourceID;
   3420  }
   3421 
   3422  CopyUTF8toUTF16(audioDecoderName, aInfo.mAudioDecoderName);
   3423  CopyUTF8toUTF16(audioType, aInfo.mAudioType);
   3424  aInfo.mAudioChannels = audioInfo.mChannels;
   3425  aInfo.mAudioRate = audioInfo.mRate;
   3426  aInfo.mAudioFramesDecoded = mAudio.mNumSamplesOutputTotal;
   3427 
   3428  VideoInfo videoInfo;
   3429  if (HasVideo()) {
   3430    videoInfo = *mVideo.GetWorkingInfo()->GetAsVideoInfo();
   3431    videoDecoderName = mVideo.mDecoder ? mVideo.mDecoder->GetDescriptionName()
   3432                                       : mVideo.mDescription;
   3433    videoType = videoInfo.mMimeType;
   3434    aInfo.mVideoState.mNeedInput = NeedInput(mVideo);
   3435    aInfo.mVideoState.mHasPromise = mVideo.HasPromise();
   3436    aInfo.mVideoState.mWaitingPromise = !mVideo.mWaitingPromise.IsEmpty();
   3437    aInfo.mVideoState.mHasDemuxRequest = mVideo.mDemuxRequest.Exists();
   3438    aInfo.mVideoState.mDemuxQueueSize = mVideo.mQueuedSamples.Length();
   3439    aInfo.mVideoState.mHasDecoder = mVideo.mDecodeRequest.Exists();
   3440    aInfo.mVideoState.mTimeTreshold =
   3441        mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().Time().ToSeconds()
   3442                              : -1.0;
   3443    aInfo.mVideoState.mTimeTresholdHasSeeked =
   3444        mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().mHasSeeked : false;
   3445    aInfo.mVideoState.mNumSamplesInput = mVideo.mNumSamplesInput;
   3446    aInfo.mVideoState.mNumSamplesOutput = mVideo.mNumSamplesOutput;
   3447    aInfo.mVideoState.mQueueSize = mVideo.mSizeOfQueue;
   3448    aInfo.mVideoState.mPending = mVideo.mOutput.Length();
   3449    aInfo.mVideoState.mWaitingForData = !!mVideo.mWaitingForDataStartTime;
   3450    aInfo.mVideoState.mDemuxEOS = mVideo.mDemuxEOS;
   3451    aInfo.mVideoState.mDrainState = int32_t(mVideo.mDrainState);
   3452    aInfo.mVideoState.mWaitingForKey = mVideo.mWaitingForKey;
   3453    aInfo.mVideoState.mLastStreamSourceID = mVideo.mLastStreamSourceID;
   3454    aInfo.mTotalReadMetadataTimeMs = mReadMetaDataTime.ToMilliseconds();
   3455    aInfo.mTotalWaitingForVideoDataTimeMs =
   3456        mTotalWaitingForVideoDataTime.ToMilliseconds();
   3457  }
   3458 
   3459  CopyUTF8toUTF16(videoDecoderName, aInfo.mVideoDecoderName);
   3460  CopyUTF8toUTF16(videoType, aInfo.mVideoType);
   3461  aInfo.mVideoWidth =
   3462      videoInfo.mDisplay.width < 0 ? 0 : videoInfo.mDisplay.width;
   3463  aInfo.mVideoHeight =
   3464      videoInfo.mDisplay.height < 0 ? 0 : videoInfo.mDisplay.height;
   3465  aInfo.mVideoRate = mVideo.mMeanRate.Mean();
   3466  aInfo.mVideoHardwareAccelerated = VideoIsHardwareAccelerated();
   3467  aInfo.mVideoNumSamplesOutputTotal = mVideo.mNumSamplesOutputTotal;
   3468  aInfo.mVideoNumSamplesSkippedTotal = mVideo.mNumSamplesSkippedTotal;
   3469 
   3470  // Looking at dropped frames
   3471  FrameStatisticsData stats = mFrameStats->GetFrameStatisticsData();
   3472  aInfo.mFrameStats.mDroppedDecodedFrames = stats.mDroppedDecodedFrames;
   3473  aInfo.mFrameStats.mDroppedSinkFrames = stats.mDroppedSinkFrames;
   3474  aInfo.mFrameStats.mDroppedCompositorFrames = stats.mDroppedCompositorFrames;
   3475 }
   3476 
   3477 void MediaFormatReader::SetVideoNullDecode(bool aIsNullDecode) {
   3478  MOZ_ASSERT(OnTaskQueue());
   3479  return SetNullDecode(TrackType::kVideoTrack, aIsNullDecode);
   3480 }
   3481 
   3482 void MediaFormatReader::UpdateCompositor(
   3483    already_AddRefed<layers::KnowsCompositor> aCompositor) {
   3484  MOZ_ASSERT(OnTaskQueue());
   3485  mKnowsCompositor = aCompositor;
   3486 }
   3487 
   3488 void MediaFormatReader::SetNullDecode(TrackType aTrack, bool aIsNullDecode) {
   3489  MOZ_ASSERT(OnTaskQueue());
   3490 
   3491  auto& decoder = GetDecoderData(aTrack);
   3492  if (decoder.mIsNullDecode == aIsNullDecode) {
   3493    return;
   3494  }
   3495 
   3496  LOG("%s, decoder.mIsNullDecode = %d => aIsNullDecode = %d",
   3497      TrackTypeToStr(aTrack), decoder.mIsNullDecode, aIsNullDecode);
   3498 
   3499  decoder.mIsNullDecode = aIsNullDecode;
   3500  ShutdownDecoder(aTrack);
   3501 }
   3502 
   3503 void MediaFormatReader::OnFirstDemuxCompleted(
   3504    TrackInfo::TrackType aType,
   3505    const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples) {
   3506  AUTO_PROFILER_LABEL("MediaFormatReader::OnFirstDemuxCompleted",
   3507                      MEDIA_PLAYBACK);
   3508  MOZ_ASSERT(OnTaskQueue());
   3509 
   3510  if (mShutdown) {
   3511    return;
   3512  }
   3513 
   3514  auto& decoder = GetDecoderData(aType);
   3515  MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
   3516  decoder.mFirstDemuxedSampleTime.emplace(aSamples->GetSamples()[0]->mTime);
   3517  MaybeResolveMetadataPromise();
   3518 }
   3519 
   3520 void MediaFormatReader::OnFirstDemuxFailed(TrackInfo::TrackType aType,
   3521                                           const MediaResult& aError) {
   3522  MOZ_ASSERT(OnTaskQueue());
   3523 
   3524  if (mShutdown) {
   3525    return;
   3526  }
   3527 
   3528  auto& decoder = GetDecoderData(aType);
   3529  MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
   3530  decoder.mFirstDemuxedSampleTime.emplace(TimeUnit::FromInfinity());
   3531  MaybeResolveMetadataPromise();
   3532 }
   3533 
   3534 void MediaFormatReader::SetEncryptedCustomIdent() {
   3535  LOG("Set mEncryptedCustomIdent");
   3536  mEncryptedCustomIdent = true;
   3537 }
   3538 
   3539 void MediaFormatReader::VideoDecodeProperties::Load(
   3540    RefPtr<MediaDataDecoder>& aDecoder) {
   3541  using V = MediaDataDecoder::PropertyValue;
   3542  aDecoder
   3543      ->GetDecodeProperty(MediaDataDecoder::PropertyName::MaxNumVideoBuffers)
   3544      .apply([this](const V& v) { mMaxQueueSize = Some(v.as<uint32_t>()); });
   3545  aDecoder
   3546      ->GetDecodeProperty(MediaDataDecoder::PropertyName::MinNumVideoBuffers)
   3547      .apply([this](const V& v) { mMinQueueSize = Some(v.as<uint32_t>()); });
   3548  aDecoder
   3549      ->GetDecodeProperty(MediaDataDecoder::PropertyName::MaxNumCurrentImages)
   3550      .apply([this](const V& v) {
   3551        mSendToCompositorSize = Some(v.as<uint32_t>());
   3552      });
   3553 }
   3554 
   3555 }  // namespace mozilla
   3556 
   3557 #undef NS_DispatchToMainThread
   3558 #undef LOGV
   3559 #undef LOG