Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / media / gmp / GMPVideoEncoderParent.cpp
blob21c86ff9ab51987f767e77c262ddac428037b2f0
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/. */
6 #include "GMPVideoEncoderParent.h"
8 #include "GMPContentParent.h"
9 #include "GMPCrashHelper.h"
10 #include "GMPLog.h"
11 #include "GMPMessageUtils.h"
12 #include "GMPVideoEncodedFrameImpl.h"
13 #include "GMPVideoi420FrameImpl.h"
14 #include "mozilla/gmp/GMPTypes.h"
15 #include "mozilla/Unused.h"
16 #include "nsAutoRef.h"
17 #include "nsThread.h"
18 #include "nsThreadUtils.h"
19 #include "runnable_utils.h"
21 namespace mozilla::gmp {
23 #ifdef __CLASS__
24 # undef __CLASS__
25 #endif
26 #define __CLASS__ "GMPVideoEncoderParent"
28 // States:
29 // Initial: mIsOpen == false
30 // on InitDecode success -> Open
31 // on Shutdown -> Dead
32 // Open: mIsOpen == true
33 // on Close -> Dead
34 // on ActorDestroy -> Dead
35 // on Shutdown -> Dead
36 // Dead: mIsOpen == false
38 GMPVideoEncoderParent::GMPVideoEncoderParent(GMPContentParent* aPlugin)
39 : GMPSharedMemManager(aPlugin),
40 mIsOpen(false),
41 mShuttingDown(false),
42 mActorDestroyed(false),
43 mPlugin(aPlugin),
44 mCallback(nullptr),
45 mVideoHost(this),
46 mPluginId(aPlugin->GetPluginId()) {
47 MOZ_ASSERT(mPlugin);
50 GMPVideoHostImpl& GMPVideoEncoderParent::Host() { return mVideoHost; }
52 // Note: may be called via Terminated()
53 void GMPVideoEncoderParent::Close() {
54 GMP_LOG_DEBUG("%s::%s: %p", __CLASS__, __FUNCTION__, this);
55 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
56 // Consumer is done with us; we can shut down. No more callbacks should
57 // be made to mCallback. Note: do this before Shutdown()!
58 mCallback = nullptr;
60 // Let Shutdown mark us as dead so it knows if we had been alive
62 // In case this is the last reference
63 RefPtr<GMPVideoEncoderParent> kungfudeathgrip(this);
64 Release();
65 Shutdown();
68 GMPErr GMPVideoEncoderParent::InitEncode(
69 const GMPVideoCodec& aCodecSettings,
70 const nsTArray<uint8_t>& aCodecSpecific,
71 GMPVideoEncoderCallbackProxy* aCallback, int32_t aNumberOfCores,
72 uint32_t aMaxPayloadSize) {
73 GMP_LOG_DEBUG("%s::%s: %p", __CLASS__, __FUNCTION__, this);
74 if (mIsOpen) {
75 NS_WARNING("Trying to re-init an in-use GMP video encoder!");
76 return GMPGenericErr;
80 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
81 MOZ_ASSERT(!mCallback);
83 if (!aCallback) {
84 return GMPGenericErr;
86 mCallback = aCallback;
88 if (!SendInitEncode(aCodecSettings, aCodecSpecific, aNumberOfCores,
89 aMaxPayloadSize)) {
90 return GMPGenericErr;
92 mIsOpen = true;
94 // Async IPC, we don't have access to a return value.
95 return GMPNoErr;
98 GMPErr GMPVideoEncoderParent::Encode(
99 GMPUniquePtr<GMPVideoi420Frame> aInputFrame,
100 const nsTArray<uint8_t>& aCodecSpecificInfo,
101 const nsTArray<GMPVideoFrameType>& aFrameTypes) {
102 if (!mIsOpen) {
103 NS_WARNING("Trying to use an dead GMP video encoder");
104 return GMPGenericErr;
107 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
109 GMPUniquePtr<GMPVideoi420FrameImpl> inputFrameImpl(
110 static_cast<GMPVideoi420FrameImpl*>(aInputFrame.release()));
112 // Very rough kill-switch if the plugin stops processing. If it's merely
113 // hung and continues, we'll come back to life eventually.
114 // 3* is because we're using 3 buffers per frame for i420 data for now.
115 if ((NumInUse(GMPSharedMem::kGMPFrameData) >
116 3 * GMPSharedMem::kGMPBufLimit) ||
117 (NumInUse(GMPSharedMem::kGMPEncodedData) > GMPSharedMem::kGMPBufLimit)) {
118 GMP_LOG_ERROR(
119 "%s::%s: Out of mem buffers. Frame Buffers:%lu Max:%lu, Encoded "
120 "Buffers: %lu Max: %lu",
121 __CLASS__, __FUNCTION__,
122 static_cast<unsigned long>(NumInUse(GMPSharedMem::kGMPFrameData)),
123 static_cast<unsigned long>(3 * GMPSharedMem::kGMPBufLimit),
124 static_cast<unsigned long>(NumInUse(GMPSharedMem::kGMPEncodedData)),
125 static_cast<unsigned long>(GMPSharedMem::kGMPBufLimit));
126 return GMPGenericErr;
129 GMPVideoi420FrameData frameData;
130 inputFrameImpl->InitFrameData(frameData);
132 if (!SendEncode(frameData, aCodecSpecificInfo, aFrameTypes)) {
133 GMP_LOG_ERROR("%s::%s: failed to send encode", __CLASS__, __FUNCTION__);
134 return GMPGenericErr;
137 // Async IPC, we don't have access to a return value.
138 return GMPNoErr;
141 GMPErr GMPVideoEncoderParent::SetChannelParameters(uint32_t aPacketLoss,
142 uint32_t aRTT) {
143 if (!mIsOpen) {
144 NS_WARNING("Trying to use an invalid GMP video encoder!");
145 return GMPGenericErr;
148 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
150 if (!SendSetChannelParameters(aPacketLoss, aRTT)) {
151 return GMPGenericErr;
154 // Async IPC, we don't have access to a return value.
155 return GMPNoErr;
158 GMPErr GMPVideoEncoderParent::SetRates(uint32_t aNewBitRate,
159 uint32_t aFrameRate) {
160 if (!mIsOpen) {
161 NS_WARNING("Trying to use an dead GMP video decoder");
162 return GMPGenericErr;
165 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
167 if (!SendSetRates(aNewBitRate, aFrameRate)) {
168 return GMPGenericErr;
171 // Async IPC, we don't have access to a return value.
172 return GMPNoErr;
175 GMPErr GMPVideoEncoderParent::SetPeriodicKeyFrames(bool aEnable) {
176 if (!mIsOpen) {
177 NS_WARNING("Trying to use an invalid GMP video encoder!");
178 return GMPGenericErr;
181 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
183 if (!SendSetPeriodicKeyFrames(aEnable)) {
184 return GMPGenericErr;
187 // Async IPC, we don't have access to a return value.
188 return GMPNoErr;
191 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
192 void GMPVideoEncoderParent::Shutdown() {
193 GMP_LOG_DEBUG("%s::%s: %p", __CLASS__, __FUNCTION__, this);
194 MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
196 if (mShuttingDown) {
197 return;
199 mShuttingDown = true;
201 // Notify client we're gone! Won't occur after Close()
202 if (mCallback) {
203 mCallback->Terminated();
204 mCallback = nullptr;
207 mIsOpen = false;
208 if (!mActorDestroyed) {
209 Unused << SendEncodingComplete();
213 // Note: Keep this sync'd up with Shutdown
214 void GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy) {
215 GMP_LOG_DEBUG("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int)aWhy);
216 mIsOpen = false;
217 mActorDestroyed = true;
218 if (mCallback) {
219 // May call Close() (and Shutdown()) immediately or with a delay
220 mCallback->Terminated();
221 mCallback = nullptr;
223 if (mPlugin) {
224 // Ignore any return code. It is OK for this to fail without killing the
225 // process.
226 mPlugin->VideoEncoderDestroyed(this);
227 mPlugin = nullptr;
229 mVideoHost.ActorDestroyed(); // same as DoneWithAPI
230 MaybeDisconnect(aWhy == AbnormalShutdown);
233 mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvEncoded(
234 const GMPVideoEncodedFrameData& aEncodedFrame,
235 nsTArray<uint8_t>&& aCodecSpecificInfo) {
236 if (mCallback) {
237 auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost);
238 mCallback->Encoded(f, aCodecSpecificInfo);
239 f->Destroy();
241 return IPC_OK();
244 mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvError(const GMPErr& aError) {
245 if (mCallback) {
246 mCallback->Error(aError);
249 return IPC_OK();
252 mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvShutdown() {
253 Shutdown();
254 return IPC_OK();
257 mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvParentShmemForPool(
258 Shmem&& aFrameBuffer) {
259 if (aFrameBuffer.IsWritable()) {
260 // This test may be paranoia now that we don't shut down the VideoHost
261 // in ::Shutdown, but doesn't hurt
262 if (mVideoHost.SharedMemMgr()) {
263 mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMem::kGMPFrameData,
264 aFrameBuffer);
265 } else {
266 GMP_LOG_DEBUG(
267 "%s::%s: %p Called in shutdown, ignoring and freeing directly",
268 __CLASS__, __FUNCTION__, this);
269 DeallocShmem(aFrameBuffer);
272 return IPC_OK();
275 mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvNeedShmem(
276 const uint32_t& aEncodedBufferSize, Shmem* aMem) {
277 ipc::Shmem mem;
279 // This test may be paranoia now that we don't shut down the VideoHost
280 // in ::Shutdown, but doesn't hurt
281 if (!mVideoHost.SharedMemMgr() ||
282 !mVideoHost.SharedMemMgr()->MgrAllocShmem(GMPSharedMem::kGMPEncodedData,
283 aEncodedBufferSize, &mem)) {
284 GMP_LOG_ERROR(
285 "%s::%s: Failed to get a shared mem buffer for Child! size %u",
286 __CLASS__, __FUNCTION__, aEncodedBufferSize);
287 return IPC_FAIL(this, "Failed to get a shared mem buffer for Child!");
289 *aMem = mem;
290 mem = ipc::Shmem();
291 return IPC_OK();
294 mozilla::ipc::IPCResult GMPVideoEncoderParent::Recv__delete__() {
295 if (mPlugin) {
296 // Ignore any return code. It is OK for this to fail without killing the
297 // process.
298 mPlugin->VideoEncoderDestroyed(this);
299 mPlugin = nullptr;
302 return IPC_OK();
305 } // namespace mozilla::gmp
307 #undef __CLASS__