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