gecko-dev/dom/media/gmp/ChromiumCDMParent.h
Chris Pearce ab9e4db6d1 Bug 1383580 - Add an explicit message to increase CDM-Firefox shmem pool. r=gerald
The strategy we were using to expand the pool of shmems we use to shuffle video
frames between the CDM and content processses is to increase the size of the
pool if the content process receives a video frame in a non-shmem. However the
CDM process will send a frame in a non-shmem if none of the shmems in the pool
are big enough to fit the frame the CDM produces. This happens if we
underestimate the size required for video frames. This causes the
ChromiumCDMParent to increase the number of shmems in the pool every time we
rate switch, until we eventually hit the limit of 50, whereupon playback fails.

So we need to disambiguate between these two cases; the first being we have a
pool of shmems, but they're the wrong size, the second being our shmems are the
right size, but we've run out and we need to expand the shmem pool. The only
place where we know this is in the CDM process. So this commit adds a new
message to PChromiumCDM through which the ChromiumCDMChild can report to the
parent that it needs more shmems in the pool.

The new Widevine CDM has a new video decoder which allocates video frames less
optimally than the previous, which causes us to hit this more often in Nightly.
Our telemetry also indicates we hit this rarely in Beta with the old CDM.

MozReview-Commit-ID: LoSvVhxHQxn

--HG--
extra : rebase_source : 6c7201a74dbf202d0ef8c2269292a80a7ad95dff
extra : source : 57cf5455fd14ef0b68b61f914146ff942b5ca4a0
2017-07-24 12:57:40 +12:00

