Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (c) 2012, The WebRTC project authors. All rights reserved.
3
 *
4
 *  Redistribution and use in source and binary forms, with or without
5
 *  modification, are permitted provided that the following conditions are
6
 *  met:
7
 *
8
 *    * Redistributions of source code must retain the above copyright
9
 *      notice, this list of conditions and the following disclaimer.
10
 *
11
 *    * Redistributions in binary form must reproduce the above copyright
12
 *      notice, this list of conditions and the following disclaimer in
13
 *      the documentation and/or other materials provided with the
14
 *      distribution.
15
 *
16
 *    * Neither the name of Google nor the names of its contributors may
17
 *      be used to endorse or promote products derived from this software
18
 *      without specific prior written permission.
19
 *
20
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
 */
32
33
#ifndef WEBRTCGMPVIDEOCODEC_H_
34
#define WEBRTCGMPVIDEOCODEC_H_
35
36
#include <queue>
37
#include <string>
38
39
#include "nsThreadUtils.h"
40
#include "mozilla/Monitor.h"
41
#include "mozilla/Mutex.h"
42
43
#include "mozIGeckoMediaPluginService.h"
44
#include "MediaConduitInterface.h"
45
#include "AudioConduit.h"
46
#include "VideoConduit.h"
47
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
48
49
#include "gmp-video-host.h"
50
#include "GMPVideoDecoderProxy.h"
51
#include "GMPVideoEncoderProxy.h"
52
53
#include "PeerConnectionImpl.h"
54
55
namespace mozilla {
56
57
// Class that allows code on the other side of webrtc.org to tell
58
// WebrtcGmpVideoEncoder/Decoder what PC they should send errors to.
59
// This is necessary because webrtc.org gives us no way to plumb the handle
60
// through, nor does it give us any way to inform it of an error that will
61
// make it back to the PC that cares (except for errors encountered
62
// synchronously in functions like InitEncode/Decode, which will not happen
63
// because GMP init is async).
64
// Right now, this is used in MediaPipelineFactory.
65
class WebrtcGmpPCHandleSetter
66
{
67
  public:
68
    explicit WebrtcGmpPCHandleSetter(const std::string& aPCHandle);
69
70
    ~WebrtcGmpPCHandleSetter();
71
72
    static std::string GetCurrentHandle();
73
74
  private:
75
    static std::string sCurrentHandle;
76
};
77
78
class GmpInitDoneRunnable : public Runnable
79
{
80
  public:
81
    explicit GmpInitDoneRunnable(const std::string& aPCHandle) :
82
      Runnable("GmpInitDoneRunnable"),
83
      mResult(WEBRTC_VIDEO_CODEC_OK),
84
      mPCHandle(aPCHandle)
85
0
    {
86
0
    }
87
88
    NS_IMETHOD Run() override
89
0
    {
90
0
      if (mResult == WEBRTC_VIDEO_CODEC_OK) {
91
0
        // Might be useful to notify the PeerConnection about successful init
92
0
        // someday.
93
0
        return NS_OK;
94
0
      }
95
0
96
0
      PeerConnectionWrapper wrapper(mPCHandle);
97
0
      if (wrapper.impl()) {
98
0
        wrapper.impl()->OnMediaError(mError);
99
0
      }
100
0
      return NS_OK;
101
0
    }
102
103
    void Dispatch(int32_t aResult, const std::string& aError = "")
104
0
    {
105
0
      mResult = aResult;
106
0
      mError = aError;
107
0
      nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
108
0
      if (mainThread) {
109
0
        // For some reason, the compiler on CI is treating |this| as a const
110
0
        // pointer, despite the fact that we're in a non-const function. And,
111
0
        // interestingly enough, correcting this doesn't require a const_cast.
112
0
        mainThread->Dispatch(do_AddRef(static_cast<nsIRunnable*>(this)),
113
0
                             NS_DISPATCH_NORMAL);
114
0
      }
115
0
    }
116
117
    int32_t Result()
118
0
    {
119
0
      return mResult;
120
0
    }
121
122
  private:
123
    int32_t mResult;
124
    std::string mPCHandle;
125
    std::string mError;
126
};
127
128
// Hold a frame for later decode
129
class GMPDecodeData
130
{
131
public:
132
  GMPDecodeData(const webrtc::EncodedImage& aInputImage,
133
                bool aMissingFrames,
134
                int64_t aRenderTimeMs)
135
    : mImage(aInputImage)
136
    , mMissingFrames(aMissingFrames)
137
    , mRenderTimeMs(aRenderTimeMs)
138
0
  {
139
0
    // We want to use this for queuing, and the calling code recycles the
140
0
    // buffer on return from Decode()
141
0
    mImage._length = aInputImage._length;
142
0
    mImage._size = aInputImage._length +
143
0
                   webrtc::EncodedImage::GetBufferPaddingBytes(webrtc::kVideoCodecH264);
144
0
    mImage._buffer = new uint8_t[mImage._size];
145
0
    memcpy(mImage._buffer, aInputImage._buffer, aInputImage._length);
146
0
  }
147
148
0
  ~GMPDecodeData() {
149
0
    delete [] mImage._buffer;
150
0
  }
151
152
  webrtc::EncodedImage mImage;
153
  bool mMissingFrames;
154
  int64_t mRenderTimeMs;
155
};
156
157
class WebrtcGmpVideoEncoder : public GMPVideoEncoderCallbackProxy
158
{
159
public:
160
  WebrtcGmpVideoEncoder();
161
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoEncoder);
162
163
  // Implement VideoEncoder interface, sort of.
164
  // (We cannot use |Release|, since that's needed for nsRefPtr)
165
  virtual uint64_t PluginID() const
166
0
  {
167
0
    return mCachedPluginId;
168
0
  }
169
170
  virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
171
                             int32_t aNumberOfCores,
172
                             uint32_t aMaxPayloadSize);
