tor-browser

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

DecoderTemplate.cpp (34941B)


      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 "DecoderTemplate.h"
      8 
      9 #include <atomic>
     10 #include <utility>
     11 
     12 #include "DecoderTypes.h"
     13 #include "MediaInfo.h"
     14 #include "mozilla/ScopeExit.h"
     15 #include "mozilla/Try.h"
     16 #include "mozilla/dom/DOMException.h"
     17 #include "mozilla/dom/Event.h"
     18 #include "mozilla/dom/Promise.h"
     19 #include "mozilla/dom/VideoDecoderBinding.h"
     20 #include "mozilla/dom/VideoFrame.h"
     21 #include "mozilla/dom/WorkerCommon.h"
     22 #include "nsGkAtoms.h"
     23 #include "nsString.h"
     24 #include "nsThreadUtils.h"
     25 
     26 mozilla::LazyLogModule gWebCodecsLog("WebCodecs");
     27 
     28 namespace mozilla::dom {
     29 
     30 #ifdef LOG_INTERNAL
     31 #  undef LOG_INTERNAL
     32 #endif  // LOG_INTERNAL
     33 #define LOG_INTERNAL(level, msg, ...) \
     34  MOZ_LOG(gWebCodecsLog, LogLevel::level, (msg, ##__VA_ARGS__))
     35 
     36 #ifdef LOG
     37 #  undef LOG
     38 #endif  // LOG
     39 #define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)
     40 
     41 #ifdef LOGW
     42 #  undef LOGW
     43 #endif  // LOGW
     44 #define LOGW(msg, ...) LOG_INTERNAL(Warning, msg, ##__VA_ARGS__)
     45 
     46 #ifdef LOGE
     47 #  undef LOGE
     48 #endif  // LOGE
     49 #define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__)
     50 
     51 #ifdef LOGV
     52 #  undef LOGV
     53 #endif  // LOGV
     54 #define LOGV(msg, ...) LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__)
     55 
     56 #define AUTO_DECODER_MARKER(var, postfix) \
     57  AutoWebCodecsMarker var(DecoderType::Name.get(), postfix);
     58 
     59 /*
     60 * Below are ControlMessage classes implementations
     61 */
     62 
     63 template <typename DecoderType>
     64 DecoderTemplate<DecoderType>::ConfigureMessage::ConfigureMessage(
     65    WebCodecsId aConfigId, already_AddRefed<ConfigTypeInternal> aConfig)
     66    : ControlMessage(aConfigId),
     67      mConfig(aConfig),
     68      mCodec(NS_ConvertUTF16toUTF8(mConfig->mCodec)) {}
     69 
     70 template <typename DecoderType>
     71 nsCString DecoderTemplate<DecoderType>::ConfigureMessage::ToString() const {
     72  return nsPrintfCString("configure #%zu (%s)", ControlMessage::mConfigId,
     73                         mCodec.get());
     74 }
     75 
     76 /* static */
     77 template <typename DecoderType>
     78 typename DecoderTemplate<DecoderType>::ConfigureMessage*
     79 DecoderTemplate<DecoderType>::ConfigureMessage::Create(
     80    already_AddRefed<ConfigTypeInternal> aConfig) {
     81  // This needs to be atomic since this can run on the main thread or worker
     82  // thread.
     83  static std::atomic<WebCodecsId> sNextId = 0;
     84  return new ConfigureMessage(++sNextId, std::move(aConfig));
     85 }
     86 
     87 template <typename DecoderType>
     88 DecoderTemplate<DecoderType>::DecodeMessage::DecodeMessage(
     89    WebCodecsId aSeqId, WebCodecsId aConfigId,
     90    UniquePtr<InputTypeInternal>&& aData)
     91    : ControlMessage(aConfigId), mSeqId(aSeqId), mData(std::move(aData)) {}
     92 
     93 template <typename DecoderType>
     94 nsCString DecoderTemplate<DecoderType>::DecodeMessage::ToString() const {
     95  return nsPrintfCString("decode #%zu (config #%zu)", mSeqId,
     96                         ControlMessage::mConfigId);
     97 }
     98 
     99 static int64_t GenerateUniqueId() {
    100  // This needs to be atomic since this can run on the main thread or worker
    101  // thread.
    102  static std::atomic<int64_t> sNextId = 0;
    103  return ++sNextId;
    104 }
    105 
    106 template <typename DecoderType>
    107 DecoderTemplate<DecoderType>::FlushMessage::FlushMessage(WebCodecsId aSeqId,
    108                                                         WebCodecsId aConfigId)
    109    : ControlMessage(aConfigId),
    110      mSeqId(aSeqId),
    111      mUniqueId(GenerateUniqueId()) {}
    112 
    113 template <typename DecoderType>
    114 nsCString DecoderTemplate<DecoderType>::FlushMessage::ToString() const {
    115  return nsPrintfCString("flush #%zu (config #%zu)", mSeqId,
    116                         ControlMessage::mConfigId);
    117 }
    118 
    119 /*
    120 * Below are DecoderTemplate implementation
    121 */
    122 
    123 template <typename DecoderType>
    124 DecoderTemplate<DecoderType>::DecoderTemplate(
    125    nsIGlobalObject* aGlobalObject,
    126    RefPtr<WebCodecsErrorCallback>&& aErrorCallback,
    127    RefPtr<OutputCallbackType>&& aOutputCallback)
    128    : DOMEventTargetHelper(aGlobalObject),
    129      mErrorCallback(std::move(aErrorCallback)),
    130      mOutputCallback(std::move(aOutputCallback)),
    131      mState(CodecState::Unconfigured),
    132      mKeyChunkRequired(true),
    133      mMessageQueueBlocked(false),
    134      mDecodeQueueSize(0),
    135      mDequeueEventScheduled(false),
    136      mLatestConfigureId(0),
    137      mDecodeCounter(0),
    138      mFlushCounter(0) {}
    139 
    140 template <typename DecoderType>
    141 void DecoderTemplate<DecoderType>::Configure(const ConfigType& aConfig,
    142                                             ErrorResult& aRv) {
    143  AssertIsOnOwningThread();
    144 
    145  LOG("%s %p, Configure: codec %s", DecoderType::Name.get(), this,
    146      NS_ConvertUTF16toUTF8(aConfig.mCodec).get());
    147 
    148  nsCString errorMessage;
    149  if (!DecoderType::Validate(aConfig, errorMessage)) {
    150    LOG("Configure: Validate error: %s", errorMessage.get());
    151    aRv.ThrowTypeError(errorMessage);
    152    return;
    153  }
    154 
    155  if (mState == CodecState::Closed) {
    156    LOG("Configure: CodecState::Closed, rejecting with InvalidState");
    157    aRv.ThrowInvalidStateError("The codec is no longer usable");
    158    return;
    159  }
    160 
    161  // Clone a ConfigType as the active decoder config.
    162  RefPtr<ConfigTypeInternal> config =
    163      DecoderType::CreateConfigInternal(aConfig);
    164  if (!config) {
    165    aRv.Throw(NS_ERROR_UNEXPECTED);  // Invalid description data.
    166    return;
    167  }
    168 
    169  // Audio encoders are all software, no need to do anything.
    170  // This is incomplete and will be implemented fully in bug 1967793
    171  if constexpr (std::is_same_v<ConfigType, VideoDecoderConfig>) {
    172    ApplyResistFingerprintingIfNeeded(config, GetOwnerGlobal());
    173  }
    174 
    175  mState = CodecState::Configured;
    176  mKeyChunkRequired = true;
    177  mDecodeCounter = 0;
    178  mFlushCounter = 0;
    179 
    180  mControlMessageQueue.emplace(
    181      UniquePtr<ControlMessage>(ConfigureMessage::Create(config.forget())));
    182  mLatestConfigureId = mControlMessageQueue.back()->mConfigId;
    183  LOG("%s %p enqueues %s", DecoderType::Name.get(), this,
    184      mControlMessageQueue.back()->ToString().get());
    185  ProcessControlMessageQueue();
    186 }
    187 
    188 template <typename DecoderType>
    189 void DecoderTemplate<DecoderType>::Decode(InputType& aInput, ErrorResult& aRv) {
    190  AssertIsOnOwningThread();
    191 
    192  LOG("%s %p, Decode %s", DecoderType::Name.get(), this,
    193      aInput.ToString().get());
    194 
    195  if (mState != CodecState::Configured) {
    196    aRv.ThrowInvalidStateError("Decoder must be configured first");
    197    return;
    198  }
    199 
    200  if (mKeyChunkRequired) {
    201    // TODO: Verify input's data is truly a key chunk
    202    if (!DecoderType::IsKeyChunk(aInput)) {
    203      aRv.ThrowDataError(
    204          nsPrintfCString("%s needs a key chunk", DecoderType::Name.get()));
    205      return;
    206    }
    207    mKeyChunkRequired = false;
    208  }
    209 
    210  mAsyncDurationTracker.Start(
    211      aInput.Timestamp(),
    212      AutoWebCodecsMarker(DecoderType::Name.get(), ".decode-duration"));
    213  mDecodeQueueSize += 1;
    214  mControlMessageQueue.emplace(UniquePtr<ControlMessage>(
    215      new DecodeMessage(++mDecodeCounter, mLatestConfigureId,
    216                        DecoderType::CreateInputInternal(aInput))));
    217  LOGV("%s %p enqueues %s", DecoderType::Name.get(), this,
    218       mControlMessageQueue.back()->ToString().get());
    219  ProcessControlMessageQueue();
    220 }
    221 
    222 template <typename DecoderType>
    223 already_AddRefed<Promise> DecoderTemplate<DecoderType>::Flush(
    224    ErrorResult& aRv) {
    225  AssertIsOnOwningThread();
    226 
    227  LOG("%s %p, Flush", DecoderType::Name.get(), this);
    228 
    229  if (mState != CodecState::Configured) {
    230    LOG("%s %p, wrong state!", DecoderType::Name.get(), this);
    231    aRv.ThrowInvalidStateError("Decoder must be configured first");
    232    return nullptr;
    233  }
    234 
    235  RefPtr<Promise> p = Promise::Create(GetParentObject(), aRv);
    236  if (NS_WARN_IF(aRv.Failed())) {
    237    return p.forget();
    238  }
    239 
    240  mKeyChunkRequired = true;
    241 
    242  auto msg = UniquePtr<ControlMessage>(
    243      new FlushMessage(++mFlushCounter, mLatestConfigureId));
    244  const auto flushPromiseId = msg->AsFlushMessage()->mUniqueId;
    245  MOZ_ASSERT(!mPendingFlushPromises.Contains(flushPromiseId));
    246  mPendingFlushPromises.Insert(flushPromiseId, p);
    247 
    248  mControlMessageQueue.emplace(std::move(msg));
    249 
    250  LOG("%s %p enqueues %s, with unique id %" PRId64, DecoderType::Name.get(),
    251      this, mControlMessageQueue.back()->ToString().get(), flushPromiseId);
    252  ProcessControlMessageQueue();
    253  return p.forget();
    254 }
    255 
    256 template <typename DecoderType>
    257 void DecoderTemplate<DecoderType>::Reset(ErrorResult& aRv) {
    258  AssertIsOnOwningThread();
    259 
    260  LOG("%s %p, Reset", DecoderType::Name.get(), this);
    261 
    262  if (auto r = ResetInternal(NS_ERROR_DOM_ABORT_ERR); r.isErr()) {
    263    aRv.Throw(r.unwrapErr());
    264  }
    265 }
    266 
    267 template <typename DecoderType>
    268 void DecoderTemplate<DecoderType>::Close(ErrorResult& aRv) {
    269  AssertIsOnOwningThread();
    270 
    271  LOG("%s %p, Close", DecoderType::Name.get(), this);
    272 
    273  if (auto r = CloseInternalWithAbort(); r.isErr()) {
    274    aRv.Throw(r.unwrapErr());
    275  }
    276 }
    277 
    278 template <typename DecoderType>
    279 Result<Ok, nsresult> DecoderTemplate<DecoderType>::ResetInternal(
    280    const nsresult& aResult) {
    281  AssertIsOnOwningThread();
    282 
    283  if (mState == CodecState::Closed) {
    284    return Err(NS_ERROR_DOM_INVALID_STATE_ERR);
    285  }
    286 
    287  mState = CodecState::Unconfigured;
    288  mDecodeCounter = 0;
    289  mFlushCounter = 0;
    290 
    291  CancelPendingControlMessagesAndFlushPromises(aResult);
    292  DestroyDecoderAgentIfAny();
    293 
    294  if (mDecodeQueueSize > 0) {
    295    mDecodeQueueSize = 0;
    296    ScheduleDequeueEventIfNeeded();
    297  }
    298 
    299  LOG("%s %p now has its message queue unblocked", DecoderType::Name.get(),
    300      this);
    301  mMessageQueueBlocked = false;
    302 
    303  return Ok();
    304 }
    305 template <typename DecoderType>
    306 Result<Ok, nsresult> DecoderTemplate<DecoderType>::CloseInternalWithAbort() {
    307  AssertIsOnOwningThread();
    308 
    309  MOZ_TRY(ResetInternal(NS_ERROR_DOM_ABORT_ERR));
    310  mState = CodecState::Closed;
    311  return Ok();
    312 }
    313 
    314 template <typename DecoderType>
    315 void DecoderTemplate<DecoderType>::CloseInternal(const nsresult& aResult) {
    316  AssertIsOnOwningThread();
    317  MOZ_ASSERT(aResult != NS_ERROR_DOM_ABORT_ERR, "Use CloseInternalWithAbort");
    318 
    319  auto r = ResetInternal(aResult);
    320  if (r.isErr()) {
    321    nsCString name;
    322    GetErrorName(r.unwrapErr(), name);
    323    LOGE("Error in ResetInternal during CloseInternal: %s", name.get());
    324  }
    325  mState = CodecState::Closed;
    326  nsCString error;
    327  GetErrorName(aResult, error);
    328  LOGE("%s %p Close on error: %s", DecoderType::Name.get(), this, error.get());
    329  ReportError(aResult);
    330 }
    331 
    332 template <typename DecoderType>
    333 void DecoderTemplate<DecoderType>::ReportError(const nsresult& aResult) {
    334  AssertIsOnOwningThread();
    335 
    336  RefPtr<DOMException> e = DOMException::Create(aResult);
    337  RefPtr<WebCodecsErrorCallback> cb(mErrorCallback);
    338  cb->Call(*e);
    339 }
    340 
    341 template <typename DecoderType>
    342 void DecoderTemplate<DecoderType>::OutputDecodedData(
    343    const nsTArray<RefPtr<MediaData>>&& aData,
    344    const ConfigTypeInternal& aConfig) {
    345  AssertIsOnOwningThread();
    346  MOZ_ASSERT(mState == CodecState::Configured);
    347 
    348  if (!GetParentObject()) {
    349    LOGE("%s %p Canceling output callbacks since parent-object is gone",
    350         DecoderType::Name.get(), this);
    351    return;
    352  }
    353 
    354  nsTArray<RefPtr<OutputType>> frames =
    355      DecodedDataToOutputType(GetParentObject(), std::move(aData), aConfig);
    356  RefPtr<OutputCallbackType> cb(mOutputCallback);
    357  for (RefPtr<OutputType>& frame : frames) {
    358    LOG("Outputing decoded data: ts: %" PRId64, frame->Timestamp());
    359    RefPtr<OutputType> f = frame;
    360    mAsyncDurationTracker.End(f->Timestamp());
    361    cb->Call((OutputType&)(*f));
    362  }
    363 }
    364 
    365 template <typename DecoderType>
    366 void DecoderTemplate<DecoderType>::ScheduleDequeueEventIfNeeded() {
    367  AssertIsOnOwningThread();
    368 
    369  if (mDequeueEventScheduled) {
    370    return;
    371  }
    372  mDequeueEventScheduled = true;
    373 
    374  QueueATask("dequeue event task", [self = RefPtr{this}]() {
    375    self->FireEvent(nsGkAtoms::ondequeue, u"dequeue"_ns);
    376    self->mDequeueEventScheduled = false;
    377  });
    378 }
    379 
    380 template <typename DecoderType>
    381 nsresult DecoderTemplate<DecoderType>::FireEvent(nsAtom* aTypeWithOn,
    382                                                 const nsAString& aEventType) {
    383  if (aTypeWithOn && !HasListenersFor(aTypeWithOn)) {
    384    LOGV("%s %p has no %s event listener", DecoderType::Name.get(), this,
    385         NS_ConvertUTF16toUTF8(aEventType).get());
    386    return NS_ERROR_ABORT;
    387  }
    388 
    389  LOGV("Dispatch %s event to %s %p", NS_ConvertUTF16toUTF8(aEventType).get(),
    390       DecoderType::Name.get(), this);
    391  RefPtr<Event> event = new Event(this, nullptr, nullptr);
    392  event->InitEvent(aEventType, true, true);
    393  event->SetTrusted(true);
    394  this->DispatchEvent(*event);
    395  return NS_OK;
    396 }
    397 
    398 template <typename DecoderType>
    399 void DecoderTemplate<DecoderType>::ProcessControlMessageQueue() {
    400  AssertIsOnOwningThread();
    401  MOZ_ASSERT(mState == CodecState::Configured);
    402 
    403  while (!mMessageQueueBlocked && !mControlMessageQueue.empty()) {
    404    UniquePtr<ControlMessage>& msg = mControlMessageQueue.front();
    405    if (msg->AsConfigureMessage()) {
    406      if (ProcessConfigureMessage(msg) ==
    407          MessageProcessedResult::NotProcessed) {
    408        break;
    409      }
    410    } else if (msg->AsDecodeMessage()) {
    411      if (ProcessDecodeMessage(msg) == MessageProcessedResult::NotProcessed) {
    412        break;
    413      }
    414    } else {
    415      MOZ_ASSERT(msg->AsFlushMessage());
    416      if (ProcessFlushMessage(msg) == MessageProcessedResult::NotProcessed) {
    417        break;
    418      }
    419    }
    420  }
    421 }
    422 
    423 template <typename DecoderType>
    424 void DecoderTemplate<DecoderType>::CancelPendingControlMessagesAndFlushPromises(
    425    const nsresult& aResult) {
    426  AssertIsOnOwningThread();
    427 
    428  // Cancel the message that is being processed.
    429  if (mProcessingMessage) {
    430    LOG("%s %p cancels current %s", DecoderType::Name.get(), this,
    431        mProcessingMessage->ToString().get());
    432    mProcessingMessage->Cancel();
    433    mProcessingMessage.reset();
    434  }
    435 
    436  // Clear the message queue.
    437  while (!mControlMessageQueue.empty()) {
    438    LOG("%s %p cancels pending %s", DecoderType::Name.get(), this,
    439        mControlMessageQueue.front()->ToString().get());
    440    MOZ_ASSERT(!mControlMessageQueue.front()->IsProcessing());
    441    mControlMessageQueue.pop();
    442  }
    443 
    444  // If there are pending flush promises, reject them.
    445  mPendingFlushPromises.ForEach(
    446      [&](const int64_t& id, const RefPtr<Promise>& p) {
    447        LOG("%s %p, reject the promise for flush %" PRId64 " (unique id)",
    448            DecoderType::Name.get(), this, id);
    449        p->MaybeReject(aResult);
    450      });
    451  mPendingFlushPromises.Clear();
    452 }
    453 
    454 template <typename DecoderType>
    455 template <typename Func>
    456 void DecoderTemplate<DecoderType>::QueueATask(const char* aName,
    457                                              Func&& aSteps) {
    458  AssertIsOnOwningThread();
    459  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(
    460      NS_NewRunnableFunction(aName, std::forward<Func>(aSteps))));
    461 }
    462 
    463 template <typename DecoderType>
    464 MessageProcessedResult DecoderTemplate<DecoderType>::ProcessConfigureMessage(
    465    UniquePtr<ControlMessage>& aMessage) {
    466  AssertIsOnOwningThread();
    467  MOZ_ASSERT(mState == CodecState::Configured);
    468  MOZ_ASSERT(aMessage->AsConfigureMessage());
    469 
    470  AUTO_DECODER_MARKER(marker, ".configure");
    471 
    472  if (mProcessingMessage) {
    473    LOG("%s %p is processing %s. Defer %s", DecoderType::Name.get(), this,
    474        mProcessingMessage->ToString().get(), aMessage->ToString().get());
    475    return MessageProcessedResult::NotProcessed;
    476  }
    477 
    478  mProcessingMessage.reset(aMessage.release());
    479  mControlMessageQueue.pop();
    480 
    481  ConfigureMessage* msg = mProcessingMessage->AsConfigureMessage();
    482  LOG("%s %p starts processing %s", DecoderType::Name.get(), this,
    483      msg->ToString().get());
    484 
    485  DestroyDecoderAgentIfAny();
    486 
    487  mMessageQueueBlocked = true;
    488 
    489  nsAutoCString errorMessage;
    490  auto i = DecoderType::CreateTrackInfo(msg->Config());
    491  if (i.isErr()) {
    492    nsCString res;
    493    GetErrorName(i.unwrapErr(), res);
    494    errorMessage.AppendPrintf("CreateTrackInfo failed: %s", res.get());
    495  } else if (!DecoderType::IsSupported(msg->Config())) {
    496    errorMessage.Append("Not supported.");
    497  } else if (!CreateDecoderAgent(msg->mConfigId, msg->TakeConfig(),
    498                                 i.unwrap())) {
    499    errorMessage.Append("DecoderAgent creation failed.");
    500  }
    501  if (!errorMessage.IsEmpty()) {
    502    LOGE("%s %p ProcessConfigureMessage error (sync): %s",
    503         DecoderType::Name.get(), this, errorMessage.get());
    504 
    505    mProcessingMessage.reset();
    506    QueueATask("Error while configuring decoder",
    507               [self = RefPtr{this}]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    508                 self->CloseInternal(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    509               });
    510    return MessageProcessedResult::Processed;
    511  }
    512 
    513  MOZ_ASSERT(mAgent);
    514  MOZ_ASSERT(mActiveConfig);
    515 
    516  LOG("%s %p now blocks message-queue-processing", DecoderType::Name.get(),
    517      this);
    518 
    519  bool preferSW = mActiveConfig->mHardwareAcceleration ==
    520                  HardwareAcceleration::Prefer_software;
    521  bool lowLatency = mActiveConfig->mOptimizeForLatency.isSome() &&
    522                    mActiveConfig->mOptimizeForLatency.value();
    523 
    524  mAgent->Configure(preferSW, lowLatency)
    525      ->Then(GetCurrentSerialEventTarget(), __func__,
    526             [self = RefPtr{this}, id = mAgent->mId, m = std::move(marker)](
    527                 const DecoderAgent::ConfigurePromise::ResolveOrRejectValue&
    528                     aResult) mutable {
    529               MOZ_ASSERT(self->mProcessingMessage);
    530               MOZ_ASSERT(self->mProcessingMessage->AsConfigureMessage());
    531               MOZ_ASSERT(self->mState == CodecState::Configured);
    532               MOZ_ASSERT(self->mAgent);
    533               MOZ_ASSERT(id == self->mAgent->mId);
    534               MOZ_ASSERT(self->mActiveConfig);
    535 
    536               ConfigureMessage* msg =
    537                   self->mProcessingMessage->AsConfigureMessage();
    538               LOG("%s %p, DecoderAgent #%d %s has been %s. now unblocks "
    539                   "message-queue-processing",
    540                   DecoderType::Name.get(), self.get(), id,
    541                   msg->ToString().get(),
    542                   aResult.IsResolve() ? "resolved" : "rejected");
    543 
    544               msg->Complete();
    545               self->mProcessingMessage.reset();
    546 
    547               if (aResult.IsReject()) {
    548                 // The spec asks to close the decoder with an
    549                 // NotSupportedError so we log the exact error here.
    550                 const MediaResult& error = aResult.RejectValue();
    551                 LOGE("%s %p, DecoderAgent #%d failed to configure: %s",
    552                      DecoderType::Name.get(), self.get(), id,
    553                      error.Description().get());
    554 
    555                 self->QueueATask(
    556                     "Error during configure",
    557                     [self = RefPtr{self}]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    558                       MOZ_ASSERT(self->mState != CodecState::Closed);
    559                       self->CloseInternal(
    560                           NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
    561                     });
    562                 return;
    563               }
    564 
    565               LOG("%s %p, DecoderAgent #%d configured successfully. %u decode "
    566                   "requests are pending",
    567                   DecoderType::Name.get(), self.get(), id,
    568                   self->mDecodeQueueSize);
    569               self->mMessageQueueBlocked = false;
    570               self->ProcessControlMessageQueue();
    571             })
    572      ->Track(msg->Request());
    573 
    574  return MessageProcessedResult::Processed;
    575 }
    576 
    577 template <typename DecoderType>
    578 MessageProcessedResult DecoderTemplate<DecoderType>::ProcessDecodeMessage(
    579    UniquePtr<ControlMessage>& aMessage) {
    580  AssertIsOnOwningThread();
    581  MOZ_ASSERT(mState == CodecState::Configured);
    582  MOZ_ASSERT(aMessage->AsDecodeMessage());
    583 
    584  AUTO_DECODER_MARKER(marker, ".decode-process");
    585 
    586  if (mProcessingMessage) {
    587    LOGV("%s %p is processing %s. Defer %s", DecoderType::Name.get(), this,
    588         mProcessingMessage->ToString().get(), aMessage->ToString().get());
    589    return MessageProcessedResult::NotProcessed;
    590  }
    591 
    592  mProcessingMessage.reset(aMessage.release());
    593  mControlMessageQueue.pop();
    594 
    595  DecodeMessage* msg = mProcessingMessage->AsDecodeMessage();
    596  LOGV("%s %p starts processing %s", DecoderType::Name.get(), this,
    597       msg->ToString().get());
    598 
    599  mDecodeQueueSize -= 1;
    600  ScheduleDequeueEventIfNeeded();
    601 
    602  // Treat it like decode error if no DecoderAgent is available or the encoded
    603  // data is invalid.
    604  auto closeOnError = [&]() {
    605    mProcessingMessage.reset();
    606    QueueATask("Error during decode",
    607               [self = RefPtr{this}]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    608                 self->CloseInternal(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
    609               });
    610    return MessageProcessedResult::Processed;
    611  };
    612 
    613  if (!mAgent) {
    614    LOGE("%s %p is not configured", DecoderType::Name.get(), this);
    615    return closeOnError();
    616  }
    617 
    618  MOZ_ASSERT(mActiveConfig);
    619  RefPtr<MediaRawData> data = InputDataToMediaRawData(
    620      std::move(msg->mData), *(mAgent->mInfo), *mActiveConfig);
    621  if (!data) {
    622    LOGE("%s %p, data for %s is empty or invalid", DecoderType::Name.get(),
    623         this, msg->ToString().get());
    624    return closeOnError();
    625  }
    626 
    627  mAgent->Decode(data.get())
    628      ->Then(GetCurrentSerialEventTarget(), __func__,
    629             [self = RefPtr{this}, id = mAgent->mId, m = std::move(marker)](
    630                 DecoderAgent::DecodePromise::ResolveOrRejectValue&&
    631                     aResult) mutable {
    632               MOZ_ASSERT(self->mProcessingMessage);
    633               MOZ_ASSERT(self->mProcessingMessage->AsDecodeMessage());
    634               MOZ_ASSERT(self->mState == CodecState::Configured);
    635               MOZ_ASSERT(self->mAgent);
    636               MOZ_ASSERT(id == self->mAgent->mId);
    637               MOZ_ASSERT(self->mActiveConfig);
    638 
    639               DecodeMessage* msg = self->mProcessingMessage->AsDecodeMessage();
    640               LOGV("%s %p, DecoderAgent #%d %s has been %s",
    641                    DecoderType::Name.get(), self.get(), id,
    642                    msg->ToString().get(),
    643                    aResult.IsResolve() ? "resolved" : "rejected");
    644 
    645               nsCString msgStr = msg->ToString();
    646 
    647               msg->Complete();
    648               self->mProcessingMessage.reset();
    649 
    650               if (aResult.IsReject()) {
    651                 // The spec asks to queue a task to run close the decoder
    652                 // with an EncodingError so we log the exact error here.
    653                 const MediaResult& error = aResult.RejectValue();
    654                 LOGE("%s %p, DecoderAgent #%d %s failed: %s",
    655                      DecoderType::Name.get(), self.get(), id, msgStr.get(),
    656                      error.Description().get());
    657                 self->QueueATask(
    658                     "Error during decode runnable",
    659                     [self = RefPtr{self}]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    660                       MOZ_ASSERT(self->mState != CodecState::Closed);
    661                       self->CloseInternal(
    662                           NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
    663                     });
    664                 return;
    665               }
    666 
    667               MOZ_ASSERT(aResult.IsResolve());
    668               nsTArray<RefPtr<MediaData>> data =
    669                   std::move(aResult.ResolveValue());
    670               if (data.IsEmpty()) {
    671                 LOGV("%s %p got no data for %s", DecoderType::Name.get(),
    672                      self.get(), msgStr.get());
    673               } else {
    674                 LOGV("%s %p, schedule %zu decoded data output for %s",
    675                      DecoderType::Name.get(), self.get(), data.Length(),
    676                      msgStr.get());
    677 
    678                 m.End();
    679                 AUTO_DECODER_MARKER(outMarker, ".decode-output");
    680 
    681                 self->QueueATask("Output Decoded Data",
    682                                  [self = RefPtr{self}, data = std::move(data),
    683                                   config = RefPtr{self->mActiveConfig},
    684                                   om = std::move(outMarker)]()
    685                                      MOZ_CAN_RUN_SCRIPT_BOUNDARY mutable {
    686                                        self->OutputDecodedData(std::move(data),
    687                                                                *config);
    688                                      });
    689               }
    690               self->ProcessControlMessageQueue();
    691             })
    692      ->Track(msg->Request());
    693 
    694  return MessageProcessedResult::Processed;
    695 }
    696 
    697 template <typename DecoderType>
    698 MessageProcessedResult DecoderTemplate<DecoderType>::ProcessFlushMessage(
    699    UniquePtr<ControlMessage>& aMessage) {
    700  AssertIsOnOwningThread();
    701  MOZ_ASSERT(mState == CodecState::Configured);
    702  MOZ_ASSERT(aMessage->AsFlushMessage());
    703 
    704  AUTO_DECODER_MARKER(marker, ".flush");
    705 
    706  if (mProcessingMessage) {
    707    LOG("%s %p is processing %s. Defer %s", DecoderType::Name.get(), this,
    708        mProcessingMessage->ToString().get(), aMessage->ToString().get());
    709    return MessageProcessedResult::NotProcessed;
    710  }
    711 
    712  mProcessingMessage.reset(aMessage.release());
    713  mControlMessageQueue.pop();
    714 
    715  FlushMessage* msg = mProcessingMessage->AsFlushMessage();
    716  LOG("%s %p starts processing %s", DecoderType::Name.get(), this,
    717      msg->ToString().get());
    718 
    719  // No agent, no thing to do. The promise has been rejected with the
    720  // appropriate error in ResetInternal already.
    721  if (!mAgent) {
    722    LOGE("%s %p no agent, nothing to do", DecoderType::Name.get(), this);
    723    mProcessingMessage.reset();
    724    return MessageProcessedResult::Processed;
    725  }
    726 
    727  mAgent->DrainAndFlush()
    728      ->Then(GetCurrentSerialEventTarget(), __func__,
    729             [self = RefPtr{this}, id = mAgent->mId, m = std::move(marker),
    730              this](DecoderAgent::DecodePromise::ResolveOrRejectValue&&
    731                        aResult) mutable {
    732               MOZ_ASSERT(self->mProcessingMessage);
    733               MOZ_ASSERT(self->mProcessingMessage->AsFlushMessage());
    734               MOZ_ASSERT(self->mState == CodecState::Configured);
    735               MOZ_ASSERT(self->mAgent);
    736               MOZ_ASSERT(id == self->mAgent->mId);
    737               MOZ_ASSERT(self->mActiveConfig);
    738 
    739               FlushMessage* msg = self->mProcessingMessage->AsFlushMessage();
    740               LOG("%s %p, DecoderAgent #%d %s has been %s",
    741                   DecoderType::Name.get(), self.get(), id,
    742                   msg->ToString().get(),
    743                   aResult.IsResolve() ? "resolved" : "rejected");
    744 
    745               nsCString msgStr = msg->ToString();
    746 
    747               msg->Complete();
    748 
    749               const auto flushPromiseId = msg->mUniqueId;
    750 
    751               // If flush failed, it means decoder fails to decode the data
    752               // sent before, so we treat it like decode error. We reject
    753               // the promise first and then queue a task to close
    754               // VideoDecoder with an EncodingError.
    755               if (aResult.IsReject()) {
    756                 const MediaResult& error = aResult.RejectValue();
    757                 LOGE("%s %p, DecoderAgent #%d failed to flush: %s",
    758                      DecoderType::Name.get(), self.get(), id,
    759                      error.Description().get());
    760                 // Reject with an EncodingError instead of the error we got
    761                 // above.
    762                 self->QueueATask(
    763                     "Error during flush runnable",
    764                     [self = RefPtr{this}]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    765                       // If Reset() was invoked before this task executes, the
    766                       // promise in mPendingFlushPromises is handled there.
    767                       // Otherwise, the promise is going to be rejected by
    768                       // CloseInternal() below.
    769                       self->mProcessingMessage.reset();
    770                       MOZ_ASSERT(self->mState != CodecState::Closed);
    771                       self->CloseInternal(
    772                           NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
    773                     });
    774                 return;
    775               }
    776 
    777               nsTArray<RefPtr<MediaData>> data =
    778                   std::move(aResult.ResolveValue());
    779 
    780               if (data.IsEmpty()) {
    781                 LOG("%s %p gets no data for %s", DecoderType::Name.get(),
    782                     self.get(), msgStr.get());
    783               } else {
    784                 LOG("%s %p, schedule %zu decoded data output for %s",
    785                     DecoderType::Name.get(), self.get(), data.Length(),
    786                     msgStr.get());
    787               }
    788 
    789               m.End();
    790               AUTO_DECODER_MARKER(outMarker, ".flush-output");
    791 
    792               self->QueueATask(
    793                   "Flush: output decoding data task",
    794                   [self = RefPtr{self}, data = std::move(data),
    795                    config = RefPtr{self->mActiveConfig}, flushPromiseId,
    796                    om = std::move(
    797                        outMarker)]() MOZ_CAN_RUN_SCRIPT_BOUNDARY mutable {
    798                     self->OutputDecodedData(std::move(data), *config);
    799                     // If Reset() was invoked before this task executes, or
    800                     // during the output callback above in the execution of
    801                     // this task, the promise in mPendingFlushPromises is
    802                     // handled there. Otherwise, the promise is resolved here.
    803                     if (Maybe<RefPtr<Promise>> p =
    804                             self->mPendingFlushPromises.Take(flushPromiseId)) {
    805                       LOG("%s %p, resolving the promise for flush %" PRId64
    806                           " (unique id)",
    807                           DecoderType::Name.get(), self.get(), flushPromiseId);
    808                       p.value()->MaybeResolveWithUndefined();
    809                     }
    810                   });
    811               self->mProcessingMessage.reset();
    812               self->ProcessControlMessageQueue();
    813             })
    814      ->Track(msg->Request());
    815 
    816  return MessageProcessedResult::Processed;
    817 }
    818 
    819 // CreateDecoderAgent will create an DecoderAgent paired with a xpcom-shutdown
    820 // blocker and a worker-reference. Besides the needs mentioned in the header
    821 // file, the blocker and the worker-reference also provides an entry point for
    822 // us to clean up the resources. Other than the decoder dtor, Reset(), or
    823 // Close(), the resources should be cleaned up in the following situations:
    824 // 1. Decoder on window, closing document
    825 // 2. Decoder on worker, closing document
    826 // 3. Decoder on worker, terminating worker
    827 //
    828 // In case 1, the entry point to clean up is in the mShutdownBlocker's
    829 // ShutdownpPomise-resolver. In case 2, the entry point is in mWorkerRef's
    830 // shutting down callback. In case 3, the entry point is in mWorkerRef's
    831 // shutting down callback.
    832 
    833 template <typename DecoderType>
    834 bool DecoderTemplate<DecoderType>::CreateDecoderAgent(
    835    DecoderAgent::Id aId, already_AddRefed<ConfigTypeInternal> aConfig,
    836    UniquePtr<TrackInfo>&& aInfo) {
    837  AssertIsOnOwningThread();
    838  MOZ_ASSERT(mState == CodecState::Configured);
    839  MOZ_ASSERT(!mAgent);
    840  MOZ_ASSERT(!mActiveConfig);
    841  MOZ_ASSERT(!mShutdownBlocker);
    842  MOZ_ASSERT_IF(!NS_IsMainThread(), !mWorkerRef);
    843 
    844  auto resetOnFailure = MakeScopeExit([&]() {
    845    mAgent = nullptr;
    846    mActiveConfig = nullptr;
    847    mShutdownBlocker = nullptr;
    848    mWorkerRef = nullptr;
    849  });
    850 
    851  // If the decoder is on worker, get a worker reference.
    852  if (!NS_IsMainThread()) {
    853    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    854    if (NS_WARN_IF(!workerPrivate)) {
    855      return false;
    856    }
    857 
    858    // Clean up all the resources when worker is going away.
    859    RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
    860        workerPrivate, "DecoderTemplate::CreateDecoderAgent",
    861        [self = RefPtr{this}]() {
    862          LOG("%s %p, worker is going away", DecoderType::Name.get(),
    863              self.get());
    864          (void)self->ResetInternal(NS_ERROR_DOM_ABORT_ERR);
    865        });
    866    if (NS_WARN_IF(!workerRef)) {
    867      return false;
    868    }
    869 
    870    mWorkerRef = new ThreadSafeWorkerRef(workerRef);
    871  }
    872 
    873  mAgent = MakeRefPtr<DecoderAgent>(aId, std::move(aInfo));
    874  mActiveConfig = std::move(aConfig);
    875 
    876  // ShutdownBlockingTicket requires an unique name to register its own
    877  // nsIAsyncShutdownBlocker since each blocker needs a distinct name.
    878  // To do that, we use DecoderAgent's unique id to create a unique name.
    879  nsAutoString uniqueName;
    880  uniqueName.AppendPrintf(
    881      "Blocker for DecoderAgent #%d (codec: %s) @ %p", mAgent->mId,
    882      NS_ConvertUTF16toUTF8(mActiveConfig->mCodec).get(), mAgent.get());
    883 
    884  mShutdownBlocker = media::ShutdownBlockingTicket::Create(
    885      uniqueName, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__);
    886  if (!mShutdownBlocker) {
    887    LOGE("%s %p failed to create %s", DecoderType::Name.get(), this,
    888         NS_ConvertUTF16toUTF8(uniqueName).get());
    889    return false;
    890  }
    891 
    892  // Clean up all the resources when xpcom-will-shutdown arrives since the page
    893  // is going to be closed.
    894  mShutdownBlocker->ShutdownPromise()->Then(
    895      GetCurrentSerialEventTarget(), __func__,
    896      [self = RefPtr{this}, id = mAgent->mId,
    897       ref = mWorkerRef](bool /* aUnUsed*/) {
    898        LOG("%s %p gets xpcom-will-shutdown notification for DecoderAgent #%d",
    899            DecoderType::Name.get(), self.get(), id);
    900        (void)self->ResetInternal(NS_ERROR_DOM_ABORT_ERR);
    901      },
    902      [self = RefPtr{this}, id = mAgent->mId,
    903       ref = mWorkerRef](bool /* aUnUsed*/) {
    904        LOG("%s %p removes shutdown-blocker #%d before getting any "
    905            "notification. DecoderAgent #%d should have been dropped",
    906            DecoderType::Name.get(), self.get(), id, id);
    907        MOZ_ASSERT(!self->mAgent || self->mAgent->mId != id);
    908      });
    909 
    910  LOG("%s %p creates DecoderAgent #%d @ %p and its shutdown-blocker",
    911      DecoderType::Name.get(), this, mAgent->mId, mAgent.get());
    912 
    913  resetOnFailure.release();
    914  return true;
    915 }
    916 
    917 template <typename DecoderType>
    918 void DecoderTemplate<DecoderType>::DestroyDecoderAgentIfAny() {
    919  AssertIsOnOwningThread();
    920 
    921  if (!mAgent) {
    922    LOG("%s %p has no DecoderAgent to destroy", DecoderType::Name.get(), this);
    923    return;
    924  }
    925 
    926  MOZ_ASSERT(mActiveConfig);
    927  MOZ_ASSERT(mShutdownBlocker);
    928  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerRef);
    929 
    930  LOG("%s %p destroys DecoderAgent #%d @ %p", DecoderType::Name.get(), this,
    931      mAgent->mId, mAgent.get());
    932  mActiveConfig = nullptr;
    933  RefPtr<DecoderAgent> agent = std::move(mAgent);
    934  // mShutdownBlocker should be kept alive until the shutdown is done.
    935  // mWorkerRef is used to ensure this task won't be discarded in worker.
    936  agent->Shutdown()->Then(
    937      GetCurrentSerialEventTarget(), __func__,
    938      [self = RefPtr{this}, id = agent->mId, ref = std::move(mWorkerRef),
    939       blocker = std::move(mShutdownBlocker)](
    940          const ShutdownPromise::ResolveOrRejectValue& aResult) {
    941        LOG("%s %p, DecoderAgent #%d's shutdown has been %s. Drop its "
    942            "shutdown-blocker now",
    943            DecoderType::Name.get(), self.get(), id,
    944            aResult.IsResolve() ? "resolved" : "rejected");
    945      });
    946 }
    947 
    948 template class DecoderTemplate<VideoDecoderTraits>;
    949 template class DecoderTemplate<AudioDecoderTraits>;
    950 
    951 #undef LOG
    952 #undef LOGW
    953 #undef LOGE
    954 #undef LOGV
    955 #undef LOG_INTERNAL
    956 
    957 }  // namespace mozilla::dom