194 lines
7.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ChromiumCDMParent_h_
#define ChromiumCDMParent_h_
#include "DecryptJob.h"
#include "GMPCrashHelper.h"
#include "GMPCrashHelperHolder.h"
#include "GMPMessageUtils.h"
#include "mozilla/gmp/PChromiumCDMParent.h"
#include "mozilla/RefPtr.h"
#include "nsDataHashtable.h"
#include "PlatformDecoderModule.h"
#include "ImageContainer.h"
#include "mozilla/Span.h"
#include "ReorderQueue.h"
namespace mozilla {
class MediaRawData;
class ChromiumCDMProxy;
namespace gmp {
class GMPContentParent;
class ChromiumCDMParent final
: public PChromiumCDMParent
, public GMPCrashHelperHolder
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMParent)
ChromiumCDMParent(GMPContentParent* aContentParent, uint32_t aPluginId);
uint32_t PluginId() const { return mPluginId; }
bool Init(ChromiumCDMProxy* aProxy,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState);
void CreateSession(uint32_t aCreateSessionToken,
uint32_t aSessionType,
uint32_t aInitDataType,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aInitData);
void LoadSession(uint32_t aPromiseId,
uint32_t aSessionType,
nsString aSessionId);
void SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aCert);
void UpdateSession(const nsCString& aSessionId,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aResponse);
void CloseSession(const nsCString& aSessionId, uint32_t aPromiseId);
void RemoveSession(const nsCString& aSessionId, uint32_t aPromiseId);
RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample);
// TODO: Add functions for clients to send data to CDM, and
// a Close() function.
RefPtr<MediaDataDecoder::InitPromise> InitializeVideoDecoder(
const gmp::CDMVideoDecoderConfig& aConfig,
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer);
RefPtr<MediaDataDecoder::DecodePromise> DecryptAndDecodeFrame(
MediaRawData* aSample);
RefPtr<MediaDataDecoder::FlushPromise> FlushVideoDecoder();
RefPtr<MediaDataDecoder::DecodePromise> Drain();
RefPtr<ShutdownPromise> ShutdownVideoDecoder();
void Shutdown();
protected:
~ChromiumCDMParent() {}
ipc::IPCResult Recv__delete__() override;
ipc::IPCResult RecvOnResolveNewSessionPromise(
const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
ipc::IPCResult RecvResolveLoadSessionPromise(
const uint32_t& aPromiseId,
const bool& aSuccessful) override;
ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId) override;
ipc::IPCResult RecvOnRejectPromise(const uint32_t& aPromiseId,
const uint32_t& aError,
const uint32_t& aSystemCode,
const nsCString& aErrorMessage) override;
ipc::IPCResult RecvOnSessionMessage(const nsCString& aSessionId,
const uint32_t& aMessageType,
nsTArray<uint8_t>&& aMessage) override;
ipc::IPCResult RecvOnSessionKeysChange(
const nsCString& aSessionId,
nsTArray<CDMKeyInformation>&& aKeysInfo) override;
ipc::IPCResult RecvOnExpirationChange(
const nsCString& aSessionId,
const double& aSecondsSinceEpoch) override;
ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId) override;
ipc::IPCResult RecvOnLegacySessionError(const nsCString& aSessionId,
const uint32_t& aError,
const uint32_t& aSystemCode,
const nsCString& aMessage) override;
ipc::IPCResult RecvDecrypted(const uint32_t& aId,
const uint32_t& aStatus,
ipc::Shmem&& aData) override;
ipc::IPCResult RecvDecryptFailed(const uint32_t& aId,
const uint32_t& aStatus) override;
ipc::IPCResult RecvOnDecoderInitDone(const uint32_t& aStatus) override;
ipc::IPCResult RecvDecodedShmem(const CDMVideoFrame& aFrame,
ipc::Shmem&& aShmem) override;
ipc::IPCResult RecvDecodedData(const CDMVideoFrame& aFrame,
nsTArray<uint8_t>&& aData) override;
ipc::IPCResult RecvDecodeFailed(const uint32_t& aStatus) override;
ipc::IPCResult RecvShutdown() override;
ipc::IPCResult RecvResetVideoDecoderComplete() override;
ipc::IPCResult RecvDrainComplete() override;
ipc::IPCResult RecvIncreaseShmemPoolSize() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
bool SendBufferToCDM(uint32_t aSizeInBytes);
void ReorderAndReturnOutput(RefPtr<VideoData>&& aFrame);
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage);
void ResolvePromise(uint32_t aPromiseId);
bool InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample);
bool PurgeShmems();
bool EnsureSufficientShmems(size_t aVideoFrameSize);
already_AddRefed<VideoData> CreateVideoFrame(const CDMVideoFrame& aFrame,
Span<uint8_t> aData);
const uint32_t mPluginId;
GMPContentParent* mContentParent;
// Note: this pointer is a weak reference because otherwise it would cause
// a cycle, as ChromiumCDMProxy has a strong reference to the
// ChromiumCDMParent.
ChromiumCDMProxy* mProxy = nullptr;
nsDataHashtable<nsUint32HashKey, uint32_t> mPromiseToCreateSessionToken;
nsTArray<RefPtr<DecryptJob>> mDecrypts;
MozPromiseHolder<MediaDataDecoder::InitPromise> mInitVideoDecoderPromise;
MozPromiseHolder<MediaDataDecoder::DecodePromise> mDecodePromise;
RefPtr<layers::ImageContainer> mImageContainer;
VideoInfo mVideoInfo;
uint64_t mLastStreamOffset = 0;
MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushDecoderPromise;
size_t mVideoFrameBufferSize = 0;
// Count of the number of shmems in the set used to return decoded video
// frames from the CDM to Gecko.
uint32_t mVideoShmemsActive = 0;
// Maximum number of shmems to use to return decoded video frames.
uint32_t mVideoShmemLimit;
// High water mark for mVideoShmemsActive, reported via telemetry.
uint32_t mMaxVideoShmemsActive = 0;
bool mIsShutdown = false;
bool mVideoDecoderInitialized = false;
bool mActorDestroyed = false;
// The H.264 decoder in Widevine CDM versions 970 and later output in decode
// order rather than presentation order, so we reorder in presentation order
// before presenting. mMaxRefFrames is non-zero if we have an initialized
// decoder and we are decoding H.264. If so, it stores the maximum length of
// the reorder queue that we need. Note we may have multiple decoders for the
// life time of this object, but never more than one active at once.
uint32_t mMaxRefFrames = 0;
ReorderQueue mReorderQueue;
};
} // namespace gmp
} // namespace mozilla
#endif // ChromiumCDMParent_h_