size_t ArenaAllocatorBase<TFreeListPolicy, ObjectAlignmentBitShiftArg, RequireObjectAlignment, MaxObjectSize>:: AllocatedSize() { UpdateCacheBlock(); return AllocatedSize(this->fullBlocks) + AllocatedSize(this->bigBlocks) + AllocatedSize(this->mallocBlocks); }
GMPErr GMPPlaneImpl::MaybeResize(int32_t aNewSize) { if (aNewSize <= AllocatedSize()) { return GMPNoErr; } if (!mHost) { return GMPGenericErr; } ipc::Shmem new_mem; if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPFrameData, aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) || !new_mem.get<uint8_t>()) { return GMPAllocErr; } if (mBuffer.IsReadable()) { memcpy(new_mem.get<uint8_t>(), Buffer(), mSize); } DestroyBuffer(); mBuffer = new_mem; return GMPNoErr; }
// Special handing is needed around ReturnOutput as it spins the IPC message // queue when creating an empty frame and can end up with reentrant calls into // the class methods. bool WidevineVideoDecoder::ReturnOutput(WidevineVideoFrame& aCDMFrame) { MOZ_ASSERT(mReturnOutputCallDepth >= 0); CounterHelper counterHelper(mReturnOutputCallDepth); mFrameAllocationQueue.push_back(Move(aCDMFrame)); if (mReturnOutputCallDepth > 1) { // In a reentrant call. return true; } while (!mFrameAllocationQueue.empty()) { MOZ_ASSERT(mReturnOutputCallDepth == 1); // If we're at call level 1 a reset should not have been started. A // reset may be received during CreateEmptyFrame below, but we should not // be in a reset at this stage -- this would indicate receiving decode // messages before completing our reset, which we should not. MOZ_ASSERT(!mResetInProgress); WidevineVideoFrame currentCDMFrame = Move(mFrameAllocationQueue.front()); mFrameAllocationQueue.pop_front(); GMPVideoFrame* f = nullptr; auto err = mVideoHost->CreateFrame(kGMPI420VideoFrame, &f); if (GMP_FAILED(err) || !f) { Log("Failed to create i420 frame!\n"); return false; } auto gmpFrame = static_cast<GMPVideoi420Frame*>(f); FrameDestroyerHelper frameDestroyerHelper(gmpFrame); Size size = currentCDMFrame.Size(); const int32_t yStride = currentCDMFrame.Stride(VideoFrame::kYPlane); const int32_t uStride = currentCDMFrame.Stride(VideoFrame::kUPlane); const int32_t vStride = currentCDMFrame.Stride(VideoFrame::kVPlane); const int32_t halfHeight = size.height / 2; // This call can cause a shmem alloc, during this alloc other calls // may be made to this class and placed on the stack. ***WARNING***: // other IPC calls can happen during this call, resulting in calls // being made to the CDM. After this call state can have changed, // and should be reevaluated. err = gmpFrame->CreateEmptyFrame(size.width, size.height, yStride, uStride, vStride); // Assert possible reentrant calls or resets haven't altered level unexpectedly. MOZ_ASSERT(mReturnOutputCallDepth == 1); ENSURE_GMP_SUCCESS(err, false); // If a reset started we need to dump the current frame and complete the reset. if (mResetInProgress) { MOZ_ASSERT(mCDMWrapper); MOZ_ASSERT(mFrameAllocationQueue.empty()); CompleteReset(); return true; } err = gmpFrame->SetWidth(size.width); ENSURE_GMP_SUCCESS(err, false); err = gmpFrame->SetHeight(size.height); ENSURE_GMP_SUCCESS(err, false); Buffer* buffer = currentCDMFrame.FrameBuffer(); uint8_t* outBuffer = gmpFrame->Buffer(kGMPYPlane); ENSURE_TRUE(outBuffer != nullptr, false); MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPYPlane) >= yStride*size.height); memcpy(outBuffer, buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kYPlane), yStride * size.height); outBuffer = gmpFrame->Buffer(kGMPUPlane); ENSURE_TRUE(outBuffer != nullptr, false); MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPUPlane) >= uStride * halfHeight); memcpy(outBuffer, buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kUPlane), uStride * halfHeight); outBuffer = gmpFrame->Buffer(kGMPVPlane); ENSURE_TRUE(outBuffer != nullptr, false); MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPVPlane) >= vStride * halfHeight); memcpy(outBuffer, buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kVPlane), vStride * halfHeight); gmpFrame->SetTimestamp(currentCDMFrame.Timestamp()); auto d = mFrameDurations.find(currentCDMFrame.Timestamp()); if (d != mFrameDurations.end()) { gmpFrame->SetDuration(d->second); mFrameDurations.erase(d); } // Forget frame so it's not deleted, call back taking ownership. frameDestroyerHelper.ForgetFrame(); mCallback->Decoded(gmpFrame); } return true; }