173
174
  virtual int32_t Encode(const webrtc::VideoFrame& aInputImage,
175
                         const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
176
                         const std::vector<webrtc::FrameType>* aFrameTypes);
177
178
  virtual int32_t RegisterEncodeCompleteCallback(
179
    webrtc::EncodedImageCallback* aCallback);
180
181
  virtual int32_t ReleaseGmp();
182
183
  virtual int32_t SetChannelParameters(uint32_t aPacketLoss,
184
                                       int aRTT);
185
186
  virtual int32_t SetRates(uint32_t aNewBitRate,
187
                           uint32_t aFrameRate);
188
189
  // GMPVideoEncoderCallback virtual functions.
190
  virtual void Terminated() override;
191
192
  virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
193
                       const nsTArray<uint8_t>& aCodecSpecificInfo) override;
194
195
0
  virtual void Error(GMPErr aError) override {
196
0
  }
197
198
private:
199
  virtual ~WebrtcGmpVideoEncoder();
200
201
  static void InitEncode_g(const RefPtr<WebrtcGmpVideoEncoder>& aThis,
202
                           const GMPVideoCodec& aCodecParams,
203
                           int32_t aNumberOfCores,
204
                           uint32_t aMaxPayloadSize,
205
                           const RefPtr<GmpInitDoneRunnable>& aInitDone);
206
  int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost,
207
                      const GMPVideoCodec& aCodecParams,
208
                      uint32_t aMaxPayloadSize,
209
                      std::string* aErrorOut);
210
  int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP,
211
                      GMPVideoHost* aHost,
212
                      std::string* aErrorOut);
213
  int32_t InitEncoderForSize(unsigned short aWidth,
214
                             unsigned short aHeight,
215
                             std::string* aErrorOut);
216
  static void ReleaseGmp_g(RefPtr<WebrtcGmpVideoEncoder>& aEncoder);
217
  void Close_g();
218
219
  class InitDoneCallback : public GetGMPVideoEncoderCallback
