tor-browser

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

RemoteMediaManagerParent.cpp (13007B)


      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 "RemoteMediaManagerParent.h"
      7 
      8 #if XP_WIN
      9 #  include <objbase.h>
     10 #endif
     11 
     12 #include "ImageContainer.h"
     13 #include "PDMFactory.h"
     14 #include "RemoteAudioDecoder.h"
     15 #include "RemoteCDMParent.h"
     16 #include "RemoteMediaDataEncoderParent.h"
     17 #include "RemoteVideoDecoder.h"
     18 #include "VideoUtils.h"  // for MediaThreadType
     19 #include "mozilla/RDDParent.h"
     20 #include "mozilla/RemoteDecodeUtils.h"
     21 #include "mozilla/SyncRunnable.h"
     22 #include "mozilla/gfx/GPUParent.h"
     23 #include "mozilla/ipc/Endpoint.h"
     24 #include "mozilla/ipc/UtilityProcessChild.h"
     25 #include "mozilla/layers/ImageDataSerializer.h"
     26 #include "mozilla/layers/VideoBridgeChild.h"
     27 #include "mozilla/layers/VideoBridgeParent.h"
     28 #include "nsIObserverService.h"
     29 
     30 #ifdef MOZ_WMF_MEDIA_ENGINE
     31 #  include "MFMediaEngineParent.h"
     32 #endif
     33 
     34 #ifdef MOZ_WMF_CDM
     35 #  include "MFCDMParent.h"
     36 #endif
     37 
     38 #ifdef MOZ_WIDGET_ANDROID
     39 #  include "mozilla/MediaDrmRemoteCDMParent.h"
     40 #endif
     41 
     42 namespace mozilla {
     43 
     44 #define LOG(msg, ...) \
     45  MOZ_LOG(gRemoteDecodeLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
     46 
     47 using namespace ipc;
     48 using namespace layers;
     49 using namespace gfx;
     50 
     51 StaticRefPtr<TaskQueue> sRemoteMediaManagerParentThread;
     52 
     53 void RemoteMediaManagerParent::StoreImage(const SurfaceDescriptorGPUVideo& aSD,
     54                                          Image* aImage,
     55                                          TextureClient* aTexture) {
     56  MOZ_ASSERT(OnManagerThread());
     57  mImageMap[static_cast<SurfaceDescriptorRemoteDecoder>(aSD).handle()] = aImage;
     58  mTextureMap[static_cast<SurfaceDescriptorRemoteDecoder>(aSD).handle()] =
     59      aTexture;
     60 }
     61 
     62 class RemoteDecoderManagerThreadShutdownObserver : public nsIObserver {
     63  virtual ~RemoteDecoderManagerThreadShutdownObserver() = default;
     64 
     65 public:
     66  RemoteDecoderManagerThreadShutdownObserver() = default;
     67 
     68  NS_DECL_ISUPPORTS
     69 
     70  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
     71                     const char16_t* aData) override {
     72    MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
     73 
     74    RemoteMediaManagerParent::ShutdownVideoBridge();
     75    RemoteMediaManagerParent::ShutdownThreads();
     76    return NS_OK;
     77  }
     78 };
     79 NS_IMPL_ISUPPORTS(RemoteDecoderManagerThreadShutdownObserver, nsIObserver);
     80 
     81 bool RemoteMediaManagerParent::StartupThreads() {
     82  MOZ_ASSERT(NS_IsMainThread());
     83 
     84  if (sRemoteMediaManagerParentThread) {
     85    return true;
     86  }
     87 
     88  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
     89  if (!observerService) {
     90    return false;
     91  }
     92 
     93  sRemoteMediaManagerParentThread = TaskQueue::Create(
     94      GetMediaThreadPool(MediaThreadType::SUPERVISOR), "RemVidParent");
     95  if (XRE_IsGPUProcess()) {
     96    MOZ_ALWAYS_SUCCEEDS(
     97        sRemoteMediaManagerParentThread->Dispatch(NS_NewRunnableFunction(
     98            "RemoteMediaManagerParent::StartupThreads",
     99            []() { layers::VideoBridgeChild::StartupForGPUProcess(); })));
    100  }
    101 
    102  auto* obs = new RemoteDecoderManagerThreadShutdownObserver();
    103  observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    104  return true;
    105 }
    106 
    107 void RemoteMediaManagerParent::ShutdownThreads() {
    108  sRemoteMediaManagerParentThread->BeginShutdown();
    109  sRemoteMediaManagerParentThread->AwaitShutdownAndIdle();
    110  sRemoteMediaManagerParentThread = nullptr;
    111 }
    112 
    113 /* static */
    114 void RemoteMediaManagerParent::ShutdownVideoBridge() {
    115  if (sRemoteMediaManagerParentThread) {
    116    RefPtr<Runnable> task =
    117        NS_NewRunnableFunction("RemoteMediaManagerParent::ShutdownVideoBridge",
    118                               []() { VideoBridgeChild::Shutdown(); });
    119    SyncRunnable::DispatchToThread(sRemoteMediaManagerParentThread, task);
    120  }
    121 }
    122 
    123 bool RemoteMediaManagerParent::OnManagerThread() {
    124  return sRemoteMediaManagerParentThread->IsOnCurrentThread();
    125 }
    126 
    127 /* static */
    128 void RemoteMediaManagerParent::Dispatch(
    129    already_AddRefed<nsIRunnable> aRunnable) {
    130  if (!sRemoteMediaManagerParentThread) {
    131    MOZ_DIAGNOSTIC_CRASH(
    132        "Dispatching after RemoteMediaManagerParent thread shutdown!");
    133    return;
    134  }
    135 
    136  MOZ_ALWAYS_SUCCEEDS(
    137      sRemoteMediaManagerParentThread->Dispatch(std::move(aRunnable)));
    138 }
    139 
    140 PDMFactory& RemoteMediaManagerParent::EnsurePDMFactory() {
    141  MOZ_ASSERT(OnManagerThread());
    142  if (!mPDMFactory) {
    143    mPDMFactory = MakeRefPtr<PDMFactory>();
    144  }
    145  return *mPDMFactory;
    146 }
    147 
    148 bool RemoteMediaManagerParent::CreateForContent(
    149    Endpoint<PRemoteMediaManagerParent>&& aEndpoint,
    150    dom::ContentParentId aChildId) {
    151  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_RDD ||
    152             XRE_GetProcessType() == GeckoProcessType_Utility ||
    153             XRE_GetProcessType() == GeckoProcessType_GPU);
    154  MOZ_ASSERT(NS_IsMainThread());
    155 
    156  if (!StartupThreads()) {
    157    return false;
    158  }
    159 
    160  RefPtr<RemoteMediaManagerParent> parent =
    161      new RemoteMediaManagerParent(sRemoteMediaManagerParentThread, aChildId);
    162 
    163  RefPtr<Runnable> task =
    164      NewRunnableMethod<Endpoint<PRemoteMediaManagerParent>&&>(
    165          "dom::RemoteMediaManagerParent::Open", parent,
    166          &RemoteMediaManagerParent::Open, std::move(aEndpoint));
    167  MOZ_ALWAYS_SUCCEEDS(sRemoteMediaManagerParentThread->Dispatch(task.forget()));
    168  return true;
    169 }
    170 
    171 bool RemoteMediaManagerParent::CreateVideoBridgeToOtherProcess(
    172    Endpoint<PVideoBridgeChild>&& aEndpoint) {
    173  LOG("Create video bridge");
    174  // We never want to decode in the GPU process, but output
    175  // frames to the parent process.
    176  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_RDD ||
    177             XRE_GetProcessType() == GeckoProcessType_Utility);
    178 #ifdef MOZ_WMF_MEDIA_ENGINE
    179  MOZ_ASSERT_IF(
    180      XRE_GetProcessType() == GeckoProcessType_Utility,
    181      GetCurrentSandboxingKind() == SandboxingKind::MF_MEDIA_ENGINE_CDM);
    182 #endif
    183  MOZ_ASSERT(NS_IsMainThread());
    184 
    185  if (!StartupThreads()) {
    186    return false;
    187  }
    188 
    189  RefPtr<Runnable> task =
    190      NewRunnableFunction("gfx::VideoBridgeChild::Open",
    191                          &VideoBridgeChild::Open, std::move(aEndpoint));
    192  MOZ_ALWAYS_SUCCEEDS(sRemoteMediaManagerParentThread->Dispatch(task.forget()));
    193  return true;
    194 }
    195 
    196 RemoteMediaManagerParent::RemoteMediaManagerParent(
    197    nsISerialEventTarget* aThread, dom::ContentParentId aContentId)
    198    : mThread(aThread), mContentId(aContentId) {
    199  MOZ_COUNT_CTOR(RemoteMediaManagerParent);
    200  auto& registrar =
    201      XRE_IsGPUProcess() ? GPUParent::GetSingleton()->AsyncShutdownService()
    202      : XRE_IsUtilityProcess()
    203          ? UtilityProcessChild::GetSingleton()->AsyncShutdownService()
    204          : RDDParent::GetSingleton()->AsyncShutdownService();
    205  registrar.Register(this);
    206 }
    207 
    208 RemoteMediaManagerParent::~RemoteMediaManagerParent() {
    209  MOZ_COUNT_DTOR(RemoteMediaManagerParent);
    210  auto& registrar =
    211      XRE_IsGPUProcess() ? GPUParent::GetSingleton()->AsyncShutdownService()
    212      : XRE_IsUtilityProcess()
    213          ? UtilityProcessChild::GetSingleton()->AsyncShutdownService()
    214          : RDDParent::GetSingleton()->AsyncShutdownService();
    215  registrar.Deregister(this);
    216 }
    217 
    218 void RemoteMediaManagerParent::ActorDestroy(
    219    mozilla::ipc::IProtocol::ActorDestroyReason) {
    220  mThread = nullptr;
    221 }
    222 
    223 PRemoteDecoderParent* RemoteMediaManagerParent::AllocPRemoteDecoderParent(
    224    const RemoteDecoderInfoIPDL& aRemoteDecoderInfo,
    225    const CreateDecoderParams::OptionSet& aOptions,
    226    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
    227    const Maybe<uint64_t>& aMediaEngineId, const Maybe<TrackingId>& aTrackingId,
    228    PRemoteCDMParent* aCDM) {
    229  RefPtr<TaskQueue> decodeTaskQueue =
    230      TaskQueue::Create(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
    231                        "RemoteVideoDecoderParent::mDecodeTaskQueue");
    232 
    233  auto* cdm = static_cast<RemoteCDMParent*>(aCDM);
    234 
    235  if (aRemoteDecoderInfo.type() ==
    236      RemoteDecoderInfoIPDL::TVideoDecoderInfoIPDL) {
    237    const VideoDecoderInfoIPDL& decoderInfo =
    238        aRemoteDecoderInfo.get_VideoDecoderInfoIPDL();
    239    return new RemoteVideoDecoderParent(
    240        this, decoderInfo.videoInfo(), decoderInfo.framerate(), aOptions,
    241        aIdentifier, sRemoteMediaManagerParentThread, decodeTaskQueue,
    242        aMediaEngineId, aTrackingId, cdm);
    243  }
    244 
    245  if (aRemoteDecoderInfo.type() == RemoteDecoderInfoIPDL::TAudioInfo) {
    246    return new RemoteAudioDecoderParent(
    247        this, aRemoteDecoderInfo.get_AudioInfo(), aOptions,
    248        sRemoteMediaManagerParentThread, decodeTaskQueue, aMediaEngineId, cdm);
    249  }
    250 
    251  MOZ_CRASH("unrecognized type of RemoteDecoderInfoIPDL union");
    252  return nullptr;
    253 }
    254 
    255 bool RemoteMediaManagerParent::DeallocPRemoteDecoderParent(
    256    PRemoteDecoderParent* actor) {
    257  RemoteDecoderParent* parent = static_cast<RemoteDecoderParent*>(actor);
    258  parent->Destroy();
    259  return true;
    260 }
    261 
    262 already_AddRefed<PRemoteEncoderParent>
    263 RemoteMediaManagerParent::AllocPRemoteEncoderParent(
    264    const EncoderConfig& aConfig) {
    265  return MakeAndAddRef<RemoteMediaDataEncoderParent>(aConfig);
    266 }
    267 
    268 PMFMediaEngineParent* RemoteMediaManagerParent::AllocPMFMediaEngineParent() {
    269 #ifdef MOZ_WMF_MEDIA_ENGINE
    270  return new MFMediaEngineParent(this, sRemoteMediaManagerParentThread);
    271 #else
    272  return nullptr;
    273 #endif
    274 }
    275 
    276 bool RemoteMediaManagerParent::DeallocPMFMediaEngineParent(
    277    PMFMediaEngineParent* actor) {
    278 #ifdef MOZ_WMF_MEDIA_ENGINE
    279  MFMediaEngineParent* parent = static_cast<MFMediaEngineParent*>(actor);
    280  parent->Destroy();
    281 #endif
    282  return true;
    283 }
    284 
    285 PMFCDMParent* RemoteMediaManagerParent::AllocPMFCDMParent(
    286    const nsAString& aKeySystem) {
    287 #ifdef MOZ_WMF_CDM
    288  return new MFCDMParent(aKeySystem, this, sRemoteMediaManagerParentThread);
    289 #else
    290  return nullptr;
    291 #endif
    292 }
    293 
    294 bool RemoteMediaManagerParent::DeallocPMFCDMParent(PMFCDMParent* actor) {
    295 #ifdef MOZ_WMF_CDM
    296  static_cast<MFCDMParent*>(actor)->Destroy();
    297 #endif
    298  return true;
    299 }
    300 
    301 PRemoteCDMParent* RemoteMediaManagerParent::AllocPRemoteCDMParent(
    302    const nsAString& aKeySystem) {
    303 #ifdef MOZ_WIDGET_ANDROID
    304  return new MediaDrmRemoteCDMParent(aKeySystem);
    305 #else
    306  return nullptr;
    307 #endif
    308 }
    309 
    310 void RemoteMediaManagerParent::Open(
    311    Endpoint<PRemoteMediaManagerParent>&& aEndpoint) {
    312  if (!aEndpoint.Bind(this)) {
    313    // We can't recover from this.
    314    MOZ_CRASH("Failed to bind RemoteMediaManagerParent to endpoint");
    315  }
    316 }
    317 
    318 mozilla::ipc::IPCResult RemoteMediaManagerParent::RecvReadback(
    319    const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) {
    320  const SurfaceDescriptorRemoteDecoder& sd = aSD;
    321  RefPtr<Image> image = mImageMap[sd.handle()];
    322  if (!image) {
    323    *aResult = null_t();
    324    return IPC_OK();
    325  }
    326 
    327  // Read directly into the shmem to avoid extra copies, if possible.
    328  SurfaceDescriptorBuffer sdb;
    329  nsresult rv = image->BuildSurfaceDescriptorBuffer(
    330      sdb, Image::BuildSdbFlags::RgbOnly, [&](uint32_t aBufferSize) {
    331        Shmem buffer;
    332        if (!AllocShmem(aBufferSize, &buffer)) {
    333          return MemoryOrShmem();
    334        }
    335        return MemoryOrShmem(std::move(buffer));
    336      });
    337 
    338  if (NS_SUCCEEDED(rv)) {
    339    *aResult = std::move(sdb);
    340    return IPC_OK();
    341  }
    342 
    343  if (sdb.data().type() == MemoryOrShmem::TShmem) {
    344    DeallocShmem(sdb.data().get_Shmem());
    345  }
    346  *aResult = null_t();
    347  return IPC_OK();
    348 }
    349 
    350 mozilla::ipc::IPCResult
    351 RemoteMediaManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(
    352    const SurfaceDescriptorGPUVideo& aSD) {
    353  MOZ_ASSERT(OnManagerThread());
    354  const SurfaceDescriptorRemoteDecoder& sd = aSD;
    355  mImageMap.erase(sd.handle());
    356  mTextureMap.erase(sd.handle());
    357  return IPC_OK();
    358 }
    359 
    360 mozilla::ipc::IPCResult RemoteMediaManagerParent::RecvOnSetCurrent(
    361    const SurfaceDescriptorGPUVideo& aSD) {
    362  MOZ_ASSERT(OnManagerThread());
    363  const SurfaceDescriptorRemoteDecoder& sd = aSD;
    364  RefPtr<Image> image = mImageMap[sd.handle()];
    365  if (!image) {
    366    return IPC_OK();
    367  }
    368 
    369  image->OnSetCurrent();
    370  return IPC_OK();
    371 }
    372 
    373 already_AddRefed<Image> RemoteMediaManagerParent::TransferToImage(
    374    const SurfaceDescriptorGPUVideo& aSD, const IntSize& aSize,
    375    const ColorDepth& aColorDepth, YUVColorSpace aYUVColorSpace,
    376    ColorSpace2 aColorPrimaries, TransferFunction aTransferFunction,
    377    ColorRange aColorRange) {
    378  MOZ_ASSERT(OnManagerThread());
    379  const SurfaceDescriptorRemoteDecoder& sd = aSD;
    380  const auto i = mImageMap.find(sd.handle());
    381  if (NS_WARN_IF(i == mImageMap.end())) {
    382    return nullptr;
    383  }
    384  return do_AddRef(i->second);
    385 }
    386 
    387 void RemoteMediaManagerParent::DeallocateSurfaceDescriptor(
    388    const SurfaceDescriptorGPUVideo& aSD) {
    389  if (!OnManagerThread()) {
    390    MOZ_ALWAYS_SUCCEEDS(
    391        sRemoteMediaManagerParentThread->Dispatch(NS_NewRunnableFunction(
    392            "RemoteMediaManagerParent::DeallocateSurfaceDescriptor",
    393            [ref = RefPtr{this}, sd = aSD]() {
    394              ref->RecvDeallocateSurfaceDescriptorGPUVideo(sd);
    395            })));
    396  } else {
    397    RecvDeallocateSurfaceDescriptorGPUVideo(aSD);
    398  }
    399 }
    400 
    401 #undef LOG
    402 
    403 }  // namespace mozilla