Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/ipc/VideoDecoderParent.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 "VideoDecoderParent.h"
7
#include "mozilla/Unused.h"
8
#include "mozilla/layers/CompositorThread.h"
9
#include "base/thread.h"
10
#include "mozilla/layers/TextureClient.h"
11
#include "mozilla/layers/VideoBridgeChild.h"
12
#include "mozilla/layers/ImageClient.h"
13
#include "MediaInfo.h"
14
#include "VideoDecoderManagerParent.h"
15
#ifdef XP_WIN
16
#include "WMFDecoderModule.h"
17
#endif
18
19
namespace mozilla {
20
namespace dom {
21
22
using base::Thread;
23
using media::TimeUnit;
24
using namespace ipc;
25
using namespace layers;
26
using namespace gfx;
27
28
class KnowsCompositorVideo : public layers::KnowsCompositor
29
{
30
public:
31
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KnowsCompositorVideo, override)
32
33
  layers::TextureForwarder* GetTextureForwarder() override
34
0
  {
35
0
    return VideoBridgeChild::GetSingleton();
36
0
  }
37
  layers::LayersIPCActor* GetLayersIPCActor() override
38
0
  {
39
0
    return VideoBridgeChild::GetSingleton();
40
0
  }
41
private:
42
  virtual ~KnowsCompositorVideo() = default;
43
};
44
45
VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent,
46
                                       const VideoInfo& aVideoInfo,
47
                                       float aFramerate,
48
                                       const layers::TextureFactoryIdentifier& aIdentifier,
49
                                       TaskQueue* aManagerTaskQueue,
50
                                       TaskQueue* aDecodeTaskQueue,
51
                                       bool* aSuccess,
52
                                       nsCString* aErrorDescription)
53
  : mParent(aParent)
54
  , mManagerTaskQueue(aManagerTaskQueue)
55
  , mDecodeTaskQueue(aDecodeTaskQueue)
56
  , mKnowsCompositor(new KnowsCompositorVideo)
57
  , mDestroyed(false)
