1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "GMPVideoEncoderChild.h"
7 #include "GMPContentChild.h"
8 #include <stdio.h>
9 #include "mozilla/Unused.h"
10 #include "GMPVideoEncodedFrameImpl.h"
11 #include "GMPVideoi420FrameImpl.h"
12 #include "runnable_utils.h"
13
14 namespace mozilla::gmp {
15
GMPVideoEncoderChild(GMPContentChild * aPlugin)16 GMPVideoEncoderChild::GMPVideoEncoderChild(GMPContentChild* aPlugin)
17 : GMPSharedMemManager(aPlugin),
18 mPlugin(aPlugin),
19 mVideoEncoder(nullptr),
20 mVideoHost(this),
21 mNeedShmemIntrCount(0),
22 mPendingEncodeComplete(false) {
23 MOZ_ASSERT(mPlugin);
24 }
25
~GMPVideoEncoderChild()26 GMPVideoEncoderChild::~GMPVideoEncoderChild() {
27 MOZ_ASSERT(!mNeedShmemIntrCount);
28 }
29
Init(GMPVideoEncoder * aEncoder)30 void GMPVideoEncoderChild::Init(GMPVideoEncoder* aEncoder) {
31 MOZ_ASSERT(aEncoder,
32 "Cannot initialize video encoder child without a video encoder!");
33 mVideoEncoder = aEncoder;
34 }
35
Host()36 GMPVideoHostImpl& GMPVideoEncoderChild::Host() { return mVideoHost; }
37
Encoded(GMPVideoEncodedFrame * aEncodedFrame,const uint8_t * aCodecSpecificInfo,uint32_t aCodecSpecificInfoLength)38 void GMPVideoEncoderChild::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
39 const uint8_t* aCodecSpecificInfo,
40 uint32_t aCodecSpecificInfoLength) {
41 MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
42
43 auto ef = static_cast<GMPVideoEncodedFrameImpl*>(aEncodedFrame);
44
45 GMPVideoEncodedFrameData frameData;
46 ef->RelinquishFrameData(frameData);
47
48 nsTArray<uint8_t> codecSpecific;
49 codecSpecific.AppendElements(aCodecSpecificInfo, aCodecSpecificInfoLength);
50 SendEncoded(frameData, codecSpecific);
51
52 aEncodedFrame->Destroy();
53 }
54
Error(GMPErr aError)55 void GMPVideoEncoderChild::Error(GMPErr aError) {
56 MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
57
58 SendError(aError);
59 }
60
RecvInitEncode(const GMPVideoCodec & aCodecSettings,nsTArray<uint8_t> && aCodecSpecific,const int32_t & aNumberOfCores,const uint32_t & aMaxPayloadSize)61 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvInitEncode(
62 const GMPVideoCodec& aCodecSettings, nsTArray<uint8_t>&& aCodecSpecific,
63 const int32_t& aNumberOfCores, const uint32_t& aMaxPayloadSize) {
64 if (!mVideoEncoder) {
65 return IPC_FAIL_NO_REASON(this);
66 }
67
68 // Ignore any return code. It is OK for this to fail without killing the
69 // process.
70 mVideoEncoder->InitEncode(aCodecSettings, aCodecSpecific.Elements(),
71 aCodecSpecific.Length(), this, aNumberOfCores,
72 aMaxPayloadSize);
73
74 return IPC_OK();
75 }
76
RecvEncode(const GMPVideoi420FrameData & aInputFrame,nsTArray<uint8_t> && aCodecSpecificInfo,nsTArray<GMPVideoFrameType> && aFrameTypes)77 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvEncode(
78 const GMPVideoi420FrameData& aInputFrame,
79 nsTArray<uint8_t>&& aCodecSpecificInfo,
80 nsTArray<GMPVideoFrameType>&& aFrameTypes) {
81 if (!mVideoEncoder) {
82 return IPC_FAIL_NO_REASON(this);
83 }
84
85 auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost);
86
87 // Ignore any return code. It is OK for this to fail without killing the
88 // process.
89 mVideoEncoder->Encode(f, aCodecSpecificInfo.Elements(),
90 aCodecSpecificInfo.Length(), aFrameTypes.Elements(),
91 aFrameTypes.Length());
92
93 return IPC_OK();
94 }
95
RecvChildShmemForPool(Shmem && aEncodedBuffer)96 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvChildShmemForPool(
97 Shmem&& aEncodedBuffer) {
98 if (aEncodedBuffer.IsWritable()) {
99 mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMem::kGMPEncodedData,
100 aEncodedBuffer);
101 }
102 return IPC_OK();
103 }
104
RecvSetChannelParameters(const uint32_t & aPacketLoss,const uint32_t & aRTT)105 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetChannelParameters(
106 const uint32_t& aPacketLoss, const uint32_t& aRTT) {
107 if (!mVideoEncoder) {
108 return IPC_FAIL_NO_REASON(this);
109 }
110
111 // Ignore any return code. It is OK for this to fail without killing the
112 // process.
113 mVideoEncoder->SetChannelParameters(aPacketLoss, aRTT);
114
115 return IPC_OK();
116 }
117
RecvSetRates(const uint32_t & aNewBitRate,const uint32_t & aFrameRate)118 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetRates(
119 const uint32_t& aNewBitRate, const uint32_t& aFrameRate) {
120 if (!mVideoEncoder) {
121 return IPC_FAIL_NO_REASON(this);
122 }
123
124 // Ignore any return code. It is OK for this to fail without killing the
125 // process.
126 mVideoEncoder->SetRates(aNewBitRate, aFrameRate);
127
128 return IPC_OK();
129 }
130
RecvSetPeriodicKeyFrames(const bool & aEnable)131 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetPeriodicKeyFrames(
132 const bool& aEnable) {
133 if (!mVideoEncoder) {
134 return IPC_FAIL_NO_REASON(this);
135 }
136
137 // Ignore any return code. It is OK for this to fail without killing the
138 // process.
139 mVideoEncoder->SetPeriodicKeyFrames(aEnable);
140
141 return IPC_OK();
142 }
143
RecvEncodingComplete()144 mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvEncodingComplete() {
145 MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
146
147 if (mNeedShmemIntrCount) {
148 // There's a GMP blocked in Alloc() waiting for the CallNeedShem() to
149 // return a frame they can use. Don't call the GMP's EncodingComplete()
150 // now and don't delete the GMPVideoEncoderChild, defer processing the
151 // EncodingComplete() until once the Alloc() finishes.
152 mPendingEncodeComplete = true;
153 return IPC_OK();
154 }
155
156 if (!mVideoEncoder) {
157 Unused << Send__delete__(this);
158 return IPC_FAIL_NO_REASON(this);
159 }
160
161 // Ignore any return code. It is OK for this to fail without killing the
162 // process.
163 mVideoEncoder->EncodingComplete();
164
165 mVideoHost.DoneWithAPI();
166
167 mPlugin = nullptr;
168
169 Unused << Send__delete__(this);
170
171 return IPC_OK();
172 }
173
Alloc(size_t aSize,Shmem::SharedMemory::SharedMemoryType aType,Shmem * aMem)174 bool GMPVideoEncoderChild::Alloc(size_t aSize,
175 Shmem::SharedMemory::SharedMemoryType aType,
176 Shmem* aMem) {
177 MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
178
179 bool rv;
180 #ifndef SHMEM_ALLOC_IN_CHILD
181 ++mNeedShmemIntrCount;
182 rv = CallNeedShmem(aSize, aMem);
183 --mNeedShmemIntrCount;
184 if (mPendingEncodeComplete && mNeedShmemIntrCount == 0) {
185 mPendingEncodeComplete = false;
186 mPlugin->GMPMessageLoop()->PostTask(
187 NewRunnableMethod("gmp::GMPVideoEncoderChild::RecvEncodingComplete",
188 this, &GMPVideoEncoderChild::RecvEncodingComplete));
189 }
190 #else
191 # ifdef GMP_SAFE_SHMEM
192 rv = AllocShmem(aSize, aType, aMem);
193 # else
194 rv = AllocUnsafeShmem(aSize, aType, aMem);
195 # endif
196 #endif
197 return rv;
198 }
199
Dealloc(Shmem && aMem)200 void GMPVideoEncoderChild::Dealloc(Shmem&& aMem) {
201 #ifndef SHMEM_ALLOC_IN_CHILD
202 SendParentShmemForPool(std::move(aMem));
203 #else
204 DeallocShmem(aMem);
205 #endif
206 }
207
208 } // namespace mozilla::gmp
209