tor-browser

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

RemoteDecoderChild.cpp (10731B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 #include "RemoteDecoderChild.h"
      7 
      8 #include "RemoteMediaManagerChild.h"
      9 #include "mozilla/RemoteDecodeUtils.h"
     10 
     11 namespace mozilla {
     12 
     13 RemoteDecoderChild::RemoteDecoderChild(RemoteMediaIn aLocation)
     14    : ShmemRecycleAllocator(this),
     15      mLocation(aLocation),
     16      mThread(GetCurrentSerialEventTarget()) {
     17 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     18  auto managerThread = RemoteMediaManagerChild::GetManagerThread();
     19  MOZ_DIAGNOSTIC_ASSERT(managerThread);
     20  MOZ_DIAGNOSTIC_ASSERT(managerThread->IsOnCurrentThread());
     21 #endif
     22 }
     23 
     24 RemoteDecoderChild::~RemoteDecoderChild() = default;
     25 
     26 // ActorDestroy is called if the channel goes down while waiting for a response.
     27 void RemoteDecoderChild::ActorDestroy(ActorDestroyReason aWhy) {
     28  mRemoteDecoderCrashed = (aWhy == AbnormalShutdown);
     29  mDecodedData.Clear();
     30  CleanupShmemRecycleAllocator();
     31  RecordShutdownTelemetry(mRemoteDecoderCrashed);
     32 }
     33 
     34 void RemoteDecoderChild::DestroyIPDL() {
     35  AssertOnManagerThread();
     36  MOZ_DIAGNOSTIC_ASSERT(mInitPromise.IsEmpty() && mDecodePromise.IsEmpty() &&
     37                            mDrainPromise.IsEmpty() &&
     38                            mFlushPromise.IsEmpty() &&
     39                            mShutdownPromise.IsEmpty(),
     40                        "All promises should have been rejected");
     41  if (CanSend()) {
     42    PRemoteDecoderChild::Send__delete__(this);
     43  }
     44 }
     45 
     46 void RemoteDecoderChild::IPDLActorDestroyed() { mIPDLSelfRef = nullptr; }
     47 
     48 // MediaDataDecoder methods
     49 
     50 RefPtr<MediaDataDecoder::InitPromise> RemoteDecoderChild::Init() {
     51  AssertOnManagerThread();
     52 
     53  mRemoteDecoderCrashed = false;
     54 
     55  RefPtr<RemoteDecoderChild> self = this;
     56  SendInit()
     57      ->Then(
     58          mThread, __func__,
     59          [self, this](InitResultIPDL&& aResponse) {
     60            mInitPromiseRequest.Complete();
     61            if (aResponse.type() == InitResultIPDL::TMediaResult) {
     62              mInitPromise.Reject(aResponse.get_MediaResult(), __func__);
     63              return;
     64            }
     65            const auto& initResponse = aResponse.get_InitCompletionIPDL();
     66            mDescription = initResponse.decoderDescription();
     67            mDescription.Append(" (");
     68            mDescription.Append(RemoteMediaInToStr(GetManager()->Location()));
     69            mDescription.Append(" remote)");
     70 
     71            mProcessName = initResponse.decoderProcessName();
     72            mCodecName = initResponse.decoderCodecName();
     73 
     74            mIsHardwareAccelerated = initResponse.hardware();
     75            mHardwareAcceleratedReason = initResponse.hardwareReason();
     76            mConversion = initResponse.conversion();
     77            mShouldDecoderAlwaysBeRecycled =
     78                initResponse.shouldDecoderAlwaysBeRecycled();
     79            for (auto p : initResponse.decodeProperties()) {
     80              mDecodeProperties[p.name()] = Some(p.value());
     81            }
     82            // Either the promise has not yet been resolved or the handler has
     83            // been disconnected and we can't get here.
     84            mInitPromise.Resolve(initResponse.type(), __func__);
     85          },
     86          [self](const mozilla::ipc::ResponseRejectReason& aReason) {
     87            self->mInitPromiseRequest.Complete();
     88            RemoteMediaManagerChild::HandleRejectionError(
     89                self->GetManager(), self->mLocation, aReason,
     90                [self](const MediaResult& aError) {
     91                  self->mInitPromise.RejectIfExists(aError, __func__);
     92                });
     93          })
     94      ->Track(mInitPromiseRequest);
     95 
     96  return mInitPromise.Ensure(__func__);
     97 }
     98 
     99 RefPtr<MediaDataDecoder::DecodePromise> RemoteDecoderChild::Decode(
    100    const nsTArray<RefPtr<MediaRawData>>& aSamples) {
    101  AssertOnManagerThread();
    102 
    103  if (mRemoteDecoderCrashed) {
    104    nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR;
    105    if (mLocation == RemoteMediaIn::GpuProcess ||
    106        mLocation == RemoteMediaIn::RddProcess) {
    107      err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR;
    108    } else if (mLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) {
    109      err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR;
    110    }
    111    return MediaDataDecoder::DecodePromise::CreateAndReject(err, __func__);
    112  }
    113 
    114  auto samples = MakeRefPtr<ArrayOfRemoteMediaRawData>();
    115  if (!samples->Fill(aSamples,
    116                     [&](size_t aSize) { return AllocateBuffer(aSize); })) {
    117    return MediaDataDecoder::DecodePromise::CreateAndReject(
    118        NS_ERROR_OUT_OF_MEMORY, __func__);
    119  }
    120  SendDecode(samples)->Then(
    121      mThread, __func__,
    122      [self = RefPtr{this}, this](
    123          PRemoteDecoderChild::DecodePromise::ResolveOrRejectValue&& aValue) {
    124        // We no longer need the samples as the data has been
    125        // processed by the parent.
    126        // If the parent died, the error being fatal will cause the
    127        // decoder to be torn down and all shmem in the pool will be
    128        // deallocated.
    129        ReleaseAllBuffers();
    130 
    131        if (aValue.IsReject()) {
    132          RemoteMediaManagerChild::HandleRejectionError(
    133              self->GetManager(), self->mLocation, aValue.RejectValue(),
    134              [self](const MediaResult& aError) {
    135                self->mDecodePromise.RejectIfExists(aError, __func__);
    136              });
    137          return;
    138        }
    139        MOZ_DIAGNOSTIC_ASSERT(CanSend(),
    140                              "The parent unexpectedly died, promise should "
    141                              "have been rejected first");
    142        if (mDecodePromise.IsEmpty()) {
    143          // We got flushed.
    144          return;
    145        }
    146        auto response = std::move(aValue.ResolveValue());
    147        if (response.type() == DecodeResultIPDL::TMediaResult &&
    148            NS_FAILED(response.get_MediaResult())) {
    149          mDecodePromise.Reject(response.get_MediaResult(), __func__);
    150          return;
    151        }
    152        if (response.type() == DecodeResultIPDL::TDecodedOutputIPDL) {
    153          ProcessOutput(std::move(response.get_DecodedOutputIPDL()));
    154        }
    155        mDecodePromise.Resolve(std::move(mDecodedData), __func__);
    156        mDecodedData = MediaDataDecoder::DecodedData();
    157      });
    158 
    159  return mDecodePromise.Ensure(__func__);
    160 }
    161 
    162 RefPtr<MediaDataDecoder::FlushPromise> RemoteDecoderChild::Flush() {
    163  AssertOnManagerThread();
    164  mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    165  mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    166 
    167  RefPtr<RemoteDecoderChild> self = this;
    168  SendFlush()->Then(
    169      mThread, __func__,
    170      [self](const MediaResult& aResult) {
    171        if (NS_SUCCEEDED(aResult)) {
    172          self->mFlushPromise.ResolveIfExists(true, __func__);
    173        } else {
    174          self->mFlushPromise.RejectIfExists(aResult, __func__);
    175        }
    176      },
    177      [self](const mozilla::ipc::ResponseRejectReason& aReason) {
    178        RemoteMediaManagerChild::HandleRejectionError(
    179            self->GetManager(), self->mLocation, aReason,
    180            [self](const MediaResult& aError) {
    181              self->mFlushPromise.RejectIfExists(aError, __func__);
    182            });
    183      });
    184  return mFlushPromise.Ensure(__func__);
    185 }
    186 
    187 RefPtr<MediaDataDecoder::DecodePromise> RemoteDecoderChild::Drain() {
    188  AssertOnManagerThread();
    189 
    190  RefPtr<RemoteDecoderChild> self = this;
    191  SendDrain()->Then(
    192      mThread, __func__,
    193      [self, this](DecodeResultIPDL&& aResponse) {
    194        if (mDrainPromise.IsEmpty()) {
    195          // We got flushed.
    196          return;
    197        }
    198        if (aResponse.type() == DecodeResultIPDL::TMediaResult &&
    199            NS_FAILED(aResponse.get_MediaResult())) {
    200          mDrainPromise.Reject(aResponse.get_MediaResult(), __func__);
    201          return;
    202        }
    203        MOZ_DIAGNOSTIC_ASSERT(CanSend(),
    204                              "The parent unexpectedly died, promise should "
    205                              "have been rejected first");
    206        if (aResponse.type() == DecodeResultIPDL::TDecodedOutputIPDL) {
    207          ProcessOutput(std::move(aResponse.get_DecodedOutputIPDL()));
    208        }
    209        mDrainPromise.Resolve(std::move(mDecodedData), __func__);
    210        mDecodedData = MediaDataDecoder::DecodedData();
    211      },
    212      [self](const mozilla::ipc::ResponseRejectReason& aReason) {
    213        RemoteMediaManagerChild::HandleRejectionError(
    214            self->GetManager(), self->mLocation, aReason,
    215            [self](const MediaResult& aError) {
    216              self->mDrainPromise.RejectIfExists(aError, __func__);
    217            });
    218      });
    219  return mDrainPromise.Ensure(__func__);
    220 }
    221 
    222 RefPtr<mozilla::ShutdownPromise> RemoteDecoderChild::Shutdown() {
    223  AssertOnManagerThread();
    224  // Shutdown() can be called while an InitPromise is pending.
    225  mInitPromiseRequest.DisconnectIfExists();
    226  mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    227  mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    228  mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    229  mFlushPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
    230 
    231  RefPtr<RemoteDecoderChild> self = this;
    232  SendShutdown()->Then(
    233      mThread, __func__,
    234      [self](
    235          PRemoteDecoderChild::ShutdownPromise::ResolveOrRejectValue&& aValue) {
    236        self->mShutdownPromise.Resolve(aValue.IsResolve(), __func__);
    237      });
    238  return mShutdownPromise.Ensure(__func__);
    239 }
    240 
    241 bool RemoteDecoderChild::IsHardwareAccelerated(
    242    nsACString& aFailureReason) const {
    243  AssertOnManagerThread();
    244  aFailureReason = mHardwareAcceleratedReason;
    245  return mIsHardwareAccelerated;
    246 }
    247 
    248 nsCString RemoteDecoderChild::GetDescriptionName() const {
    249  AssertOnManagerThread();
    250  return mDescription;
    251 }
    252 
    253 nsCString RemoteDecoderChild::GetProcessName() const {
    254  AssertOnManagerThread();
    255  return mProcessName;
    256 }
    257 
    258 nsCString RemoteDecoderChild::GetCodecName() const {
    259  AssertOnManagerThread();
    260  return mCodecName;
    261 }
    262 
    263 void RemoteDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime) {
    264  AssertOnManagerThread();
    265  (void)SendSetSeekThreshold(aTime);
    266 }
    267 
    268 MediaDataDecoder::ConversionRequired RemoteDecoderChild::NeedsConversion()
    269    const {
    270  AssertOnManagerThread();
    271  return mConversion;
    272 }
    273 
    274 bool RemoteDecoderChild::ShouldDecoderAlwaysBeRecycled() const {
    275  AssertOnManagerThread();
    276  return mShouldDecoderAlwaysBeRecycled;
    277 }
    278 
    279 void RemoteDecoderChild::AssertOnManagerThread() const {
    280  MOZ_ASSERT(mThread->IsOnCurrentThread());
    281 }
    282 
    283 RemoteMediaManagerChild* RemoteDecoderChild::GetManager() {
    284  if (!CanSend()) {
    285    return nullptr;
    286  }
    287  return static_cast<RemoteMediaManagerChild*>(Manager());
    288 }
    289 
    290 }  // namespace mozilla