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