58
0
{
59
0
  MOZ_COUNT_CTOR(VideoDecoderParent);
60
0
  MOZ_ASSERT(OnManagerThread());
61
0
  // We hold a reference to ourselves to keep us alive until IPDL
62
0
  // explictly destroys us. There may still be refs held by
63
0
  // tasks, but no new ones should be added after we're
64
0
  // destroyed.
65
0
  mIPDLSelfRef = this;
66
0
67
0
  mKnowsCompositor->IdentifyTextureHost(aIdentifier);
68
0
69
#ifdef XP_WIN
70
  // TODO: Ideally we wouldn't hardcode the WMF PDM, and we'd use the normal PDM
71
  // factory logic for picking a decoder.
72
  WMFDecoderModule::Init();
73
  RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
74
  pdm->Startup();
75
76
  CreateDecoderParams params(aVideoInfo);
77
  params.mTaskQueue = mDecodeTaskQueue;
78
  params.mKnowsCompositor = mKnowsCompositor;
79
  params.mImageContainer = new layers::ImageContainer();
80
  params.mRate = CreateDecoderParams::VideoFrameRate(aFramerate);
81
  MediaResult error(NS_OK);
82
  params.mError = &error;
83
84
  mDecoder = pdm->CreateVideoDecoder(params);
85
86
  if (NS_FAILED(error)) {
87
    MOZ_ASSERT(aErrorDescription);
88
    *aErrorDescription = error.Description();
89
  }
90
#else
91
0
  MOZ_ASSERT(false,
92
0
             "Can't use RemoteVideoDecoder on non-Windows platforms yet");
93
0
#endif
94
0
  *aSuccess = !!mDecoder;
95
0
}
96
97
VideoDecoderParent::~VideoDecoderParent()
98
0
{
99
0
  MOZ_COUNT_DTOR(VideoDecoderParent);
100
0
}
101
102
void
103
VideoDecoderParent::Destroy()
104
0
{
105
0
  MOZ_ASSERT(OnManagerThread());
106
0
  mDecodeTaskQueue->AwaitShutdownAndIdle();
107
0
  mDestroyed = true;
108
0
  mIPDLSelfRef = nullptr;
109
0
}
110
111
mozilla::ipc::IPCResult
112
VideoDecoderParent::RecvInit()
113
0
{
114
0
  MOZ_ASSERT(OnManagerThread());
115
0
  RefPtr<VideoDecoderParent> self = this;
116
0
  mDecoder->Init()->Then(mManagerTaskQueue, __func__,
117
0
    [self] (TrackInfo::TrackType aTrack) {
118
0
      if (self->mDecoder) {
119
0
        nsCString hardwareReason;
120
0
        bool hardwareAccelerated =
121
0
          self->mDecoder->IsHardwareAccelerated(hardwareReason);
122
0
        uint32_t conversion =
123
0
          static_cast<uint32_t>(self->mDecoder->NeedsConversion());
124
0
        Unused << self->SendInitComplete(self->mDecoder->GetDescriptionName(),
125
0
                                         hardwareAccelerated,
126
0
                                         hardwareReason,
127
0
                                         conversion);
128
0
      }
129
0
    },
130
0
    [self] (MediaResult aReason) {
131
0
      if (!self->mDestroyed) {
132
0
        Unused << self->SendInitFailed(aReason);
133
0
      }
134
0
    });
135
0
  return IPC_OK();
136
0
}
137
138
mozilla::ipc::IPCResult
139
VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
140
0
{
141
0
  MOZ_ASSERT(OnManagerThread());
142
0
  // XXX: This copies the data into a buffer owned by the MediaRawData. Ideally
143
0
  // we'd just take ownership of the shmem.
144
0
  RefPtr<MediaRawData> data = new MediaRawData(aData.buffer().get<uint8_t>(),
145
0
                                               aData.buffer().Size<uint8_t>());
146
0
  if (aData.buffer().Size<uint8_t>() && !data->Data()) {
147
0
    // OOM
148
0
    Error(NS_ERROR_OUT_OF_MEMORY);
149
0
    return IPC_OK();
150
0
  }
151
0
  data->mOffset = aData.base().offset();
152
0
  data->mTime = TimeUnit::FromMicroseconds(aData.base().time());
153
0
  data->mTimecode = TimeUnit::FromMicroseconds(aData.base().timecode());
154
0
  data->mDuration = TimeUnit::FromMicroseconds(aData.base().duration());
155
0
  data->mKeyframe = aData.base().keyframe();
156
0
157
0
  DeallocShmem(aData.buffer());
158
0
159
0
  RefPtr<VideoDecoderParent> self = this;
160
0
  mDecoder->Decode(data)->Then(
161
0
    mManagerTaskQueue, __func__,
162
0
    [self, this](const MediaDataDecoder::DecodedData& aResults) {
163
0
      if (mDestroyed) {
164
0
        return;
165
0
      }
166
0
      ProcessDecodedData(aResults);
167
0
      Unused << SendInputExhausted();
168
0
    },
169
0
    [self](const MediaResult& aError) { self->Error(aError); });
170
0
  return IPC_OK();
171
0
}
172
173
void
174
VideoDecoderParent::ProcessDecodedData(
175
  const MediaDataDecoder::DecodedData& aData)
