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