Coverage Report

Created: 2018-09-25 14:53

/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