tor-browser

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

GMPVideoDecoderChild.cpp (6890B)


      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
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "GMPVideoDecoderChild.h"
      7 
      8 #include "GMPContentChild.h"
      9 #include "GMPPlatform.h"
     10 #include "GMPVideoEncodedFrameImpl.h"
     11 #include "GMPVideoi420FrameImpl.h"
     12 #include "mozilla/StaticPrefs_media.h"
     13 #include "runnable_utils.h"
     14 
     15 namespace mozilla::gmp {
     16 
     17 GMPVideoDecoderChild::GMPVideoDecoderChild(GMPContentChild* aPlugin)
     18    : mPlugin(aPlugin), mVideoDecoder(nullptr), mVideoHost(this) {
     19  MOZ_ASSERT(mPlugin);
     20 }
     21 
     22 GMPVideoDecoderChild::~GMPVideoDecoderChild() = default;
     23 
     24 bool GMPVideoDecoderChild::MgrIsOnOwningThread() const {
     25  return !mPlugin || mPlugin->GMPMessageLoop() == MessageLoop::current();
     26 }
     27 
     28 void GMPVideoDecoderChild::Init(GMPVideoDecoder* aDecoder) {
     29  MOZ_ASSERT(aDecoder,
     30             "Cannot initialize video decoder child without a video decoder!");
     31  mVideoDecoder = aDecoder;
     32 }
     33 
     34 GMPVideoHostImpl& GMPVideoDecoderChild::Host() { return mVideoHost; }
     35 
     36 void GMPVideoDecoderChild::Decoded(GMPVideoi420Frame* aDecodedFrame) {
     37  if (!aDecodedFrame) {
     38    MOZ_CRASH("Not given a decoded frame!");
     39  }
     40 
     41  if (NS_WARN_IF(!mPlugin)) {
     42    aDecodedFrame->Destroy();
     43    return;
     44  }
     45 
     46  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
     47 
     48  auto df = static_cast<GMPVideoi420FrameImpl*>(aDecodedFrame);
     49 
     50  if (GMPSharedMemManager* memMgr = mVideoHost.SharedMemMgr()) {
     51    ipc::Shmem inputShmem;
     52    if (memMgr->MgrTakeShmem(GMPSharedMemClass::Encoded, &inputShmem)) {
     53      (void)SendReturnShmem(std::move(inputShmem));
     54    }
     55  }
     56 
     57  GMPVideoi420FrameData frameData;
     58  ipc::Shmem frameShmem;
     59  nsTArray<uint8_t> frameArray;
     60 
     61  if (df->InitFrameData(frameData, frameShmem)) {
     62    (void)SendDecodedShmem(frameData, std::move(frameShmem));
     63  } else if (df->InitFrameData(frameData, frameArray)) {
     64    (void)SendDecodedData(frameData, std::move(frameArray));
     65  } else {
     66    MOZ_CRASH("Decoded without any frame data!");
     67  }
     68 
     69  aDecodedFrame->Destroy();
     70 }
     71 
     72 void GMPVideoDecoderChild::ReceivedDecodedReferenceFrame(
     73    const uint64_t aPictureId) {
     74  if (NS_WARN_IF(!mPlugin)) {
     75    return;
     76  }
     77 
     78  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
     79 
     80  SendReceivedDecodedReferenceFrame(aPictureId);
     81 }
     82 
     83 void GMPVideoDecoderChild::ReceivedDecodedFrame(const uint64_t aPictureId) {
     84  if (NS_WARN_IF(!mPlugin)) {
     85    return;
     86  }
     87 
     88  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
     89 
     90  SendReceivedDecodedFrame(aPictureId);
     91 }
     92 
     93 void GMPVideoDecoderChild::InputDataExhausted() {
     94  if (NS_WARN_IF(!mPlugin)) {
     95    return;
     96  }
     97 
     98  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
     99 
    100  SendInputDataExhausted();
    101 }
    102 
    103 void GMPVideoDecoderChild::DrainComplete() {
    104  MOZ_ASSERT(mOutstandingDrain, "DrainComplete without Drain!");
    105  mOutstandingDrain = false;
    106 
    107  if (NS_WARN_IF(!mPlugin)) {
    108    return;
    109  }
    110 
    111  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
    112 
    113  SendDrainComplete();
    114 }
    115 
    116 void GMPVideoDecoderChild::ResetComplete() {
    117  MOZ_ASSERT(mOutstandingReset, "ResetComplete without Reset!");
    118  mOutstandingReset = false;
    119 
    120  if (NS_WARN_IF(!mPlugin)) {
    121    return;
    122  }
    123 
    124  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
    125 
    126  SendResetComplete();
    127 }
    128 
    129 void GMPVideoDecoderChild::Error(GMPErr aError) {
    130  if (NS_WARN_IF(!mPlugin)) {
    131    return;
    132  }
    133 
    134  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
    135 
    136  SendError(aError);
    137 }
    138 
    139 mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvInitDecode(
    140    const GMPVideoCodec& aCodecSettings, nsTArray<uint8_t>&& aCodecSpecific,
    141    const int32_t& aCoreCount) {
    142  if (!mVideoDecoder) {
    143    return IPC_FAIL(this, "!mVideoDecoder");
    144  }
    145 
    146  // Ignore any return code. It is OK for this to fail without killing the
    147  // process.
    148  mVideoDecoder->InitDecode(aCodecSettings, aCodecSpecific.Elements(),
    149                            aCodecSpecific.Length(), this, aCoreCount);
    150  return IPC_OK();
    151 }
    152 
    153 mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvGiveShmem(
    154    ipc::Shmem&& aOutputShmem) {
    155  if (GMPSharedMemManager* memMgr = mVideoHost.SharedMemMgr()) {
    156    memMgr->MgrGiveShmem(GMPSharedMemClass::Decoded, std::move(aOutputShmem));
    157  } else {
    158    DeallocShmem(aOutputShmem);
    159  }
    160 
    161  return IPC_OK();
    162 }
    163 
    164 mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvDecode(
    165    const GMPVideoEncodedFrameData& aInputFrame, ipc::Shmem&& aInputShmem,
    166    const bool& aMissingFrames, nsTArray<uint8_t>&& aCodecSpecificInfo,
    167    const int64_t& aRenderTimeMs) {
    168  if (!mVideoDecoder) {
    169    DeallocShmem(aInputShmem);
    170    return IPC_FAIL(this, "!mVideoDecoder");
    171  }
    172 
    173  auto* f = new GMPVideoEncodedFrameImpl(aInputFrame, std::move(aInputShmem),
    174                                         &mVideoHost);
    175 
    176  // Ignore any return code. It is OK for this to fail without killing the
    177  // process.
    178  mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo.Elements(),
    179                        aCodecSpecificInfo.Length(), aRenderTimeMs);
    180 
    181  return IPC_OK();
    182 }
    183 
    184 mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvReset() {
    185  if (!mVideoDecoder) {
    186    return IPC_FAIL(this, "!mVideoDecoder");
    187  }
    188 
    189  if (mOutstandingReset) {
    190    MOZ_ASSERT_UNREACHABLE("Already has outstanding reset!");
    191    return IPC_OK();
    192  }
    193 
    194  // Ignore any return code. It is OK for this to fail without killing the
    195  // process.
    196  mOutstandingReset = true;
    197  mVideoDecoder->Reset();
    198 
    199  return IPC_OK();
    200 }
    201 
    202 mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvDrain() {
    203  if (!mVideoDecoder) {
    204    return IPC_FAIL(this, "!mVideoDecoder");
    205  }
    206 
    207  if (mOutstandingDrain) {
    208    MOZ_ASSERT_UNREACHABLE("Already has outstanding drain!");
    209    return IPC_OK();
    210  }
    211 
    212  // Ignore any return code. It is OK for this to fail without killing the
    213  // process.
    214  mOutstandingDrain = true;
    215  mVideoDecoder->Drain();
    216 
    217  return IPC_OK();
    218 }
    219 
    220 void GMPVideoDecoderChild::ActorDestroy(ActorDestroyReason why) {
    221  // If there are no encoded frames, then we know that OpenH264 has destroyed
    222  // any outstanding references to its pending decode frames. This means it
    223  // should be safe to destroy the decoder since there should not be any pending
    224  // sync callbacks.
    225  if (!SpinPendingGmpEventsUntil(
    226          [&]() -> bool {
    227            return mOutstandingDrain || mOutstandingReset ||
    228                   mVideoHost.IsEncodedFramesEmpty();
    229          },
    230          StaticPrefs::media_gmp_coder_shutdown_timeout_ms())) {
    231    NS_WARNING("Timed out waiting for synchronous events!");
    232  }
    233 
    234  if (mVideoDecoder) {
    235    // Ignore any return code. It is OK for this to fail without killing the
    236    // process.
    237    mVideoDecoder->DecodingComplete();
    238    mVideoDecoder = nullptr;
    239  }
    240 
    241  mVideoHost.DoneWithAPI();
    242 
    243  mPlugin = nullptr;
    244 }
    245 
    246 }  // namespace mozilla::gmp