gecko-dev/dom/media/gmp/ChromiumCDMParent.h

199 строки
7.4 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"
class ChromiumCDMCallback;
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(ChromiumCDMCallback* aCDMCallback,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState,
nsIEventTarget* aMainThread);
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,
Bug 1351953 - Pre-allocate shmems for the CDM process to use for storing decrypted and audio samples. r=gerald Makes transfer of samples between the content and CDM processes use shmems. The Chromium CDM API requires us to implement a synchronous interface to supply buffers to the CDM for it to write decrypted samples into. We want our buffers to be backed by shmems, in order to reduce the overhead of transferring decoded frames. However due to sandboxing restrictions, the CDM process cannot allocate shmems itself. We don't want to be doing synchronous IPC to request shmems from the content process, nor do we want to have to do intr IPC or make async IPC conform to the sync allocation interface. So instead we have the content process pre-allocate a set of shmems and give them to the CDM process in advance of them being needed. When the CDM needs to allocate a buffer for storing a decrypted sample, the CDM host gives it one of these shmems' buffers. When this is sent back to the content process, we copy the result out (uploading to a GPU surface for video frames), and send the shmem back to the CDM process so it can reuse it. We predict the size of buffer the CDM will allocate, and prepopulate the CDM's list of shmems with shmems of at least that size, plus a bit of padding for safety. We pad frames out to be the next multiple of 16, as we've seen some decoders do that. Normally the CDM won't allocate more than one buffer at once, but we've seen cases where it allocates two buffers, returns one and holds onto the other. So the minimum number of shmems we give to the CDM must be at least two, and the default is three for safety. MozReview-Commit-ID: 5FaWAst3aeh --HG-- extra : rebase_source : a0cb126e72bfb2905bcdf02e864dc654e8340410
2017-03-28 08:59:11 +03:00
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;
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 03:57:40 +03:00
ipc::IPCResult RecvIncreaseShmemPoolSize() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
Bug 1351953 - Pre-allocate shmems for the CDM process to use for storing decrypted and audio samples. r=gerald Makes transfer of samples between the content and CDM processes use shmems. The Chromium CDM API requires us to implement a synchronous interface to supply buffers to the CDM for it to write decrypted samples into. We want our buffers to be backed by shmems, in order to reduce the overhead of transferring decoded frames. However due to sandboxing restrictions, the CDM process cannot allocate shmems itself. We don't want to be doing synchronous IPC to request shmems from the content process, nor do we want to have to do intr IPC or make async IPC conform to the sync allocation interface. So instead we have the content process pre-allocate a set of shmems and give them to the CDM process in advance of them being needed. When the CDM needs to allocate a buffer for storing a decrypted sample, the CDM host gives it one of these shmems' buffers. When this is sent back to the content process, we copy the result out (uploading to a GPU surface for video frames), and send the shmem back to the CDM process so it can reuse it. We predict the size of buffer the CDM will allocate, and prepopulate the CDM's list of shmems with shmems of at least that size, plus a bit of padding for safety. We pad frames out to be the next multiple of 16, as we've seen some decoders do that. Normally the CDM won't allocate more than one buffer at once, but we've seen cases where it allocates two buffers, returns one and holds onto the other. So the minimum number of shmems we give to the CDM must be at least two, and the default is three for safety. MozReview-Commit-ID: 5FaWAst3aeh --HG-- extra : rebase_source : a0cb126e72bfb2905bcdf02e864dc654e8340410
2017-03-28 08:59:11 +03:00
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 as ChromiumCDMProxy has a strong reference to the
// ChromiumCDMCallback.
ChromiumCDMCallback* mCDMCallback = 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;
Bug 1351953 - Pre-allocate shmems for the CDM process to use for storing decrypted and audio samples. r=gerald Makes transfer of samples between the content and CDM processes use shmems. The Chromium CDM API requires us to implement a synchronous interface to supply buffers to the CDM for it to write decrypted samples into. We want our buffers to be backed by shmems, in order to reduce the overhead of transferring decoded frames. However due to sandboxing restrictions, the CDM process cannot allocate shmems itself. We don't want to be doing synchronous IPC to request shmems from the content process, nor do we want to have to do intr IPC or make async IPC conform to the sync allocation interface. So instead we have the content process pre-allocate a set of shmems and give them to the CDM process in advance of them being needed. When the CDM needs to allocate a buffer for storing a decrypted sample, the CDM host gives it one of these shmems' buffers. When this is sent back to the content process, we copy the result out (uploading to a GPU surface for video frames), and send the shmem back to the CDM process so it can reuse it. We predict the size of buffer the CDM will allocate, and prepopulate the CDM's list of shmems with shmems of at least that size, plus a bit of padding for safety. We pad frames out to be the next multiple of 16, as we've seen some decoders do that. Normally the CDM won't allocate more than one buffer at once, but we've seen cases where it allocates two buffers, returns one and holds onto the other. So the minimum number of shmems we give to the CDM must be at least two, and the default is three for safety. MozReview-Commit-ID: 5FaWAst3aeh --HG-- extra : rebase_source : a0cb126e72bfb2905bcdf02e864dc654e8340410
2017-03-28 08:59:11 +03:00
// 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;
// The main thread associated with the root document. Must be set in Init().
nsCOMPtr<nsIEventTarget> mMainThread;
};
} // namespace gmp
} // namespace mozilla
#endif // ChromiumCDMParent_h_