176
0
{
177
0
  MOZ_ASSERT(OnManagerThread());
178
0
179
0
  // If the video decoder bridge has shut down, stop.
180
0
  if (!mKnowsCompositor->GetTextureForwarder()) {
181
0
    return;
182
0
  }
183
0
184
0
  for (const auto& data : aData) {
185
0
    MOZ_ASSERT(data->mType == MediaData::VIDEO_DATA,
186
0
                "Can only decode videos using VideoDecoderParent!");
187
0
    VideoData* video = static_cast<VideoData*>(data.get());
188
0
189
0
    MOZ_ASSERT(video->mImage, "Decoded video must output a layer::Image to "
190
0
                              "be used with VideoDecoderParent");
191
0
192
0
    RefPtr<TextureClient> texture =
193
0
      video->mImage->GetTextureClient(mKnowsCompositor);
194
0
195
0
    if (!texture) {
196
0
      texture = ImageClient::CreateTextureClientForImage(video->mImage,
197
0
                                                          mKnowsCompositor);
198
0
    }
199
0
200
0
    if (texture && !texture->IsAddedToCompositableClient()) {
201
0
      texture->InitIPDLActor(mKnowsCompositor);
202
0
      texture->SetAddedToCompositableClient();
203
0
    }
204
0
205
0
    VideoDataIPDL output(
206
0
      MediaDataIPDL(data->mOffset, data->mTime.ToMicroseconds(),
207
0
                    data->mTimecode.ToMicroseconds(),
208
0
                    data->mDuration.ToMicroseconds(),
209
0
                    data->mFrames, data->mKeyframe),
210
0
      video->mDisplay,
211
0
      texture ? texture->GetSize() : IntSize(),
212
0
      texture ? mParent->StoreImage(video->mImage, texture)
213
0
              : SurfaceDescriptorGPUVideo(0, null_t()),
214
0
      video->mFrameID);
215
0
    Unused << SendOutput(output);
216
0
  }
217
0
}
218
219
mozilla::ipc::IPCResult
220
VideoDecoderParent::RecvFlush()
221
0
{
222
0
  MOZ_ASSERT(!mDestroyed);
223
0
  MOZ_ASSERT(OnManagerThread());
224
0
  RefPtr<VideoDecoderParent> self = this;
225
0
  mDecoder->Flush()->Then(
226
0
    mManagerTaskQueue, __func__,
227
0
    [self]() {
228
0
      if (!self->mDestroyed) {
229
0
        Unused << self->SendFlushComplete();
230
0
      }
231
0
    },
232
0
    [self](const MediaResult& aError) { self->Error(aError); });
233
0
234
0
  return IPC_OK();
235
0
}
236
237
mozilla::ipc::IPCResult
238
VideoDecoderParent::RecvDrain()
239
0
{
240
0
  MOZ_ASSERT(!mDestroyed);
241
0
  MOZ_ASSERT(OnManagerThread());
242
0
  RefPtr<VideoDecoderParent> self = this;
243
0
  mDecoder->Drain()->Then(
244
0
    mManagerTaskQueue, __func__,
245
0
    [self, this](const MediaDataDecoder::DecodedData& aResults) {
246
0
      if (!mDestroyed) {
247
0
        ProcessDecodedData(aResults);
248
0
        Unused << SendDrainComplete();
249
0
      }
250
0
    },
251
0
    [self](const MediaResult& aError) { self->Error(aError); });
252
0
  return IPC_OK();
253
0
}
254
255
mozilla::ipc::IPCResult
256
VideoDecoderParent::RecvShutdown()
257
0
{
258
0
  MOZ_ASSERT(!mDestroyed);
259
0
  MOZ_ASSERT(OnManagerThread());
260
0
  if (mDecoder) {
261
0
    mDecoder->Shutdown();
262
0
  }
263
0
  mDecoder = nullptr;
264
0
  return IPC_OK();
265
0
}
266
267
mozilla::ipc::IPCResult
268
VideoDecoderParent::RecvSetSeekThreshold(const int64_t& aTime)
269
0
{
270
0
  MOZ_ASSERT(!mDestroyed);
271
0
  MOZ_ASSERT(OnManagerThread());
272
0
  mDecoder->SetSeekThreshold(TimeUnit::FromMicroseconds(aTime));
273
0
  return IPC_OK();
274
0
}
275
276
void
277
VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
278
0
{
279
0
  MOZ_ASSERT(!mDestroyed);
280
0
  MOZ_ASSERT(OnManagerThread());
281
0
  if (mDecoder) {
282
0
    mDecoder->Shutdown();
283
0
    mDecoder = nullptr;
284
0
  }
285
0
  if (mDecodeTaskQueue) {
286
0
    mDecodeTaskQueue->BeginShutdown();
287
0
  }
288
0
}
289
290
void
291
VideoDecoderParent::Error(const MediaResult& aError)
292
0
{
293
0
  MOZ_ASSERT(OnManagerThread());
294
0
  if (!mDestroyed) {
295
0
    Unused << SendError(aError);
296
0
  }
297
0
}
298
299
bool
300
VideoDecoderParent::OnManagerThread()
301
0
{
302
0
  return mParent->OnManagerThread();
303
0
}
304
305
} // namespace dom
306
} // namespace mozilla