Coverage Report

Created: 2018-09-25 14:53

/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