tor-browser

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

MediaEncoder.cpp (37384B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "MediaEncoder.h"
      7 
      8 #include <algorithm>
      9 
     10 #include "AudioNodeEngine.h"
     11 #include "AudioNodeTrack.h"
     12 #include "DriftCompensation.h"
     13 #include "MediaDecoder.h"
     14 #include "MediaTrackGraph.h"
     15 #include "MediaTrackListener.h"
     16 #include "Muxer.h"
     17 #include "OggWriter.h"
     18 #include "OpusTrackEncoder.h"
     19 #include "TimeUnits.h"
     20 #include "Tracing.h"
     21 #include "VP8TrackEncoder.h"
     22 #include "WebMWriter.h"
     23 #include "mozilla/Logging.h"
     24 #include "mozilla/Preferences.h"
     25 #include "mozilla/ProfilerLabels.h"
     26 #include "mozilla/StaticPrefs_media.h"
     27 #include "mozilla/StaticPtr.h"
     28 #include "mozilla/TaskQueue.h"
     29 #include "mozilla/dom/AudioNode.h"
     30 #include "mozilla/dom/AudioStreamTrack.h"
     31 #include "mozilla/dom/Blob.h"
     32 #include "mozilla/dom/BlobImpl.h"
     33 #include "mozilla/dom/MediaStreamTrack.h"
     34 #include "mozilla/dom/MutableBlobStorage.h"
     35 #include "mozilla/dom/VideoStreamTrack.h"
     36 #include "mozilla/gfx/Point.h"  // IntSize
     37 #include "nsMimeTypes.h"
     38 #include "nsThreadUtils.h"
     39 
     40 mozilla::LazyLogModule gMediaEncoderLog("MediaEncoder");
     41 #define LOG(type, msg) MOZ_LOG(gMediaEncoderLog, type, msg)
     42 
     43 namespace mozilla {
     44 
     45 using namespace dom;
     46 using namespace media;
     47 
     48 namespace {
     49 class BlobStorer : public MutableBlobStorageCallback {
     50  MozPromiseHolder<MediaEncoder::BlobPromise> mHolder;
     51 
     52  virtual ~BlobStorer() = default;
     53 
     54 public:
     55  BlobStorer() = default;
     56 
     57  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BlobStorer, override)
     58 
     59  void BlobStoreCompleted(MutableBlobStorage*, BlobImpl* aBlobImpl,
     60                          nsresult aRv) override {
     61    MOZ_ASSERT(NS_IsMainThread());
     62    if (NS_FAILED(aRv)) {
     63      mHolder.Reject(aRv, __func__);
     64      return;
     65    }
     66 
     67    mHolder.Resolve(aBlobImpl, __func__);
     68  }
     69 
     70  RefPtr<MediaEncoder::BlobPromise> Promise() {
     71    return mHolder.Ensure(__func__);
     72  }
     73 };
     74 }  // namespace
     75 
     76 class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
     77 public:
     78  AudioTrackListener(RefPtr<DriftCompensator> aDriftCompensator,
     79                     RefPtr<MediaEncoder> aMediaEncoder)
     80      : mDirectConnected(false),
     81        mInitialized(false),
     82        mRemoved(false),
     83        mDriftCompensator(std::move(aDriftCompensator)),
     84        mMediaEncoder(std::move(aMediaEncoder)),
     85        mEncoderThread(mMediaEncoder->mEncoderThread),
     86        mShutdownPromise(mShutdownHolder.Ensure(__func__)) {
     87    MOZ_ASSERT(mMediaEncoder);
     88    MOZ_ASSERT(mMediaEncoder->mAudioEncoder);
     89    MOZ_ASSERT(mEncoderThread);
     90  }
     91 
     92  void NotifyDirectListenerInstalled(InstallationResult aResult) override {
     93    if (aResult == InstallationResult::SUCCESS) {
     94      LOG(LogLevel::Info, ("Audio track direct listener installed"));
     95      mDirectConnected = true;
     96    } else {
     97      LOG(LogLevel::Info, ("Audio track failed to install direct listener"));
     98      MOZ_ASSERT(!mDirectConnected);
     99    }
    100  }
    101 
    102  void NotifyDirectListenerUninstalled() override {
    103    mDirectConnected = false;
    104 
    105    if (mRemoved) {
    106      mMediaEncoder = nullptr;
    107      mEncoderThread = nullptr;
    108    }
    109  }
    110 
    111  void NotifyQueuedChanges(MediaTrackGraph* aGraph, TrackTime aTrackOffset,
    112                           const MediaSegment& aQueuedMedia) override {
    113    TRACE_COMMENT("MediaEncoder::NotifyQueuedChanges", "%p",
    114                  mMediaEncoder.get());
    115    MOZ_ASSERT(mMediaEncoder);
    116    MOZ_ASSERT(mEncoderThread);
    117 
    118    if (!mInitialized) {
    119      mDriftCompensator->NotifyAudioStart(TimeStamp::Now());
    120      mInitialized = true;
    121    }
    122 
    123    mDriftCompensator->NotifyAudio(aQueuedMedia.GetDuration());
    124 
    125    const AudioSegment& audio = static_cast<const AudioSegment&>(aQueuedMedia);
    126 
    127    AudioSegment copy;
    128    copy.AppendSlice(audio, 0, audio.GetDuration());
    129 
    130    nsresult rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    131        "mozilla::AudioTrackEncoder::AppendAudioSegment",
    132        [encoder = mMediaEncoder, copy = std::move(copy)]() mutable {
    133          encoder->mAudioEncoder->AppendAudioSegment(std::move(copy));
    134        }));
    135    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    136    (void)rv;
    137  }
    138 
    139  void NotifyEnded(MediaTrackGraph* aGraph) override {
    140    MOZ_ASSERT(mMediaEncoder);
    141    MOZ_ASSERT(mMediaEncoder->mAudioEncoder);
    142    MOZ_ASSERT(mEncoderThread);
    143 
    144    nsresult rv = mEncoderThread->Dispatch(
    145        NS_NewRunnableFunction("mozilla::AudioTrackEncoder::NotifyEndOfStream",
    146                               [encoder = mMediaEncoder] {
    147                                 encoder->mAudioEncoder->NotifyEndOfStream();
    148                               }));
    149    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    150    (void)rv;
    151  }
    152 
    153  void NotifyRemoved(MediaTrackGraph* aGraph) override {
    154    nsresult rv = mEncoderThread->Dispatch(
    155        NS_NewRunnableFunction("mozilla::AudioTrackEncoder::NotifyEndOfStream",
    156                               [encoder = mMediaEncoder] {
    157                                 encoder->mAudioEncoder->NotifyEndOfStream();
    158                               }));
    159    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    160    (void)rv;
    161 
    162    mRemoved = true;
    163 
    164    if (!mDirectConnected) {
    165      mMediaEncoder = nullptr;
    166      mEncoderThread = nullptr;
    167    }
    168 
    169    mShutdownHolder.Resolve(true, __func__);
    170  }
    171 
    172  const RefPtr<GenericNonExclusivePromise>& OnShutdown() const {
    173    return mShutdownPromise;
    174  }
    175 
    176 private:
    177  bool mDirectConnected;
    178  bool mInitialized;
    179  bool mRemoved;
    180  const RefPtr<DriftCompensator> mDriftCompensator;
    181  RefPtr<MediaEncoder> mMediaEncoder;
    182  RefPtr<TaskQueue> mEncoderThread;
    183  MozPromiseHolder<GenericNonExclusivePromise> mShutdownHolder;
    184  const RefPtr<GenericNonExclusivePromise> mShutdownPromise;
    185 };
    186 
    187 class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
    188 public:
    189  explicit VideoTrackListener(RefPtr<MediaEncoder> aMediaEncoder)
    190      : mDirectConnected(false),
    191        mInitialized(false),
    192        mRemoved(false),
    193        mPendingAdvanceCurrentTime(false),
    194        mMediaEncoder(std::move(aMediaEncoder)),
    195        mEncoderThread(mMediaEncoder->mEncoderThread),
    196        mShutdownPromise(mShutdownHolder.Ensure(__func__)) {
    197    MOZ_ASSERT(mMediaEncoder);
    198    MOZ_ASSERT(mEncoderThread);
    199  }
    200 
    201  void NotifyDirectListenerInstalled(InstallationResult aResult) override {
    202    if (aResult == InstallationResult::SUCCESS) {
    203      LOG(LogLevel::Info, ("Video track direct listener installed"));
    204      mDirectConnected = true;
    205    } else {
    206      LOG(LogLevel::Info, ("Video track failed to install direct listener"));
    207      MOZ_ASSERT(!mDirectConnected);
    208      return;
    209    }
    210  }
    211 
    212  void NotifyDirectListenerUninstalled() override {
    213    mDirectConnected = false;
    214 
    215    if (mRemoved) {
    216      mMediaEncoder = nullptr;
    217      mEncoderThread = nullptr;
    218    }
    219  }
    220 
    221  void NotifyQueuedChanges(MediaTrackGraph* aGraph, TrackTime aTrackOffset,
    222                           const MediaSegment& aQueuedMedia) override {
    223    TRACE_COMMENT("MediaEncoder::NotifyQueuedChanges", "%p",
    224                  mMediaEncoder.get());
    225    MOZ_ASSERT(mMediaEncoder);
    226    MOZ_ASSERT(mMediaEncoder->mVideoEncoder);
    227    MOZ_ASSERT(mEncoderThread);
    228 
    229    mCurrentTime = TimeStamp::Now();
    230    if (!mInitialized) {
    231      nsresult rv = mEncoderThread->Dispatch(
    232          NS_NewRunnableFunction("mozilla::VideoTrackEncoder::SetStartOffset",
    233                                 [encoder = mMediaEncoder, now = mCurrentTime] {
    234                                   encoder->mVideoEncoder->SetStartOffset(now);
    235                                 }));
    236      MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    237      (void)rv;
    238      mInitialized = true;
    239    }
    240 
    241    if (!mPendingAdvanceCurrentTime) {
    242      mPendingAdvanceCurrentTime = true;
    243      nsresult rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    244          "mozilla::VideoTrackEncoder::AdvanceCurrentTime",
    245          [encoder = mMediaEncoder, now = mCurrentTime] {
    246            encoder->mVideoListener->mPendingAdvanceCurrentTime = false;
    247            encoder->mVideoEncoder->AdvanceCurrentTime(now);
    248          }));
    249      MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    250      (void)rv;
    251    }
    252  }
    253 
    254  void NotifyRealtimeTrackData(MediaTrackGraph* aGraph, TrackTime aTrackOffset,
    255                               const MediaSegment& aMedia) override {
    256    TRACE_COMMENT("MediaEncoder::NotifyRealtimeTrackData", "%p",
    257                  mMediaEncoder.get());
    258    MOZ_ASSERT(mMediaEncoder);
    259    MOZ_ASSERT(mMediaEncoder->mVideoEncoder);
    260    MOZ_ASSERT(mEncoderThread);
    261    MOZ_ASSERT(aMedia.GetType() == MediaSegment::VIDEO);
    262 
    263    const VideoSegment& video = static_cast<const VideoSegment&>(aMedia);
    264    VideoSegment copy;
    265    for (VideoSegment::ConstChunkIterator iter(video); !iter.IsEnded();
    266         iter.Next()) {
    267      copy.AppendFrame(do_AddRef(iter->mFrame.GetImage()),
    268                       iter->mFrame.GetIntrinsicSize(),
    269                       iter->mFrame.GetPrincipalHandle(),
    270                       iter->mFrame.GetForceBlack(), iter->mTimeStamp);
    271    }
    272 
    273    nsresult rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    274        "mozilla::VideoTrackEncoder::AppendVideoSegment",
    275        [encoder = mMediaEncoder, copy = std::move(copy)]() mutable {
    276          encoder->mVideoEncoder->AppendVideoSegment(std::move(copy));
    277        }));
    278    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    279    (void)rv;
    280  }
    281 
    282  void NotifyEnabledStateChanged(MediaTrackGraph* aGraph,
    283                                 bool aEnabled) override {
    284    MOZ_ASSERT(mMediaEncoder);
    285    MOZ_ASSERT(mMediaEncoder->mVideoEncoder);
    286    MOZ_ASSERT(mEncoderThread);
    287 
    288    nsresult rv;
    289    if (aEnabled) {
    290      rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    291          "mozilla::VideoTrackEncoder::Enable",
    292          [encoder = mMediaEncoder, now = TimeStamp::Now()] {
    293            encoder->mVideoEncoder->Enable(now);
    294          }));
    295    } else {
    296      rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    297          "mozilla::VideoTrackEncoder::Disable",
    298          [encoder = mMediaEncoder, now = TimeStamp::Now()] {
    299            encoder->mVideoEncoder->Disable(now);
    300          }));
    301    }
    302    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    303    (void)rv;
    304  }
    305 
    306  void NotifyEnded(MediaTrackGraph* aGraph) override {
    307    MOZ_ASSERT(mMediaEncoder);
    308    MOZ_ASSERT(mMediaEncoder->mVideoEncoder);
    309    MOZ_ASSERT(mEncoderThread);
    310 
    311    nsresult rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    312        "mozilla::VideoTrackEncoder::NotifyEndOfStream",
    313        [encoder = mMediaEncoder, now = mCurrentTime] {
    314          if (!now.IsNull()) {
    315            encoder->mVideoEncoder->AdvanceCurrentTime(now);
    316          }
    317          encoder->mVideoEncoder->NotifyEndOfStream();
    318        }));
    319    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    320    (void)rv;
    321  }
    322 
    323  void NotifyRemoved(MediaTrackGraph* aGraph) override {
    324    nsresult rv = mEncoderThread->Dispatch(NS_NewRunnableFunction(
    325        "mozilla::VideoTrackEncoder::NotifyEndOfStream",
    326        [encoder = mMediaEncoder, now = mCurrentTime] {
    327          if (!now.IsNull()) {
    328            encoder->mVideoEncoder->AdvanceCurrentTime(now);
    329          }
    330          encoder->mVideoEncoder->NotifyEndOfStream();
    331        }));
    332    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
    333    (void)rv;
    334 
    335    mRemoved = true;
    336 
    337    if (!mDirectConnected) {
    338      mMediaEncoder = nullptr;
    339      mEncoderThread = nullptr;
    340    }
    341 
    342    mShutdownHolder.Resolve(true, __func__);
    343  }
    344 
    345  const RefPtr<GenericNonExclusivePromise>& OnShutdown() const {
    346    return mShutdownPromise;
    347  }
    348 
    349 private:
    350  bool mDirectConnected;
    351  bool mInitialized;
    352  bool mRemoved;
    353  TimeStamp mCurrentTime;
    354  Atomic<bool> mPendingAdvanceCurrentTime;
    355  RefPtr<MediaEncoder> mMediaEncoder;
    356  RefPtr<TaskQueue> mEncoderThread;
    357  MozPromiseHolder<GenericNonExclusivePromise> mShutdownHolder;
    358  const RefPtr<GenericNonExclusivePromise> mShutdownPromise;
    359 };
    360 
    361 class MediaEncoder::EncoderListener : public TrackEncoderListener {
    362 public:
    363  EncoderListener(TaskQueue* aEncoderThread, MediaEncoder* aEncoder)
    364      : mEncoderThread(aEncoderThread), mEncoder(aEncoder) {}
    365 
    366  void Forget() {
    367    MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    368    mEncoder = nullptr;
    369  }
    370 
    371  void Initialized(TrackEncoder* aTrackEncoder) override {
    372    MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    373    MOZ_ASSERT(aTrackEncoder->IsInitialized());
    374 
    375    if (!mEncoder) {
    376      return;
    377    }
    378 
    379    mEncoder->UpdateInitialized();
    380  }
    381 
    382  void Started(TrackEncoder* aTrackEncoder) override {
    383    MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    384    MOZ_ASSERT(aTrackEncoder->IsStarted());
    385 
    386    if (!mEncoder) {
    387      return;
    388    }
    389 
    390    mEncoder->UpdateStarted();
    391  }
    392 
    393  void Error(TrackEncoder* aTrackEncoder) override {
    394    MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    395 
    396    if (!mEncoder) {
    397      return;
    398    }
    399 
    400    mEncoder->SetError();
    401  }
    402 
    403 protected:
    404  RefPtr<TaskQueue> mEncoderThread;
    405  RefPtr<MediaEncoder> mEncoder;
    406 };
    407 
    408 MediaEncoder::MediaEncoder(
    409    RefPtr<TaskQueue> aEncoderThread,
    410    RefPtr<DriftCompensator> aDriftCompensator,
    411    UniquePtr<ContainerWriter> aWriter,
    412    UniquePtr<AudioTrackEncoder> aAudioEncoder,
    413    UniquePtr<VideoTrackEncoder> aVideoEncoder,
    414    UniquePtr<MediaQueue<EncodedFrame>> aEncodedAudioQueue,
    415    UniquePtr<MediaQueue<EncodedFrame>> aEncodedVideoQueue,
    416    TrackRate aTrackRate, const nsAString& aMimeType, uint64_t aMaxMemory,
    417    TimeDuration aTimeslice)
    418    : mMainThread(GetMainThreadSerialEventTarget()),
    419      mEncoderThread(std::move(aEncoderThread)),
    420      mEncodedAudioQueue(std::move(aEncodedAudioQueue)),
    421      mEncodedVideoQueue(std::move(aEncodedVideoQueue)),
    422      mMuxer(MakeUnique<Muxer>(std::move(aWriter), *mEncodedAudioQueue,
    423                               *mEncodedVideoQueue)),
    424      mAudioEncoder(std::move(aAudioEncoder)),
    425      mAudioListener(mAudioEncoder ? MakeAndAddRef<AudioTrackListener>(
    426                                         std::move(aDriftCompensator), this)
    427                                   : nullptr),
    428      mVideoEncoder(std::move(aVideoEncoder)),
    429      mVideoListener(mVideoEncoder ? MakeAndAddRef<VideoTrackListener>(this)
    430                                   : nullptr),
    431      mEncoderListener(MakeAndAddRef<EncoderListener>(mEncoderThread, this)),
    432      mMimeType(aMimeType),
    433      mMaxMemory(aMaxMemory),
    434      mTimeslice(aTimeslice),
    435      mStartTime(TimeStamp::Now()),
    436      mInitialized(false),
    437      mStarted(false),
    438      mCompleted(false),
    439      mError(false) {
    440  if (!mAudioEncoder) {
    441    mMuxedAudioEndTime = TimeUnit::FromInfinity();
    442    mEncodedAudioQueue->Finish();
    443  }
    444  if (!mVideoEncoder) {
    445    mMuxedVideoEndTime = TimeUnit::FromInfinity();
    446    mEncodedVideoQueue->Finish();
    447  }
    448 }
    449 
    450 void MediaEncoder::RegisterListeners() {
    451  if (mAudioEncoder) {
    452    mAudioPushListener = mEncodedAudioQueue->PushEvent().Connect(
    453        mEncoderThread, this, &MediaEncoder::OnEncodedAudioPushed);
    454    mAudioFinishListener = mEncodedAudioQueue->FinishEvent().Connect(
    455        mEncoderThread, this, &MediaEncoder::MaybeShutdown);
    456    MOZ_ALWAYS_SUCCEEDS(mEncoderThread->Dispatch(NS_NewRunnableFunction(
    457        "mozilla::AudioTrackEncoder::RegisterListener",
    458        [self = RefPtr<MediaEncoder>(this), this] {
    459          mAudioEncoder->RegisterListener(mEncoderListener);
    460        })));
    461  }
    462  if (mVideoEncoder) {
    463    mVideoPushListener = mEncodedVideoQueue->PushEvent().Connect(
    464        mEncoderThread, this, &MediaEncoder::OnEncodedVideoPushed);
    465    mVideoFinishListener = mEncodedVideoQueue->FinishEvent().Connect(
    466        mEncoderThread, this, &MediaEncoder::MaybeShutdown);
    467    MOZ_ALWAYS_SUCCEEDS(mEncoderThread->Dispatch(NS_NewRunnableFunction(
    468        "mozilla::VideoTrackEncoder::RegisterListener",
    469        [self = RefPtr<MediaEncoder>(this), this] {
    470          mVideoEncoder->RegisterListener(mEncoderListener);
    471        })));
    472  }
    473 }
    474 
    475 MediaEncoder::~MediaEncoder() {
    476  MOZ_ASSERT(!mAudioTrack);
    477  MOZ_ASSERT(!mVideoTrack);
    478  MOZ_ASSERT(!mAudioNode);
    479  MOZ_ASSERT(!mInputPort);
    480  MOZ_ASSERT(!mPipeTrack);
    481 }
    482 
    483 void MediaEncoder::EnsureGraphTrackFrom(MediaTrack* aTrack) {
    484  if (mGraphTrack) {
    485    return;
    486  }
    487  MOZ_DIAGNOSTIC_ASSERT(!aTrack->IsDestroyed());
    488  mGraphTrack = MakeAndAddRef<SharedDummyTrack>(
    489      aTrack->Graph()->CreateSourceTrack(MediaSegment::VIDEO));
    490 }
    491 
    492 void MediaEncoder::Suspend() {
    493  mGraphTrack->mTrack->QueueControlMessageWithNoShutdown(
    494      [self = RefPtr<MediaEncoder>(this), this] {
    495        TRACE("MediaEncoder::Suspend (graph)");
    496        if (NS_FAILED(mEncoderThread->Dispatch(
    497                NS_NewRunnableFunction("MediaEncoder::Suspend (encoder)",
    498                                       [self, this, now = TimeStamp::Now()] {
    499                                         if (mAudioEncoder) {
    500                                           mAudioEncoder->Suspend();
    501                                         }
    502                                         if (mVideoEncoder) {
    503                                           mVideoEncoder->Suspend(now);
    504                                         }
    505                                       })))) {
    506          // QueueControlMessageWithNoShutdown added an extra async step, and
    507          // now `thread` has shut down.
    508          return;
    509        }
    510      });
    511 }
    512 
    513 void MediaEncoder::Resume() {
    514  mGraphTrack->mTrack->QueueControlMessageWithNoShutdown(
    515      [self = RefPtr<MediaEncoder>(this), this] {
    516        TRACE("MediaEncoder::Resume (graph)");
    517        if (NS_FAILED(mEncoderThread->Dispatch(
    518                NS_NewRunnableFunction("MediaEncoder::Resume (encoder)",
    519                                       [self, this, now = TimeStamp::Now()] {
    520                                         if (mAudioEncoder) {
    521                                           mAudioEncoder->Resume();
    522                                         }
    523                                         if (mVideoEncoder) {
    524                                           mVideoEncoder->Resume(now);
    525                                         }
    526                                       })))) {
    527          // QueueControlMessageWithNoShutdown added an extra async step, and
    528          // now `thread` has shut down.
    529          return;
    530        }
    531      });
    532 }
    533 
    534 void MediaEncoder::ConnectAudioNode(AudioNode* aNode, uint32_t aOutput) {
    535  MOZ_ASSERT(NS_IsMainThread());
    536 
    537  if (mAudioNode) {
    538    MOZ_ASSERT(false, "Only one audio node supported");
    539    return;
    540  }
    541 
    542  // Only AudioNodeTrack of kind EXTERNAL_OUTPUT stores output audio data in
    543  // the track (see AudioNodeTrack::AdvanceOutputSegment()). That means
    544  // forwarding input track in recorder session won't be able to copy data from
    545  // the track of non-destination node. Create a pipe track in this case.
    546  if (aNode->NumberOfOutputs() > 0) {
    547    AudioContext* ctx = aNode->Context();
    548    AudioNodeEngine* engine = new AudioNodeEngine(nullptr);
    549    AudioNodeTrack::Flags flags = AudioNodeTrack::EXTERNAL_OUTPUT |
    550                                  AudioNodeTrack::NEED_MAIN_THREAD_ENDED;
    551    mPipeTrack = AudioNodeTrack::Create(ctx, engine, flags, ctx->Graph());
    552    AudioNodeTrack* ns = aNode->GetTrack();
    553    if (ns) {
    554      mInputPort = mPipeTrack->AllocateInputPort(aNode->GetTrack(), 0, aOutput);
    555    }
    556  }
    557 
    558  mAudioNode = aNode;
    559 
    560  if (mPipeTrack) {
    561    mPipeTrack->AddListener(mAudioListener);
    562    EnsureGraphTrackFrom(mPipeTrack);
    563  } else {
    564    mAudioNode->GetTrack()->AddListener(mAudioListener);
    565    EnsureGraphTrackFrom(mAudioNode->GetTrack());
    566  }
    567 }
    568 
    569 void MediaEncoder::ConnectMediaStreamTrack(MediaStreamTrack* aTrack) {
    570  MOZ_ASSERT(NS_IsMainThread());
    571 
    572  if (aTrack->Ended()) {
    573    MOZ_ASSERT_UNREACHABLE("Cannot connect ended track");
    574    return;
    575  }
    576 
    577  EnsureGraphTrackFrom(aTrack->GetTrack());
    578 
    579  if (AudioStreamTrack* audio = aTrack->AsAudioStreamTrack()) {
    580    if (!mAudioEncoder) {
    581      // No audio encoder for this audio track. It could be disabled.
    582      LOG(LogLevel::Warning, ("Cannot connect to audio track - no encoder"));
    583      return;
    584    }
    585 
    586    MOZ_ASSERT(!mAudioTrack, "Only one audio track supported.");
    587    MOZ_ASSERT(mAudioListener, "No audio listener for this audio track");
    588 
    589    LOG(LogLevel::Info, ("Connected to audio track %p", aTrack));
    590 
    591    mAudioTrack = audio;
    592    audio->AddListener(mAudioListener);
    593  } else if (VideoStreamTrack* video = aTrack->AsVideoStreamTrack()) {
    594    if (!mVideoEncoder) {
    595      // No video encoder for this video track. It could be disabled.
    596      LOG(LogLevel::Warning, ("Cannot connect to video track - no encoder"));
    597      return;
    598    }
    599 
    600    MOZ_ASSERT(!mVideoTrack, "Only one video track supported.");
    601    MOZ_ASSERT(mVideoListener, "No video listener for this video track");
    602 
    603    LOG(LogLevel::Info, ("Connected to video track %p", aTrack));
    604 
    605    mVideoTrack = video;
    606    video->AddDirectListener(mVideoListener);
    607    video->AddListener(mVideoListener);
    608  } else {
    609    MOZ_ASSERT(false, "Unknown track type");
    610  }
    611 }
    612 
    613 void MediaEncoder::RemoveMediaStreamTrack(MediaStreamTrack* aTrack) {
    614  if (!aTrack) {
    615    MOZ_ASSERT(false);
    616    return;
    617  }
    618 
    619  if (AudioStreamTrack* audio = aTrack->AsAudioStreamTrack()) {
    620    if (audio != mAudioTrack) {
    621      MOZ_ASSERT(false, "Not connected to this audio track");
    622      return;
    623    }
    624 
    625    if (mAudioListener) {
    626      audio->RemoveDirectListener(mAudioListener);
    627      audio->RemoveListener(mAudioListener);
    628    }
    629    mAudioTrack = nullptr;
    630  } else if (VideoStreamTrack* video = aTrack->AsVideoStreamTrack()) {
    631    if (video != mVideoTrack) {
    632      MOZ_ASSERT(false, "Not connected to this video track");
    633      return;
    634    }
    635 
    636    if (mVideoListener) {
    637      video->RemoveDirectListener(mVideoListener);
    638      video->RemoveListener(mVideoListener);
    639    }
    640    mVideoTrack = nullptr;
    641  }
    642 }
    643 
    644 /* static */
    645 already_AddRefed<MediaEncoder> MediaEncoder::CreateEncoder(
    646    RefPtr<TaskQueue> aEncoderThread, const nsAString& aMimeType,
    647    uint32_t aAudioBitrate, uint32_t aVideoBitrate, uint8_t aTrackTypes,
    648    TrackRate aTrackRate, uint64_t aMaxMemory, TimeDuration aTimeslice) {
    649  AUTO_PROFILER_LABEL("MediaEncoder::CreateEncoder", OTHER);
    650 
    651  UniquePtr<ContainerWriter> writer;
    652  UniquePtr<AudioTrackEncoder> audioEncoder;
    653  UniquePtr<VideoTrackEncoder> videoEncoder;
    654  auto encodedAudioQueue = MakeUnique<MediaQueue<EncodedFrame>>();
    655  auto encodedVideoQueue = MakeUnique<MediaQueue<EncodedFrame>>();
    656  auto driftCompensator =
    657      MakeRefPtr<DriftCompensator>(aEncoderThread, aTrackRate);
    658 
    659  Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aMimeType);
    660  if (!mimeType) {
    661    return nullptr;
    662  }
    663 
    664  for (const auto& codec : mimeType->ExtendedType().Codecs().Range()) {
    665    if (codec.EqualsLiteral("opus")) {
    666      MOZ_ASSERT(!audioEncoder);
    667      audioEncoder =
    668          MakeUnique<OpusTrackEncoder>(aTrackRate, *encodedAudioQueue);
    669    } else if (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0")) {
    670      MOZ_ASSERT(!videoEncoder);
    671      if (Preferences::GetBool("media.recorder.video.frame_drops", true)) {
    672        videoEncoder = MakeUnique<VP8TrackEncoder>(driftCompensator, aTrackRate,
    673                                                   *encodedVideoQueue,
    674                                                   FrameDroppingMode::ALLOW);
    675      } else {
    676        videoEncoder = MakeUnique<VP8TrackEncoder>(driftCompensator, aTrackRate,
    677                                                   *encodedVideoQueue,
    678                                                   FrameDroppingMode::DISALLOW);
    679      }
    680    } else {
    681      MOZ_CRASH("Unknown codec");
    682    }
    683  }
    684 
    685  if (mimeType->Type() == MEDIAMIMETYPE(VIDEO_WEBM) ||
    686      mimeType->Type() == MEDIAMIMETYPE(AUDIO_WEBM)) {
    687    MOZ_ASSERT_IF(mimeType->Type() == MEDIAMIMETYPE(AUDIO_WEBM), !videoEncoder);
    688    writer = MakeUnique<WebMWriter>();
    689  } else if (mimeType->Type() == MEDIAMIMETYPE(AUDIO_OGG)) {
    690    MOZ_ASSERT(audioEncoder);
    691    MOZ_ASSERT(!videoEncoder);
    692    writer = MakeUnique<OggWriter>();
    693  }
    694  NS_ENSURE_TRUE(writer, nullptr);
    695 
    696  LOG(LogLevel::Info,
    697      ("Create encoder result:a[%p](%u bps) v[%p](%u bps) w[%p] mimeType = "
    698       "%s.",
    699       audioEncoder.get(), aAudioBitrate, videoEncoder.get(), aVideoBitrate,
    700       writer.get(), NS_ConvertUTF16toUTF8(aMimeType).get()));
    701 
    702  if (audioEncoder) {
    703    audioEncoder->SetWorkerThread(aEncoderThread);
    704    if (aAudioBitrate != 0) {
    705      audioEncoder->SetBitrate(aAudioBitrate);
    706    }
    707  }
    708  if (videoEncoder) {
    709    videoEncoder->SetWorkerThread(aEncoderThread);
    710    if (aVideoBitrate != 0) {
    711      videoEncoder->SetBitrate(aVideoBitrate);
    712    }
    713  }
    714  RefPtr<MediaEncoder> encoder = new MediaEncoder(
    715      std::move(aEncoderThread), std::move(driftCompensator), std::move(writer),
    716      std::move(audioEncoder), std::move(videoEncoder),
    717      std::move(encodedAudioQueue), std::move(encodedVideoQueue), aTrackRate,
    718      aMimeType, aMaxMemory, aTimeslice);
    719 
    720  encoder->RegisterListeners();
    721 
    722  return encoder.forget();
    723 }
    724 
    725 nsresult MediaEncoder::GetEncodedData(
    726    nsTArray<nsTArray<uint8_t>>* aOutputBufs) {
    727  AUTO_PROFILER_LABEL("MediaEncoder::GetEncodedData", OTHER);
    728 
    729  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    730 
    731  LOG(LogLevel::Verbose,
    732      ("GetEncodedData TimeStamp = %f", GetEncodeTimeStamp()));
    733 
    734  if (!mInitialized) {
    735    return NS_ERROR_NOT_INITIALIZED;
    736  }
    737 
    738  nsresult rv = mMuxer->GetData(aOutputBufs);
    739  if (mMuxer->IsFinished()) {
    740    mCompleted = true;
    741  }
    742 
    743  LOG(LogLevel::Verbose,
    744      ("END GetEncodedData TimeStamp=%f "
    745       "mCompleted=%d, aComplete=%d, vComplete=%d",
    746       GetEncodeTimeStamp(), mCompleted,
    747       !mAudioEncoder || mAudioEncoder->IsEncodingComplete(),
    748       !mVideoEncoder || mVideoEncoder->IsEncodingComplete()));
    749 
    750  return rv;
    751 }
    752 
    753 void MediaEncoder::MaybeShutdown() {
    754  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    755  if (!mEncodedAudioQueue->IsFinished()) {
    756    LOG(LogLevel::Debug,
    757        ("MediaEncoder %p not shutting down, audio is still live", this));
    758    return;
    759  }
    760 
    761  if (!mEncodedVideoQueue->IsFinished()) {
    762    LOG(LogLevel::Debug,
    763        ("MediaEncoder %p not shutting down, video is still live", this));
    764    return;
    765  }
    766 
    767  mShutdownEvent.Notify();
    768 
    769  // Stop will Shutdown() gracefully.
    770  (void)InvokeAsync(mMainThread, this, __func__, &MediaEncoder::Stop);
    771 }
    772 
    773 RefPtr<GenericNonExclusivePromise> MediaEncoder::Shutdown() {
    774  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    775  if (mShutdownPromise) {
    776    return mShutdownPromise;
    777  }
    778 
    779  LOG(LogLevel::Info, ("MediaEncoder is shutting down."));
    780 
    781  AutoTArray<RefPtr<GenericNonExclusivePromise>, 2> shutdownPromises;
    782  if (mAudioListener) {
    783    shutdownPromises.AppendElement(mAudioListener->OnShutdown());
    784  }
    785  if (mVideoListener) {
    786    shutdownPromises.AppendElement(mVideoListener->OnShutdown());
    787  }
    788 
    789  mShutdownPromise =
    790      GenericNonExclusivePromise::All(mEncoderThread, shutdownPromises)
    791          ->Then(mEncoderThread, __func__,
    792                 [](const GenericNonExclusivePromise::AllPromiseType::
    793                        ResolveOrRejectValue& aValue) {
    794                   if (aValue.IsResolve()) {
    795                     return GenericNonExclusivePromise::CreateAndResolve(
    796                         true, __func__);
    797                   }
    798                   return GenericNonExclusivePromise::CreateAndReject(
    799                       aValue.RejectValue(), __func__);
    800                 });
    801 
    802  mShutdownPromise->Then(
    803      mEncoderThread, __func__, [self = RefPtr<MediaEncoder>(this), this] {
    804        if (mAudioEncoder) {
    805          mAudioEncoder->UnregisterListener(mEncoderListener);
    806        }
    807        if (mVideoEncoder) {
    808          mVideoEncoder->UnregisterListener(mEncoderListener);
    809        }
    810        mEncoderListener->Forget();
    811        mMuxer->Disconnect();
    812        mAudioPushListener.DisconnectIfExists();
    813        mAudioFinishListener.DisconnectIfExists();
    814        mVideoPushListener.DisconnectIfExists();
    815        mVideoFinishListener.DisconnectIfExists();
    816      });
    817 
    818  return mShutdownPromise;
    819 }
    820 
    821 RefPtr<GenericNonExclusivePromise> MediaEncoder::Stop() {
    822  MOZ_ASSERT(NS_IsMainThread());
    823 
    824  LOG(LogLevel::Info, ("MediaEncoder %p Stop", this));
    825 
    826  DisconnectTracks();
    827 
    828  return InvokeAsync(mEncoderThread, this, __func__, &MediaEncoder::Shutdown);
    829 }
    830 
    831 RefPtr<GenericNonExclusivePromise> MediaEncoder::Cancel() {
    832  MOZ_ASSERT(NS_IsMainThread());
    833 
    834  LOG(LogLevel::Info, ("MediaEncoder %p Cancel", this));
    835 
    836  DisconnectTracks();
    837 
    838  return InvokeAsync(mEncoderThread, __func__,
    839                     [self = RefPtr<MediaEncoder>(this), this]() {
    840                       if (mAudioEncoder) {
    841                         mAudioEncoder->Cancel();
    842                       }
    843                       if (mVideoEncoder) {
    844                         mVideoEncoder->Cancel();
    845                       }
    846                       return Shutdown();
    847                     });
    848 }
    849 
    850 bool MediaEncoder::HasError() {
    851  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    852  return mError;
    853 }
    854 
    855 void MediaEncoder::SetError() {
    856  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    857 
    858  if (mError) {
    859    return;
    860  }
    861 
    862  mError = true;
    863  mErrorEvent.Notify();
    864 }
    865 
    866 auto MediaEncoder::RequestData() -> RefPtr<BlobPromise> {
    867  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    868  TimeUnit muxedEndTime = std::min(mMuxedAudioEndTime, mMuxedVideoEndTime);
    869  mLastBlobTime = muxedEndTime;
    870  mLastExtractTime = muxedEndTime;
    871  return Extract()->Then(
    872      mMainThread, __func__,
    873      [this, self = RefPtr<MediaEncoder>(this)](
    874          const GenericPromise::ResolveOrRejectValue& aValue) {
    875        // Even if rejected, we want to gather what has already been
    876        // extracted into the current blob and expose that.
    877        (void)NS_WARN_IF(aValue.IsReject());
    878        return GatherBlob();
    879      });
    880 }
    881 
    882 void MediaEncoder::MaybeCreateMutableBlobStorage() {
    883  MOZ_ASSERT(NS_IsMainThread());
    884  if (!mMutableBlobStorage) {
    885    mMutableBlobStorage = new MutableBlobStorage(
    886        MutableBlobStorage::eCouldBeInTemporaryFile, nullptr, mMaxMemory);
    887  }
    888 }
    889 
    890 void MediaEncoder::OnEncodedAudioPushed(const RefPtr<EncodedFrame>& aFrame) {
    891  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    892  mMuxedAudioEndTime = aFrame->GetEndTime();
    893  MaybeExtractOrGatherBlob();
    894 }
    895 
    896 void MediaEncoder::OnEncodedVideoPushed(const RefPtr<EncodedFrame>& aFrame) {
    897  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    898  mMuxedVideoEndTime = aFrame->GetEndTime();
    899  MaybeExtractOrGatherBlob();
    900 }
    901 
    902 void MediaEncoder::MaybeExtractOrGatherBlob() {
    903  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    904 
    905  TimeUnit muxedEndTime = std::min(mMuxedAudioEndTime, mMuxedVideoEndTime);
    906  if ((muxedEndTime - mLastBlobTime).ToTimeDuration() >= mTimeslice) {
    907    LOG(LogLevel::Verbose, ("MediaEncoder %p Muxed %.2fs of data since last "
    908                            "blob. Issuing new blob.",
    909                            this, (muxedEndTime - mLastBlobTime).ToSeconds()));
    910    RequestData()->Then(mEncoderThread, __func__,
    911                        [this, self = RefPtr<MediaEncoder>(this)](
    912                            const BlobPromise::ResolveOrRejectValue& aValue) {
    913                          if (aValue.IsReject()) {
    914                            SetError();
    915                            return;
    916                          }
    917                          RefPtr<BlobImpl> blob = aValue.ResolveValue();
    918                          mDataAvailableEvent.Notify(std::move(blob));
    919                        });
    920  }
    921 
    922  if (muxedEndTime - mLastExtractTime > TimeUnit::FromSeconds(1)) {
    923    // Extract data from the muxer at least every second.
    924    LOG(LogLevel::Verbose,
    925        ("MediaEncoder %p Muxed %.2fs of data since last "
    926         "extract. Extracting more data into blob.",
    927         this, (muxedEndTime - mLastExtractTime).ToSeconds()));
    928    mLastExtractTime = muxedEndTime;
    929    (void)Extract();
    930  }
    931 }
    932 
    933 // Pull encoded media data from MediaEncoder and put into MutableBlobStorage.
    934 RefPtr<GenericPromise> MediaEncoder::Extract() {
    935  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
    936 
    937  LOG(LogLevel::Debug, ("MediaEncoder %p Extract", this));
    938 
    939  AUTO_PROFILER_LABEL("MediaEncoder::Extract", OTHER);
    940 
    941  // Pull encoded media data from MediaEncoder
    942  nsTArray<nsTArray<uint8_t>> buffer;
    943  nsresult rv = GetEncodedData(&buffer);
    944  MOZ_ASSERT(rv != NS_ERROR_INVALID_ARG, "Invalid args can be prevented.");
    945  if (NS_FAILED(rv)) {
    946    MOZ_RELEASE_ASSERT(buffer.IsEmpty());
    947    // Even if we failed to encode more data, it might be time to push a blob
    948    // with already encoded data.
    949  }
    950 
    951  // To ensure Extract() promises are resolved in calling order, we always
    952  // invoke the main thread. Even when the encoded buffer is empty.
    953  return InvokeAsync(
    954      mMainThread, __func__,
    955      [self = RefPtr<MediaEncoder>(this), this, buffer = std::move(buffer)] {
    956        MaybeCreateMutableBlobStorage();
    957        for (const auto& part : buffer) {
    958          if (part.IsEmpty()) {
    959            continue;
    960          }
    961 
    962          nsresult rv =
    963              mMutableBlobStorage->Append(part.Elements(), part.Length());
    964          if (NS_WARN_IF(NS_FAILED(rv))) {
    965            return GenericPromise::CreateAndReject(rv, __func__);
    966          }
    967        }
    968        return GenericPromise::CreateAndResolve(true, __func__);
    969      });
    970 }
    971 
    972 auto MediaEncoder::GatherBlob() -> RefPtr<BlobPromise> {
    973  MOZ_ASSERT(NS_IsMainThread());
    974  if (!mBlobPromise) {
    975    return mBlobPromise = GatherBlobImpl();
    976  }
    977  return mBlobPromise = mBlobPromise->Then(mMainThread, __func__,
    978                                           [self = RefPtr<MediaEncoder>(this)] {
    979                                             return self->GatherBlobImpl();
    980                                           });
    981 }
    982 
    983 auto MediaEncoder::GatherBlobImpl() -> RefPtr<BlobPromise> {
    984  RefPtr<BlobStorer> storer = MakeAndAddRef<BlobStorer>();
    985  MaybeCreateMutableBlobStorage();
    986  mMutableBlobStorage->GetBlobImplWhenReady(NS_ConvertUTF16toUTF8(mMimeType),
    987                                            storer);
    988  mMutableBlobStorage = nullptr;
    989 
    990  storer->Promise()->Then(
    991      mMainThread, __func__,
    992      [self = RefPtr<MediaEncoder>(this), p = storer->Promise()] {
    993        if (self->mBlobPromise == p) {
    994          // Reset BlobPromise.
    995          self->mBlobPromise = nullptr;
    996        }
    997      });
    998 
    999  return storer->Promise();
   1000 }
   1001 
   1002 void MediaEncoder::DisconnectTracks() {
   1003  MOZ_ASSERT(NS_IsMainThread());
   1004 
   1005  if (mAudioNode) {
   1006    mAudioNode->GetTrack()->RemoveListener(mAudioListener);
   1007    if (mInputPort) {
   1008      mInputPort->Destroy();
   1009      mInputPort = nullptr;
   1010    }
   1011    if (mPipeTrack) {
   1012      mPipeTrack->RemoveListener(mAudioListener);
   1013      mPipeTrack->Destroy();
   1014      mPipeTrack = nullptr;
   1015    }
   1016    mAudioNode = nullptr;
   1017  }
   1018 
   1019  if (mAudioTrack) {
   1020    RemoveMediaStreamTrack(mAudioTrack);
   1021  }
   1022 
   1023  if (mVideoTrack) {
   1024    RemoveMediaStreamTrack(mVideoTrack);
   1025  }
   1026 }
   1027 
   1028 bool MediaEncoder::IsWebMEncoderEnabled() {
   1029  return StaticPrefs::media_encoder_webm_enabled();
   1030 }
   1031 
   1032 void MediaEncoder::UpdateInitialized() {
   1033  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
   1034 
   1035  if (mInitialized) {
   1036    // This could happen if an encoder re-inits due to a resolution change.
   1037    return;
   1038  }
   1039 
   1040  if (mAudioEncoder && !mAudioEncoder->IsInitialized()) {
   1041    LOG(LogLevel::Debug,
   1042        ("MediaEncoder %p UpdateInitialized waiting for audio", this));
   1043    return;
   1044  }
   1045 
   1046  if (mVideoEncoder && !mVideoEncoder->IsInitialized()) {
   1047    LOG(LogLevel::Debug,
   1048        ("MediaEncoder %p UpdateInitialized waiting for video", this));
   1049    return;
   1050  }
   1051 
   1052  MOZ_ASSERT(mMuxer->NeedsMetadata());
   1053  nsTArray<RefPtr<TrackMetadataBase>> meta;
   1054  if (mAudioEncoder && !*meta.AppendElement(mAudioEncoder->GetMetadata())) {
   1055    LOG(LogLevel::Error, ("Audio metadata is null"));
   1056    SetError();
   1057    return;
   1058  }
   1059  if (mVideoEncoder && !*meta.AppendElement(mVideoEncoder->GetMetadata())) {
   1060    LOG(LogLevel::Error, ("Video metadata is null"));
   1061    SetError();
   1062    return;
   1063  }
   1064 
   1065  if (NS_FAILED(mMuxer->SetMetadata(meta))) {
   1066    LOG(LogLevel::Error, ("SetMetadata failed"));
   1067    SetError();
   1068    return;
   1069  }
   1070 
   1071  LOG(LogLevel::Info,
   1072      ("MediaEncoder %p UpdateInitialized set metadata in muxer", this));
   1073 
   1074  mInitialized = true;
   1075 }
   1076 
   1077 void MediaEncoder::UpdateStarted() {
   1078  MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
   1079 
   1080  if (mStarted) {
   1081    return;
   1082  }
   1083 
   1084  if (mAudioEncoder && !mAudioEncoder->IsStarted()) {
   1085    return;
   1086  }
   1087 
   1088  if (mVideoEncoder && !mVideoEncoder->IsStarted()) {
   1089    return;
   1090  }
   1091 
   1092  mStarted = true;
   1093 
   1094  // Start issuing timeslice-based blobs.
   1095  MOZ_ASSERT(mLastBlobTime == TimeUnit::Zero());
   1096 
   1097  mStartedEvent.Notify();
   1098 }
   1099 
   1100 /*
   1101 * SizeOfExcludingThis measures memory being used by the Media Encoder.
   1102 * Currently it measures the size of the Encoder buffer and memory occupied
   1103 * by mAudioEncoder, mVideoEncoder, and any current blob storage.
   1104 */
   1105 auto MediaEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
   1106    -> RefPtr<SizeOfPromise> {
   1107  MOZ_ASSERT(NS_IsMainThread());
   1108  size_t blobStorageSize =
   1109      mMutableBlobStorage ? mMutableBlobStorage->SizeOfCurrentMemoryBuffer()
   1110                          : 0;
   1111 
   1112  return InvokeAsync(
   1113      mEncoderThread, __func__,
   1114      [self = RefPtr<MediaEncoder>(this), this, blobStorageSize,
   1115       aMallocSizeOf]() {
   1116        size_t size = 0;
   1117        if (mAudioEncoder) {
   1118          size += mAudioEncoder->SizeOfExcludingThis(aMallocSizeOf);
   1119        }
   1120        if (mVideoEncoder) {
   1121          size += mVideoEncoder->SizeOfExcludingThis(aMallocSizeOf);
   1122        }
   1123        return SizeOfPromise::CreateAndResolve(blobStorageSize + size,
   1124                                               __func__);
   1125      });
   1126 }
   1127 
   1128 }  // namespace mozilla
   1129 
   1130 #undef LOG