220
  {
221
  public:
222
    InitDoneCallback(const RefPtr<WebrtcGmpVideoEncoder>& aEncoder,
223
                     const RefPtr<GmpInitDoneRunnable>& aInitDone,
224
                     const GMPVideoCodec& aCodecParams,
225
                     uint32_t aMaxPayloadSize)
226
      : mEncoder(aEncoder),
227
        mInitDone(aInitDone),
228
        mCodecParams(aCodecParams),
229
        mMaxPayloadSize(aMaxPayloadSize)
230
0
    {
231
0
    }
232
233
    virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
234
0
    {
235
0
      std::string errorOut;
236
0
      int32_t result = mEncoder->GmpInitDone(aGMP,
237
0
                                             aHost,
238
0
                                             mCodecParams,
239
0
                                             mMaxPayloadSize,
240
0
                                             &errorOut);
241
0
242
0
      mInitDone->Dispatch(result, errorOut);
243
0
    }
244
245
  private:
246
    RefPtr<WebrtcGmpVideoEncoder> mEncoder;
247
    RefPtr<GmpInitDoneRunnable> mInitDone;
248
    GMPVideoCodec mCodecParams;
249
    uint32_t mMaxPayloadSize;
250
  };
251
252
  static
253
  void Encode_g(RefPtr<WebrtcGmpVideoEncoder>& aEncoder,
254
                webrtc::VideoFrame aInputImage,
255
                std::vector<webrtc::FrameType> aFrameTypes);
256
  void RegetEncoderForResolutionChange(
257
      uint32_t aWidth,
258
      uint32_t aHeight,
259
      const RefPtr<GmpInitDoneRunnable>& aInitDone);
260
261
  class InitDoneForResolutionChangeCallback : public GetGMPVideoEncoderCallback
262
  {
263
  public:
264
    InitDoneForResolutionChangeCallback(
265
        const RefPtr<WebrtcGmpVideoEncoder>& aEncoder,
266
        const RefPtr<GmpInitDoneRunnable>& aInitDone,
267
        uint32_t aWidth,
268
        uint32_t aHeight)
269
      : mEncoder(aEncoder),
270
        mInitDone(aInitDone),
271
        mWidth(aWidth),
272
        mHeight(aHeight)
273
0
    {
274
0
    }
275
276
    virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
277
0
    {
278
0
      std::string errorOut;
279
0
      int32_t result = mEncoder->GmpInitDone(aGMP, aHost, &errorOut);
280
0
      if (result != WEBRTC_VIDEO_CODEC_OK) {
281
0
        mInitDone->Dispatch(result, errorOut);
282
0
        return;
283
0
      }
284
0
285
0
      result = mEncoder->InitEncoderForSize(mWidth, mHeight, &errorOut);
286
0
      mInitDone->Dispatch(result, errorOut);
287
0
    }
288
289
  private:
290
    RefPtr<WebrtcGmpVideoEncoder> mEncoder;
291
    RefPtr<GmpInitDoneRunnable> mInitDone;
292
    uint32_t mWidth;
293
    uint32_t mHeight;
294
  };
295
296
  static int32_t SetRates_g(RefPtr<WebrtcGmpVideoEncoder> aThis,
297
                             uint32_t aNewBitRate,
298
                             uint32_t aFrameRate);
299
300
  nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
301
  nsCOMPtr<nsIThread> mGMPThread;
302
  GMPVideoEncoderProxy* mGMP;
303
  // Used to handle a race where Release() is called while init is in progress
304
  bool mInitting;
305
  GMPVideoHost* mHost;
306
  GMPVideoCodec mCodecParams;
307
  uint32_t mMaxPayloadSize;
308
  webrtc::CodecSpecificInfo mCodecSpecificInfo;
309
  // Protects mCallback
310
  Mutex mCallbackMutex;
311
  webrtc::EncodedImageCallback* mCallback;
312
  uint64_t mCachedPluginId;
313
  std::string mPCHandle;
314
};
315
316
317
// Basically a strong ref to a WebrtcGmpVideoEncoder, that also translates
318
// from Release() to WebrtcGmpVideoEncoder::ReleaseGmp(), since we need
319
// WebrtcGmpVideoEncoder::Release() for managing the refcount.
320
// The webrtc.org code gets one of these, so it doesn't unilaterally delete
321
// the "real" encoder.
322
class WebrtcVideoEncoderProxy : public WebrtcVideoEncoder
323
{
324
  public:
325
    WebrtcVideoEncoderProxy() :
326
      mEncoderImpl(new WebrtcGmpVideoEncoder)
327
0
    {}
328
329
    virtual ~WebrtcVideoEncoderProxy()
330
0
    {
331
0
      RegisterEncodeCompleteCallback(nullptr);
332
0
    }
333
334
    uint64_t PluginID() const override
335
0
    {
336
0
      return mEncoderImpl->PluginID();
337
0
    }
338
339
    int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
340
                       int32_t aNumberOfCores,
341
                       size_t aMaxPayloadSize) override
