/src/mozilla-central/dom/media/ipc/VideoDecoderManagerParent.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=99: */ |
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 "VideoDecoderManagerParent.h" |
7 | | #include "VideoDecoderParent.h" |
8 | | #include "VideoUtils.h" |
9 | | #include "base/thread.h" |
10 | | #include "mozilla/UniquePtr.h" |
11 | | #include "mozilla/Services.h" |
12 | | #include "mozilla/Observer.h" |
13 | | #include "nsIObserverService.h" |
14 | | #include "nsIObserver.h" |
15 | | #include "nsIEventTarget.h" |
16 | | #include "nsThreadUtils.h" |
17 | | #include "ImageContainer.h" |
18 | | #include "mozilla/layers/VideoBridgeChild.h" |
19 | | #include "mozilla/layers/ImageDataSerializer.h" |
20 | | #include "mozilla/SyncRunnable.h" |
21 | | |
22 | | #if XP_WIN |
23 | | #include <objbase.h> |
24 | | #endif |
25 | | |
26 | | namespace mozilla { |
27 | | |
28 | | #ifdef XP_WIN |
29 | | extern const nsCString GetFoundD3D11BlacklistedDLL(); |
30 | | extern const nsCString GetFoundD3D9BlacklistedDLL(); |
31 | | #endif // XP_WIN |
32 | | |
33 | | namespace dom { |
34 | | |
35 | | using namespace ipc; |
36 | | using namespace layers; |
37 | | using namespace gfx; |
38 | | |
39 | | SurfaceDescriptorGPUVideo |
40 | | VideoDecoderManagerParent::StoreImage(Image* aImage, TextureClient* aTexture) |
41 | 0 | { |
42 | 0 | SurfaceDescriptorGPUVideo ret; |
43 | 0 | aTexture->GPUVideoDesc(&ret); |
44 | 0 |
|
45 | 0 | mImageMap[ret.handle()] = aImage; |
46 | 0 | mTextureMap[ret.handle()] = aTexture; |
47 | 0 | return ret; |
48 | 0 | } |
49 | | |
50 | | StaticRefPtr<nsIThread> sVideoDecoderManagerThread; |
51 | | StaticRefPtr<TaskQueue> sManagerTaskQueue; |
52 | | |
53 | | class VideoDecoderManagerThreadHolder |
54 | | { |
55 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerThreadHolder) |
56 | | |
57 | | public: |
58 | 0 | VideoDecoderManagerThreadHolder() { } |
59 | | |
60 | | private: |
61 | | ~VideoDecoderManagerThreadHolder() |
62 | 0 | { |
63 | 0 | NS_DispatchToMainThread(NS_NewRunnableFunction( |
64 | 0 | "dom::VideoDecoderManagerThreadHolder::~VideoDecoderManagerThreadHolder", |
65 | 0 | []() -> void { |
66 | 0 | sVideoDecoderManagerThread->Shutdown(); |
67 | 0 | sVideoDecoderManagerThread = nullptr; |
68 | 0 | })); |
69 | 0 | } |
70 | | }; |
71 | | StaticRefPtr<VideoDecoderManagerThreadHolder> sVideoDecoderManagerThreadHolder; |
72 | | |
73 | | class ManagerThreadShutdownObserver : public nsIObserver |
74 | | { |
75 | 0 | virtual ~ManagerThreadShutdownObserver() = default; |
76 | | public: |
77 | 0 | ManagerThreadShutdownObserver() { } |
78 | | |
79 | | NS_DECL_ISUPPORTS |
80 | | |
81 | | NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, |
82 | | const char16_t* aData) override |
83 | 0 | { |
84 | 0 | MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); |
85 | 0 |
|
86 | 0 | VideoDecoderManagerParent::ShutdownThreads(); |
87 | 0 | return NS_OK; |
88 | 0 | } |
89 | | }; |
90 | | NS_IMPL_ISUPPORTS(ManagerThreadShutdownObserver, nsIObserver); |
91 | | |
92 | | void |
93 | | VideoDecoderManagerParent::StartupThreads() |
94 | 0 | { |
95 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
96 | 0 |
|
97 | 0 | if (sVideoDecoderManagerThread) { |
98 | 0 | return; |
99 | 0 | } |
100 | 0 | |
101 | 0 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
102 | 0 | if (!observerService) { |
103 | 0 | return; |
104 | 0 | } |
105 | 0 | |
106 | 0 | RefPtr<nsIThread> managerThread; |
107 | 0 | nsresult rv = NS_NewNamedThread("VideoParent", getter_AddRefs(managerThread)); |
108 | 0 | if (NS_FAILED(rv)) { |
109 | 0 | return; |
110 | 0 | } |
111 | 0 | sVideoDecoderManagerThread = managerThread; |
112 | 0 | sVideoDecoderManagerThreadHolder = new VideoDecoderManagerThreadHolder(); |
113 | | #if XP_WIN |
114 | | sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction("VideoDecoderManagerParent::StartupThreads", |
115 | | []() { |
116 | | DebugOnly<HRESULT> hr = CoInitializeEx(0, COINIT_MULTITHREADED); |
117 | | MOZ_ASSERT(hr == S_OK); |
118 | | }), NS_DISPATCH_NORMAL); |
119 | | #endif |
120 | | sVideoDecoderManagerThread->Dispatch( |
121 | 0 | NS_NewRunnableFunction("dom::VideoDecoderManagerParent::StartupThreads", |
122 | 0 | []() { layers::VideoBridgeChild::Startup(); }), |
123 | 0 | NS_DISPATCH_NORMAL); |
124 | 0 |
|
125 | 0 | sManagerTaskQueue = new TaskQueue( |
126 | 0 | managerThread.forget(), "VideoDecoderManagerParent::sManagerTaskQueue"); |
127 | 0 |
|
128 | 0 | auto* obs = new ManagerThreadShutdownObserver(); |
129 | 0 | observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); |
130 | 0 | } |
131 | | |
132 | | void |
133 | | VideoDecoderManagerParent::ShutdownThreads() |
134 | 0 | { |
135 | 0 | sManagerTaskQueue->BeginShutdown(); |
136 | 0 | sManagerTaskQueue->AwaitShutdownAndIdle(); |
137 | 0 | sManagerTaskQueue = nullptr; |
138 | 0 |
|
139 | 0 | sVideoDecoderManagerThreadHolder = nullptr; |
140 | 0 | while (sVideoDecoderManagerThread) { |
141 | 0 | NS_ProcessNextEvent(nullptr, true); |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | | void |
146 | | VideoDecoderManagerParent::ShutdownVideoBridge() |
147 | 0 | { |
148 | 0 | if (sVideoDecoderManagerThread) { |
149 | 0 | RefPtr<Runnable> task = NS_NewRunnableFunction( |
150 | 0 | "dom::VideoDecoderManagerParent::ShutdownVideoBridge", |
151 | 0 | []() { VideoBridgeChild::Shutdown(); }); |
152 | 0 | SyncRunnable::DispatchToThread(sVideoDecoderManagerThread, task); |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | | bool |
157 | | VideoDecoderManagerParent::OnManagerThread() |
158 | 0 | { |
159 | 0 | return NS_GetCurrentThread() == sVideoDecoderManagerThread; |
160 | 0 | } |
161 | | |
162 | | bool |
163 | | VideoDecoderManagerParent::CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) |
164 | 0 | { |
165 | 0 | MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU); |
166 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
167 | 0 |
|
168 | 0 | StartupThreads(); |
169 | 0 | if (!sVideoDecoderManagerThread) { |
170 | 0 | return false; |
171 | 0 | } |
172 | 0 | |
173 | 0 | RefPtr<VideoDecoderManagerParent> parent = |
174 | 0 | new VideoDecoderManagerParent(sVideoDecoderManagerThreadHolder); |
175 | 0 |
|
176 | 0 | RefPtr<Runnable> task = |
177 | 0 | NewRunnableMethod<Endpoint<PVideoDecoderManagerParent>&&>( |
178 | 0 | "dom::VideoDecoderManagerParent::Open", |
179 | 0 | parent, |
180 | 0 | &VideoDecoderManagerParent::Open, |
181 | 0 | std::move(aEndpoint)); |
182 | 0 | sVideoDecoderManagerThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL); |
183 | 0 | return true; |
184 | 0 | } |
185 | | |
186 | | VideoDecoderManagerParent::VideoDecoderManagerParent(VideoDecoderManagerThreadHolder* aHolder) |
187 | | : mThreadHolder(aHolder) |
188 | 0 | { |
189 | 0 | MOZ_COUNT_CTOR(VideoDecoderManagerParent); |
190 | 0 | } |
191 | | |
192 | | VideoDecoderManagerParent::~VideoDecoderManagerParent() |
193 | 0 | { |
194 | 0 | MOZ_COUNT_DTOR(VideoDecoderManagerParent); |
195 | 0 | } |
196 | | |
197 | | void |
198 | | VideoDecoderManagerParent::ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) |
199 | 0 | { |
200 | 0 | mThreadHolder = nullptr; |
201 | 0 | } |
202 | | |
203 | | PVideoDecoderParent* |
204 | | VideoDecoderManagerParent::AllocPVideoDecoderParent(const VideoInfo& aVideoInfo, |
205 | | const float& aFramerate, |
206 | | const layers::TextureFactoryIdentifier& aIdentifier, |
207 | | bool* aSuccess, |
208 | | nsCString* aBlacklistedD3D11Driver, |
209 | | nsCString* aBlacklistedD3D9Driver, |
210 | | nsCString* aErrorDescription) |
211 | 0 | { |
212 | 0 | RefPtr<TaskQueue> decodeTaskQueue = new TaskQueue( |
213 | 0 | GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER), |
214 | 0 | "VideoDecoderParent::mDecodeTaskQueue"); |
215 | 0 |
|
216 | 0 | auto* parent = new VideoDecoderParent( |
217 | 0 | this, aVideoInfo, aFramerate, aIdentifier, |
218 | 0 | sManagerTaskQueue, decodeTaskQueue, aSuccess, aErrorDescription); |
219 | 0 |
|
220 | | #ifdef XP_WIN |
221 | | *aBlacklistedD3D11Driver = GetFoundD3D11BlacklistedDLL(); |
222 | | *aBlacklistedD3D9Driver = GetFoundD3D9BlacklistedDLL(); |
223 | | #endif // XP_WIN |
224 | |
|
225 | 0 | return parent; |
226 | 0 | } |
227 | | |
228 | | bool |
229 | | VideoDecoderManagerParent::DeallocPVideoDecoderParent(PVideoDecoderParent* actor) |
230 | 0 | { |
231 | 0 | VideoDecoderParent* parent = static_cast<VideoDecoderParent*>(actor); |
232 | 0 | parent->Destroy(); |
233 | 0 | return true; |
234 | 0 | } |
235 | | |
236 | | void |
237 | | VideoDecoderManagerParent::Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) |
238 | 0 | { |
239 | 0 | if (!aEndpoint.Bind(this)) { |
240 | 0 | // We can't recover from this. |
241 | 0 | MOZ_CRASH("Failed to bind VideoDecoderManagerParent to endpoint"); |
242 | 0 | } |
243 | 0 | AddRef(); |
244 | 0 | } |
245 | | |
246 | | void |
247 | | VideoDecoderManagerParent::DeallocPVideoDecoderManagerParent() |
248 | 0 | { |
249 | 0 | Release(); |
250 | 0 | } |
251 | | |
252 | | mozilla::ipc::IPCResult |
253 | | VideoDecoderManagerParent::RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) |
254 | 0 | { |
255 | 0 | RefPtr<Image> image = mImageMap[aSD.handle()]; |
256 | 0 | if (!image) { |
257 | 0 | *aResult = null_t(); |
258 | 0 | return IPC_OK(); |
259 | 0 | } |
260 | 0 |
|
261 | 0 | RefPtr<SourceSurface> source = image->GetAsSourceSurface(); |
262 | 0 | if (!source) { |
263 | 0 | *aResult = null_t(); |
264 | 0 | return IPC_OK(); |
265 | 0 | } |
266 | 0 |
|
267 | 0 | SurfaceFormat format = source->GetFormat(); |
268 | 0 | IntSize size = source->GetSize(); |
269 | 0 | size_t length = ImageDataSerializer::ComputeRGBBufferSize(size, format); |
270 | 0 |
|
271 | 0 | Shmem buffer; |
272 | 0 | if (!length || !AllocShmem(length, Shmem::SharedMemory::TYPE_BASIC, &buffer)) { |
273 | 0 | *aResult = null_t(); |
274 | 0 | return IPC_OK(); |
275 | 0 | } |
276 | 0 |
|
277 | 0 | RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO, |
278 | 0 | buffer.get<uint8_t>(), size, |
279 | 0 | ImageDataSerializer::ComputeRGBStride(format, size.width), |
280 | 0 | format); |
281 | 0 | if (!dt) { |
282 | 0 | DeallocShmem(buffer); |
283 | 0 | *aResult = null_t(); |
284 | 0 | return IPC_OK(); |
285 | 0 | } |
286 | 0 |
|
287 | 0 | dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint()); |
288 | 0 | dt->Flush(); |
289 | 0 |
|
290 | 0 | *aResult = SurfaceDescriptorBuffer(RGBDescriptor(size, format, true), MemoryOrShmem(buffer)); |
291 | 0 | return IPC_OK(); |
292 | 0 | } |
293 | | |
294 | | mozilla::ipc::IPCResult |
295 | | VideoDecoderManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) |
296 | 0 | { |
297 | 0 | mImageMap.erase(aSD.handle()); |
298 | 0 | mTextureMap.erase(aSD.handle()); |
299 | 0 | return IPC_OK(); |
300 | 0 | } |
301 | | |
302 | | } // namespace dom |
303 | | } // namespace mozilla |