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 "VideoDecoderManagerChild.h"
7 : #include "VideoDecoderChild.h"
8 : #include "mozilla/dom/ContentChild.h"
9 : #include "MediaPrefs.h"
10 : #include "nsThreadUtils.h"
11 : #include "mozilla/gfx/2D.h"
12 : #include "mozilla/ipc/ProtocolUtils.h"
13 : #include "mozilla/layers/SynchronousTask.h"
14 : #include "mozilla/gfx/DataSurfaceHelpers.h"
15 : #include "mozilla/layers/ISurfaceAllocator.h"
16 : #include "base/task.h"
17 :
18 : namespace mozilla {
19 : namespace dom {
20 :
21 : using namespace ipc;
22 : using namespace layers;
23 : using namespace gfx;
24 :
25 : // Only modified on the main-thread
26 3 : StaticRefPtr<nsIThread> sVideoDecoderChildThread;
27 3 : StaticRefPtr<AbstractThread> sVideoDecoderChildAbstractThread;
28 :
29 : // Only accessed from sVideoDecoderChildThread
30 3 : static StaticRefPtr<VideoDecoderManagerChild> sDecoderManager;
31 3 : static UniquePtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks;
32 :
33 : /* static */ void
34 2 : VideoDecoderManagerChild::InitializeThread()
35 : {
36 2 : MOZ_ASSERT(NS_IsMainThread());
37 :
38 2 : if (!sVideoDecoderChildThread) {
39 4 : RefPtr<nsIThread> childThread;
40 2 : nsresult rv = NS_NewNamedThread("VideoChild", getter_AddRefs(childThread));
41 2 : NS_ENSURE_SUCCESS_VOID(rv);
42 2 : sVideoDecoderChildThread = childThread;
43 :
44 : sVideoDecoderChildAbstractThread =
45 2 : AbstractThread::CreateXPCOMThreadWrapper(childThread, false);
46 :
47 2 : sRecreateTasks = MakeUnique<nsTArray<RefPtr<Runnable>>>();
48 : }
49 : }
50 :
51 : /* static */ void
52 2 : VideoDecoderManagerChild::InitForContent(Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
53 : {
54 2 : InitializeThread();
55 2 : sVideoDecoderChildThread->Dispatch(NewRunnableFunction(&Open, Move(aVideoManager)), NS_DISPATCH_NORMAL);
56 2 : }
57 :
58 : /* static */ void
59 0 : VideoDecoderManagerChild::Shutdown()
60 : {
61 0 : MOZ_ASSERT(NS_IsMainThread());
62 :
63 0 : if (sVideoDecoderChildThread) {
64 0 : sVideoDecoderChildThread->Dispatch(
65 0 : NS_NewRunnableFunction("dom::VideoDecoderManagerChild::Shutdown",
66 0 : []() {
67 0 : if (sDecoderManager &&
68 0 : sDecoderManager->CanSend()) {
69 0 : sDecoderManager->Close();
70 0 : sDecoderManager = nullptr;
71 : }
72 0 : }),
73 0 : NS_DISPATCH_NORMAL);
74 :
75 0 : sVideoDecoderChildAbstractThread = nullptr;
76 0 : sVideoDecoderChildThread->Shutdown();
77 0 : sVideoDecoderChildThread = nullptr;
78 :
79 0 : sRecreateTasks = nullptr;
80 : }
81 0 : }
82 :
83 : void
84 0 : VideoDecoderManagerChild::RunWhenRecreated(already_AddRefed<Runnable> aTask)
85 : {
86 0 : MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
87 :
88 : // If we've already been recreated, then run the task immediately.
89 0 : if (sDecoderManager && sDecoderManager != this && sDecoderManager->CanSend()) {
90 0 : RefPtr<Runnable> task = aTask;
91 0 : task->Run();
92 : } else {
93 0 : sRecreateTasks->AppendElement(aTask);
94 : }
95 0 : }
96 :
97 :
98 : /* static */ VideoDecoderManagerChild*
99 0 : VideoDecoderManagerChild::GetSingleton()
100 : {
101 0 : MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
102 0 : return sDecoderManager;
103 : }
104 :
105 : /* static */ nsIThread*
106 0 : VideoDecoderManagerChild::GetManagerThread()
107 : {
108 0 : return sVideoDecoderChildThread;
109 : }
110 :
111 : /* static */ AbstractThread*
112 0 : VideoDecoderManagerChild::GetManagerAbstractThread()
113 : {
114 0 : return sVideoDecoderChildAbstractThread;
115 : }
116 :
117 : PVideoDecoderChild*
118 0 : VideoDecoderManagerChild::AllocPVideoDecoderChild(const VideoInfo& aVideoInfo,
119 : const layers::TextureFactoryIdentifier& aIdentifier,
120 : bool* aSuccess)
121 : {
122 0 : return new VideoDecoderChild();
123 : }
124 :
125 : bool
126 0 : VideoDecoderManagerChild::DeallocPVideoDecoderChild(PVideoDecoderChild* actor)
127 : {
128 0 : VideoDecoderChild* child = static_cast<VideoDecoderChild*>(actor);
129 0 : child->IPDLActorDestroyed();
130 0 : return true;
131 : }
132 :
133 : void
134 2 : VideoDecoderManagerChild::Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint)
135 : {
136 : // Make sure we always dispatch everything in sRecreateTasks, even if we
137 : // fail since this is as close to being recreated as we will ever be.
138 2 : sDecoderManager = nullptr;
139 2 : if (aEndpoint.IsValid()) {
140 0 : RefPtr<VideoDecoderManagerChild> manager = new VideoDecoderManagerChild();
141 0 : if (aEndpoint.Bind(manager)) {
142 0 : sDecoderManager = manager;
143 0 : manager->InitIPDL();
144 : }
145 : }
146 2 : for (Runnable* task : *sRecreateTasks) {
147 0 : task->Run();
148 : }
149 2 : sRecreateTasks->Clear();
150 2 : }
151 :
152 : void
153 0 : VideoDecoderManagerChild::InitIPDL()
154 : {
155 0 : mCanSend = true;
156 0 : mIPDLSelfRef = this;
157 0 : }
158 :
159 : void
160 0 : VideoDecoderManagerChild::ActorDestroy(ActorDestroyReason aWhy)
161 : {
162 0 : mCanSend = false;
163 0 : }
164 :
165 : void
166 0 : VideoDecoderManagerChild::DeallocPVideoDecoderManagerChild()
167 : {
168 0 : mIPDLSelfRef = nullptr;
169 0 : }
170 :
171 : bool
172 0 : VideoDecoderManagerChild::CanSend()
173 : {
174 0 : MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread());
175 0 : return mCanSend;
176 : }
177 :
178 : bool
179 0 : VideoDecoderManagerChild::DeallocShmem(mozilla::ipc::Shmem& aShmem)
180 : {
181 0 : if (NS_GetCurrentThread() != sVideoDecoderChildThread) {
182 0 : RefPtr<VideoDecoderManagerChild> self = this;
183 0 : mozilla::ipc::Shmem shmem = aShmem;
184 0 : sVideoDecoderChildThread->Dispatch(
185 0 : NS_NewRunnableFunction("dom::VideoDecoderManagerChild::DeallocShmem",
186 0 : [self, shmem]() {
187 0 : if (self->CanSend()) {
188 0 : mozilla::ipc::Shmem shmemCopy = shmem;
189 0 : self->DeallocShmem(shmemCopy);
190 : }
191 0 : }),
192 0 : NS_DISPATCH_NORMAL);
193 0 : return true;
194 : }
195 0 : return PVideoDecoderManagerChild::DeallocShmem(aShmem);
196 : }
197 :
198 : struct SurfaceDescriptorUserData
199 : {
200 0 : SurfaceDescriptorUserData(VideoDecoderManagerChild* aAllocator, SurfaceDescriptor& aSD)
201 0 : : mAllocator(aAllocator)
202 0 : , mSD(aSD)
203 0 : {}
204 0 : ~SurfaceDescriptorUserData()
205 0 : {
206 0 : DestroySurfaceDescriptor(mAllocator, &mSD);
207 0 : }
208 :
209 : RefPtr<VideoDecoderManagerChild> mAllocator;
210 : SurfaceDescriptor mSD;
211 : };
212 :
213 0 : void DeleteSurfaceDescriptorUserData(void* aClosure)
214 : {
215 0 : SurfaceDescriptorUserData* sd = reinterpret_cast<SurfaceDescriptorUserData*>(aClosure);
216 0 : delete sd;
217 0 : }
218 :
219 : already_AddRefed<SourceSurface>
220 0 : VideoDecoderManagerChild::Readback(const SurfaceDescriptorGPUVideo& aSD)
221 : {
222 : // We can't use NS_DISPATCH_SYNC here since that can spin the event
223 : // loop while it waits. This function can be called from JS and we
224 : // don't want that to happen.
225 0 : SynchronousTask task("Readback sync");
226 :
227 0 : RefPtr<VideoDecoderManagerChild> ref = this;
228 0 : SurfaceDescriptor sd;
229 0 : if (NS_FAILED(sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction("VideoDecoderManagerChild::Readback",
230 : [&]() {
231 : AutoCompleteTask complete(&task);
232 : if (ref->CanSend()) {
233 : ref->SendReadback(aSD, &sd);
234 : }
235 : }), NS_DISPATCH_NORMAL))) {
236 0 : return nullptr;
237 : }
238 :
239 0 : task.Wait();
240 :
241 0 : if (!IsSurfaceDescriptorValid(sd)) {
242 0 : return nullptr;
243 : }
244 :
245 0 : RefPtr<DataSourceSurface> source = GetSurfaceForDescriptor(sd);
246 0 : if (!source) {
247 0 : DestroySurfaceDescriptor(this, &sd);
248 0 : NS_WARNING("Failed to map SurfaceDescriptor in Readback");
249 0 : return nullptr;
250 : }
251 :
252 : static UserDataKey sSurfaceDescriptor;
253 0 : source->AddUserData(&sSurfaceDescriptor,
254 0 : new SurfaceDescriptorUserData(this, sd),
255 0 : DeleteSurfaceDescriptorUserData);
256 :
257 0 : return source.forget();
258 : }
259 :
260 : void
261 0 : VideoDecoderManagerChild::DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
262 : {
263 0 : RefPtr<VideoDecoderManagerChild> ref = this;
264 0 : SurfaceDescriptorGPUVideo sd = Move(aSD);
265 0 : sVideoDecoderChildThread->Dispatch(
266 0 : NS_NewRunnableFunction(
267 : "dom::VideoDecoderManagerChild::DeallocateSurfaceDescriptorGPUVideo",
268 0 : [ref, sd]() {
269 0 : if (ref->CanSend()) {
270 0 : ref->SendDeallocateSurfaceDescriptorGPUVideo(sd);
271 : }
272 0 : }),
273 0 : NS_DISPATCH_NORMAL);
274 0 : }
275 :
276 : void
277 0 : VideoDecoderManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
278 : {
279 0 : dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
280 0 : }
281 :
282 : } // namespace dom
283 9 : } // namespace mozilla
|