342
0
    {
343
0
      return mEncoderImpl->InitEncode(aCodecSettings,
344
0
                                      aNumberOfCores,
345
0
                                      aMaxPayloadSize);
346
0
    }
347
348
    int32_t Encode(
349
        const webrtc::VideoFrame& aInputImage,
350
        const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
351
        const std::vector<webrtc::FrameType>* aFrameTypes) override
352
0
    {
353
0
      return mEncoderImpl->Encode(aInputImage,
354
0
                                  aCodecSpecificInfo,
355
0
                                  aFrameTypes);
356
0
    }
357
358
    int32_t RegisterEncodeCompleteCallback(
359
      webrtc::EncodedImageCallback* aCallback) override
360
0
    {
361
0
      return mEncoderImpl->RegisterEncodeCompleteCallback(aCallback);
362
0
    }
363
364
    int32_t Release() override
365
0
    {
366
0
      return mEncoderImpl->ReleaseGmp();
367
0
    }
368
369
    int32_t SetChannelParameters(uint32_t aPacketLoss,
370
                                 int64_t aRTT) override
371
0
    {
372
0
      return mEncoderImpl->SetChannelParameters(aPacketLoss, aRTT);
373
0
    }
374
375
    int32_t SetRates(uint32_t aNewBitRate,
376
                     uint32_t aFrameRate) override
377
0
    {
378
0
      return mEncoderImpl->SetRates(aNewBitRate, aFrameRate);
379
0
    }
380
381
  private:
382
    RefPtr<WebrtcGmpVideoEncoder> mEncoderImpl;
383
};
384
385
class WebrtcGmpVideoDecoder : public GMPVideoDecoderCallbackProxy
386
{
387
public:
388
  WebrtcGmpVideoDecoder();
389
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoDecoder);
390
391
  // Implement VideoEncoder interface, sort of.
392
  // (We cannot use |Release|, since that's needed for nsRefPtr)
393
  virtual uint64_t PluginID() const
394
0
  {
395
0
    return mCachedPluginId;
396
0
  }
397
398
  virtual int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
399
                             int32_t aNumberOfCores);
400
  virtual int32_t Decode(const webrtc::EncodedImage& aInputImage,
401
                         bool aMissingFrames,
402
                         const webrtc::RTPFragmentationHeader* aFragmentation,
403
                         const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
404
                         int64_t aRenderTimeMs);
405
  virtual int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback);
406
407
  virtual int32_t ReleaseGmp();
408
409
  // GMPVideoDecoderCallbackProxy
410
  virtual void Terminated() override;
411
412
  virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override;
413
414
0
  virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override {
415
0
    MOZ_CRASH();
416
0
  }
417
418
0
  virtual void ReceivedDecodedFrame(const uint64_t aPictureId) override {
419
0
    MOZ_CRASH();
420
0
  }
421
422
0
  virtual void InputDataExhausted() override {
423
0
  }
424
425
0
  virtual void DrainComplete() override {
426
0
  }
427
428
0
  virtual void ResetComplete() override {
429
0
  }
430
431
0
  virtual void Error(GMPErr aError) override {
432
0
     mDecoderStatus = aError;
433
0
  }
434
435
private:
436
  virtual ~WebrtcGmpVideoDecoder();
437
438
  static void InitDecode_g(
439
      const RefPtr<WebrtcGmpVideoDecoder>& aThis,
440
      const webrtc::VideoCodec* aCodecSettings,
441
      int32_t aNumberOfCores,
442
      const RefPtr<GmpInitDoneRunnable>& aInitDone);
443
  int32_t GmpInitDone(GMPVideoDecoderProxy* aGMP,
444
                      GMPVideoHost* aHost,
445
                      std::string* aErrorOut);
446
  static void ReleaseGmp_g(RefPtr<WebrtcGmpVideoDecoder>& aDecoder);
447
  void Close_g();
448
449
  class InitDoneCallback : public GetGMPVideoDecoderCallback
450
  {
451
  public:
452
    explicit InitDoneCallback(const RefPtr<WebrtcGmpVideoDecoder>& aDecoder,
453
                              const RefPtr<GmpInitDoneRunnable>& aInitDone)
454
      : mDecoder(aDecoder),
455
        mInitDone(aInitDone)
456
0
    {
457
0
    }
458
459
    virtual void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) override
460
0
    {
461
0
      std::string errorOut;
462
0
      int32_t result = mDecoder->GmpInitDone(aGMP, aHost, &errorOut);
463
0
464
0
      mInitDone->Dispatch(result, errorOut);
465
0
    }
466
467
  private:
468
    RefPtr<WebrtcGmpVideoDecoder> mDecoder;
469
    RefPtr<GmpInitDoneRunnable> mInitDone;
470
  };
471
472
  static void Decode_g(const RefPtr<WebrtcGmpVideoDecoder>& aThis,
473
                       nsAutoPtr<GMPDecodeData> aDecodeData);
474
475
  nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
476
  nsCOMPtr<nsIThread> mGMPThread;
477
  GMPVideoDecoderProxy* mGMP; // Addref is held for us
478
  // Used to handle a race where Release() is called while init is in progress
479
  bool mInitting;
480
  // Frames queued for decode while mInitting is true
481
  nsTArray<UniquePtr<GMPDecodeData>> mQueuedFrames;
482
  GMPVideoHost* mHost;
483
  // Protects mCallback
484
  Mutex mCallbackMutex;
485
  webrtc::DecodedImageCallback* mCallback;
486
  Atomic<uint64_t> mCachedPluginId;
487
  Atomic<GMPErr, ReleaseAcquire> mDecoderStatus;
488
  std::string mPCHandle;
489
};
490
491
// Basically a strong ref to a WebrtcGmpVideoDecoder, that also translates
492
// from Release() to WebrtcGmpVideoDecoder::ReleaseGmp(), since we need
493
// WebrtcGmpVideoDecoder::Release() for managing the refcount.
494
// The webrtc.org code gets one of these, so it doesn't unilaterally delete
495
// the "real" encoder.
496
class WebrtcVideoDecoderProxy : public WebrtcVideoDecoder
497
{
498
  public:
499
    WebrtcVideoDecoderProxy() :
500
      mDecoderImpl(new WebrtcGmpVideoDecoder)
501
0
    {}
502
503
    virtual ~WebrtcVideoDecoderProxy()
504
0
    {
505
0
      RegisterDecodeCompleteCallback(nullptr);
506
0
    }
507
508
    uint64_t PluginID() const override
509
0
    {
510
0
      return mDecoderImpl->PluginID();
511
0
    }
512
513
    int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
514
                       int32_t aNumberOfCores) override
515
0
    {
516
0
      return mDecoderImpl->InitDecode(aCodecSettings, aNumberOfCores);
517
0
    }
518
519
    int32_t Decode(
520
        const webrtc::EncodedImage& aInputImage,
521
        bool aMissingFrames,
522
        const webrtc::RTPFragmentationHeader* aFragmentation,
523
        const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
524
        int64_t aRenderTimeMs) override
525
0
    {
526
0
      return mDecoderImpl->Decode(aInputImage,
527
0
                                  aMissingFrames,
528
0
                                  aFragmentation,
529
0
                                  aCodecSpecificInfo,
530
0
                                  aRenderTimeMs);
531
0
    }
532
533
    int32_t RegisterDecodeCompleteCallback(
534
      webrtc::DecodedImageCallback* aCallback) override
535
0
    {
536
0
      return mDecoderImpl->RegisterDecodeCompleteCallback(aCallback);
537
0
    }
538
539
    int32_t Release() override
540
0
    {
541
0
      return mDecoderImpl->ReleaseGmp();
542
0
    }
543
544
  private:
545
    RefPtr<WebrtcGmpVideoDecoder> mDecoderImpl;
546
};
547
548
}
549
550
#endif