mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 2 - support asynchronous GMP API getters. r=jwwang,rjesup.
This commit is contained in:
parent
e98292c191
commit
ace406a462
@ -25,6 +25,7 @@ CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mCDM(nullptr)
|
||||
, mDecryptionJobCount(0)
|
||||
, mShutdownCalled(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(CDMProxy);
|
||||
@ -70,7 +71,7 @@ CDMProxy::Init(PromiseId aPromiseId,
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<InitData>>(this,
|
||||
&CDMProxy::gmp_Init,
|
||||
data));
|
||||
Move(data)));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
@ -83,14 +84,57 @@ CDMProxy::IsOnGMPThread()
|
||||
#endif
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
|
||||
CDMProxy::gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData)
|
||||
{
|
||||
EME_LOG("CDMProxy::gmp_InitDone");
|
||||
if (!aCDM || mShutdownCalled) {
|
||||
if (aCDM) {
|
||||
aCDM->Close();
|
||||
}
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mCDM = aCDM;
|
||||
mCallback = new CDMCallbackProxy(this);
|
||||
mCDM->Init(mCallback);
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<uint32_t>(this,
|
||||
&CDMProxy::OnCDMCreated,
|
||||
aData->mPromiseId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
class gmp_InitDoneCallback : public GetGMPDecryptorCallback
|
||||
{
|
||||
public:
|
||||
gmp_InitDoneCallback(CDMProxy* aCDMProxy,
|
||||
nsAutoPtr<CDMProxy::InitData>&& aData)
|
||||
: mCDMProxy(aCDMProxy),
|
||||
mData(Move(aData))
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPDecryptorProxy* aCDM)
|
||||
{
|
||||
mCDMProxy->gmp_InitDone(aCDM, Move(mData));
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
nsAutoPtr<CDMProxy::InitData> mData;
|
||||
};
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Init(nsAutoPtr<InitData>&& aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
uint32_t promiseID = aData->mPromiseId;
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (!mps) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -100,7 +144,7 @@ CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
|
||||
mNodeId);
|
||||
MOZ_ASSERT(!GetNodeId().IsEmpty());
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -112,17 +156,12 @@ CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
|
||||
rv = mps->GetGMPDecryptor(&tags, GetNodeId(), &mCDM);
|
||||
if (NS_FAILED(rv) || !mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
} else {
|
||||
mCallback = new CDMCallbackProxy(this);
|
||||
mCDM->Init(mCallback);
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<uint32_t>(this,
|
||||
&CDMProxy::OnCDMCreated,
|
||||
aData->mPromiseId));
|
||||
NS_DispatchToMainThread(task);
|
||||
|
||||
UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this,
|
||||
Move(aData)));
|
||||
rv = mps->GetGMPDecryptor(&tags, GetNodeId(), Move(callback));
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,6 +380,8 @@ CDMProxy::gmp_Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
mShutdownCalled = true;
|
||||
|
||||
// Abort any pending decrypt jobs, to awaken any clients waiting on a job.
|
||||
for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
|
||||
DecryptJob* job = mDecryptionJobs[i];
|
||||
|
@ -174,6 +174,7 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class gmp_InitDoneCallback;
|
||||
|
||||
struct InitData {
|
||||
uint32_t mPromiseId;
|
||||
@ -183,7 +184,8 @@ private:
|
||||
};
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Init(nsAutoPtr<InitData> aData);
|
||||
void gmp_Init(nsAutoPtr<InitData>&& aData);
|
||||
void gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData);
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Shutdown();
|
||||
@ -320,6 +322,10 @@ private:
|
||||
// from it.
|
||||
// GMP thread only.
|
||||
uint32_t mDecryptionJobCount;
|
||||
|
||||
// True if CDMProxy::gmp_Shutdown was called.
|
||||
// GMP thread only.
|
||||
bool mShutdownCalled;
|
||||
};
|
||||
|
||||
|
||||
|
@ -133,6 +133,39 @@ GMPAudioDecoder::GetNodeId()
|
||||
return NS_LITERAL_CSTRING("");
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::GetGMPAPI(GMPInitDoneRunnable* aInitDone)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
InitTags(tags);
|
||||
UniquePtr<GetGMPAudioDecoderCallback> callback(
|
||||
new GMPInitDoneCallback(this, aInitDone));
|
||||
if (NS_FAILED(mMPS->GetGMPAudioDecoder(&tags, GetNodeId(), Move(callback)))) {
|
||||
aInitDone->Dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPAudioDecoder::GMPInitDone(GMPAudioDecoderProxy* aGMP)
|
||||
{
|
||||
MOZ_ASSERT(aGMP);
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElements(mConfig.audio_specific_config->Elements(),
|
||||
mConfig.audio_specific_config->Length());
|
||||
|
||||
nsresult rv = aGMP->InitDecode(kGMPAudioCodecAAC,
|
||||
mConfig.channel_count,
|
||||
mConfig.bits_per_sample,
|
||||
mConfig.samples_per_second,
|
||||
codecSpecific,
|
||||
mAdapter);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mGMP = aGMP;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPAudioDecoder::Init()
|
||||
{
|
||||
@ -141,25 +174,20 @@ GMPAudioDecoder::Init()
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mMPS);
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
InitTags(tags);
|
||||
nsresult rv = mMPS->GetGMPAudioDecoder(&tags, GetNodeId(), &mGMP);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(mGMP);
|
||||
nsCOMPtr<nsIThread> gmpThread = NS_GetCurrentThread();
|
||||
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElements(mConfig.audio_specific_config->Elements(),
|
||||
mConfig.audio_specific_config->Length());
|
||||
nsRefPtr<GMPInitDoneRunnable> initDone(new GMPInitDoneRunnable());
|
||||
gmpThread->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<GMPInitDoneRunnable*>(this,
|
||||
&GMPAudioDecoder::GetGMPAPI,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
rv = mGMP->InitDecode(kGMPAudioCodecAAC,
|
||||
mConfig.channel_count,
|
||||
mConfig.bits_per_sample,
|
||||
mConfig.samples_per_second,
|
||||
codecSpecific,
|
||||
mAdapter);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(gmpThread, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return mGMP ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -80,6 +80,61 @@ protected:
|
||||
virtual nsCString GetNodeId();
|
||||
|
||||
private:
|
||||
class GMPInitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GMPInitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mThread(do_GetCurrentThread())
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mInitDone = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch()
|
||||
{
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
void GetGMPAPI(GMPInitDoneRunnable* aInitDone);
|
||||
class GMPInitDoneCallback : public GetGMPAudioDecoderCallback
|
||||
{
|
||||
public:
|
||||
GMPInitDoneCallback(GMPAudioDecoder* aDecoder,
|
||||
GMPInitDoneRunnable* aGMPInitDone)
|
||||
: mDecoder(aDecoder)
|
||||
, mGMPInitDone(aGMPInitDone)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPAudioDecoderProxy* aGMP)
|
||||
{
|
||||
if (aGMP) {
|
||||
mDecoder->GMPInitDone(aGMP);
|
||||
}
|
||||
mGMPInitDone->Dispatch();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<GMPAudioDecoder> mDecoder;
|
||||
nsRefPtr<GMPInitDoneRunnable> mGMPInitDone;
|
||||
};
|
||||
void GMPInitDone(GMPAudioDecoderProxy* aGMP);
|
||||
|
||||
const mp4_demuxer::AudioDecoderConfig& mConfig;
|
||||
MediaDataDecoderCallbackProxy* mCallback;
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
|
||||
|
@ -157,29 +157,24 @@ GMPVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
return frame;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPVideoDecoder::Init()
|
||||
void
|
||||
GMPVideoDecoder::GetGMPAPI(GMPInitDoneRunnable* aInitDone)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mMPS);
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
InitTags(tags);
|
||||
nsresult rv = mMPS->GetGMPVideoDecoder(&tags, GetNodeId(), &mHost, &mGMP);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(mHost && mGMP);
|
||||
UniquePtr<GetGMPVideoDecoderCallback> callback(
|
||||
new GMPInitDoneCallback(this, aInitDone));
|
||||
if (NS_FAILED(mMPS->GetGMPVideoDecoder(&tags, GetNodeId(), Move(callback)))) {
|
||||
aInitDone->Dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
// GMP implementations have interpreted the meaning of GMP_BufferLength32
|
||||
// differently. The OpenH264 GMP expects GMP_BufferLength32 to behave as
|
||||
// specified in the GMP API, where each buffer is prefixed by a 32-bit
|
||||
// host-endian buffer length that includes the size of the buffer length
|
||||
// field. Other existing GMPs currently expect GMP_BufferLength32 (when
|
||||
// combined with kGMPVideoCodecH264) to mean "like AVCC but restricted to
|
||||
// 4-byte NAL lengths" (i.e. buffer lengths are specified in big-endian
|
||||
// and do not include the length of the buffer length field.
|
||||
mConvertNALUnitLengths = mGMP->GetDisplayName().EqualsLiteral("gmpopenh264");
|
||||
void
|
||||
GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
MOZ_ASSERT(aHost && aGMP);
|
||||
|
||||
GMPVideoCodec codec;
|
||||
memset(&codec, 0, sizeof(codec));
|
||||
@ -195,13 +190,48 @@ GMPVideoDecoder::Init()
|
||||
codecSpecific.AppendElements(mConfig.extra_data->Elements(),
|
||||
mConfig.extra_data->Length());
|
||||
|
||||
rv = mGMP->InitDecode(codec,
|
||||
codecSpecific,
|
||||
mAdapter,
|
||||
PR_GetNumberOfProcessors());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = aGMP->InitDecode(codec,
|
||||
codecSpecific,
|
||||
mAdapter,
|
||||
PR_GetNumberOfProcessors());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
|
||||
return NS_OK;
|
||||
// GMP implementations have interpreted the meaning of GMP_BufferLength32
|
||||
// differently. The OpenH264 GMP expects GMP_BufferLength32 to behave as
|
||||
// specified in the GMP API, where each buffer is prefixed by a 32-bit
|
||||
// host-endian buffer length that includes the size of the buffer length
|
||||
// field. Other existing GMPs currently expect GMP_BufferLength32 (when
|
||||
// combined with kGMPVideoCodecH264) to mean "like AVCC but restricted to
|
||||
// 4-byte NAL lengths" (i.e. buffer lengths are specified in big-endian
|
||||
// and do not include the length of the buffer length field.
|
||||
mConvertNALUnitLengths = mGMP->GetDisplayName().EqualsLiteral("gmpopenh264");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPVideoDecoder::Init()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
MOZ_ASSERT(mMPS);
|
||||
|
||||
nsCOMPtr<nsIThread> gmpThread = NS_GetCurrentThread();
|
||||
|
||||
nsRefPtr<GMPInitDoneRunnable> initDone(new GMPInitDoneRunnable());
|
||||
gmpThread->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<GMPInitDoneRunnable*>(this,
|
||||
&GMPVideoDecoder::GetGMPAPI,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(gmpThread, true);
|
||||
}
|
||||
|
||||
return mGMP ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -96,6 +96,61 @@ protected:
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(mp4_demuxer::MP4Sample* aSample);
|
||||
|
||||
private:
|
||||
class GMPInitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
GMPInitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mThread(do_GetCurrentThread())
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mInitDone = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch()
|
||||
{
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
void GetGMPAPI(GMPInitDoneRunnable* aInitDone);
|
||||
class GMPInitDoneCallback : public GetGMPVideoDecoderCallback
|
||||
{
|
||||
public:
|
||||
GMPInitDoneCallback(GMPVideoDecoder* aDecoder,
|
||||
GMPInitDoneRunnable* aGMPInitDone)
|
||||
: mDecoder(aDecoder)
|
||||
, mGMPInitDone(aGMPInitDone)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
if (aGMP) {
|
||||
mDecoder->GMPInitDone(aGMP, aHost);
|
||||
}
|
||||
mGMPInitDone->Dispatch();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<GMPVideoDecoder> mDecoder;
|
||||
nsRefPtr<GMPInitDoneRunnable> mGMPInitDone;
|
||||
};
|
||||
void GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost);
|
||||
|
||||
const mp4_demuxer::VideoDecoderConfig& mConfig;
|
||||
MediaDataDecoderCallbackProxy* mCallback;
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
|
||||
|
@ -281,14 +281,33 @@ GeckoMediaPluginService::GetThread(nsIThread** aThread)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetGMPParentForAudioDecoderDone
|
||||
{
|
||||
public:
|
||||
explicit GetGMPParentForAudioDecoderDone(UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
|
||||
: mCallback(Move(aCallback))
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPParent* aGMPParent)
|
||||
{
|
||||
GMPAudioDecoderParent* gmpADP = nullptr;
|
||||
aGMPParent->GetGMPAudioDecoder(&gmpADP);
|
||||
mCallback->Done(gmpADP);
|
||||
}
|
||||
|
||||
private:
|
||||
UniquePtr<GetGMPAudioDecoderCallback> mCallback;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPAudioDecoderProxy** aGMPAD)
|
||||
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aGMPAD);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -301,27 +320,42 @@ GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GMPAudioDecoderParent* gmpADP;
|
||||
nsresult rv = gmp->GetGMPAudioDecoder(&gmpADP);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aGMPAD = gmpADP;
|
||||
GetGMPParentForAudioDecoderDone(Move(aCallback)).Done(gmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetGMPParentForVideoDecoderDone
|
||||
{
|
||||
public:
|
||||
explicit GetGMPParentForVideoDecoderDone(UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
|
||||
: mCallback(Move(aCallback))
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPParent* aGMPParent)
|
||||
{
|
||||
GMPVideoDecoderParent* gmpVDP = nullptr;
|
||||
GMPVideoHostImpl* videoHost = nullptr;
|
||||
nsresult rv = aGMPParent->GetGMPVideoDecoder(&gmpVDP);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
videoHost = &gmpVDP->Host();
|
||||
}
|
||||
mCallback->Done(gmpVDP, videoHost);
|
||||
}
|
||||
|
||||
private:
|
||||
UniquePtr<GetGMPVideoDecoderCallback> mCallback;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoDecoderProxy** aGMPVD)
|
||||
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aOutVideoHost);
|
||||
NS_ENSURE_ARG(aGMPVD);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -339,28 +373,42 @@ GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
||||
}
|
||||
|
||||
|
||||
GMPVideoDecoderParent* gmpVDP;
|
||||
nsresult rv = gmp->GetGMPVideoDecoder(&gmpVDP);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aGMPVD = gmpVDP;
|
||||
*aOutVideoHost = &gmpVDP->Host();
|
||||
GetGMPParentForVideoDecoderDone(Move(aCallback)).Done(gmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetGMPParentForVideoEncoderDone
|
||||
{
|
||||
public:
|
||||
explicit GetGMPParentForVideoEncoderDone(UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
|
||||
: mCallback(Move(aCallback))
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPParent* aGMPParent)
|
||||
{
|
||||
GMPVideoEncoderParent* gmpVEP = nullptr;
|
||||
GMPVideoHostImpl* videoHost = nullptr;
|
||||
nsresult rv = aGMPParent->GetGMPVideoEncoder(&gmpVEP);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
videoHost = &gmpVEP->Host();
|
||||
}
|
||||
mCallback->Done(gmpVEP, videoHost);
|
||||
}
|
||||
|
||||
private:
|
||||
UniquePtr<GetGMPVideoEncoderCallback> mCallback;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoEncoderProxy** aGMPVE)
|
||||
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aOutVideoHost);
|
||||
NS_ENSURE_ARG(aGMPVE);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -377,22 +425,34 @@ GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GMPVideoEncoderParent* gmpVEP;
|
||||
nsresult rv = gmp->GetGMPVideoEncoder(&gmpVEP);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aGMPVE = gmpVEP;
|
||||
*aOutVideoHost = &gmpVEP->Host();
|
||||
GetGMPParentForVideoEncoderDone(Move(aCallback)).Done(gmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetGMPParentForDecryptorDone
|
||||
{
|
||||
public:
|
||||
explicit GetGMPParentForDecryptorDone(UniquePtr<GetGMPDecryptorCallback>&& aCallback)
|
||||
: mCallback(Move(aCallback))
|
||||
{
|
||||
}
|
||||
|
||||
void Done(GMPParent* aGMPParent)
|
||||
{
|
||||
GMPDecryptorParent* ksp = nullptr;
|
||||
aGMPParent->GetGMPDecryptor(&ksp);
|
||||
mCallback->Done(ksp);
|
||||
}
|
||||
|
||||
private:
|
||||
UniquePtr<GetGMPDecryptorCallback> mCallback;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPDecryptorProxy** aDecryptor)
|
||||
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
|
||||
{
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
if (!SandboxInfo::Get().CanSandboxMedia()) {
|
||||
@ -404,7 +464,7 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||
NS_ENSURE_ARG(aDecryptor);
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
|
||||
if (mShuttingDownOnGMPThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -417,13 +477,7 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
GMPDecryptorParent* ksp;
|
||||
nsresult rv = gmp->GetGMPDecryptor(&ksp);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aDecryptor = static_cast<GMPDecryptorProxy*>(ksp);
|
||||
GetGMPParentForDecryptorDone(Move(aCallback)).Done(gmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -44,18 +44,20 @@ public:
|
||||
bool *aRetVal) override;
|
||||
NS_IMETHOD GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoDecoderProxy** aGMPVD) override;
|
||||
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
|
||||
override;
|
||||
NS_IMETHOD GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost **aOutVideoHost,
|
||||
GMPVideoEncoderProxy** aGMPVE) override;
|
||||
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
|
||||
override;
|
||||
NS_IMETHOD GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPAudioDecoderProxy **aGMPAD) override;
|
||||
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
|
||||
override;
|
||||
NS_IMETHOD GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
const nsACString& aNodeId,
|
||||
GMPDecryptorProxy** aDecryptor) override;
|
||||
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
|
||||
override;
|
||||
|
||||
int32_t AsyncShutdownTimeoutMs();
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "nsIThread.idl"
|
||||
|
||||
%{C++
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsStringGlue.h"
|
||||
class GMPAudioDecoderProxy;
|
||||
@ -14,16 +15,36 @@ class GMPDecryptorProxy;
|
||||
class GMPVideoDecoderProxy;
|
||||
class GMPVideoEncoderProxy;
|
||||
class GMPVideoHost;
|
||||
|
||||
template<class T>
|
||||
class GMPGetterCallback
|
||||
{
|
||||
public:
|
||||
GMPGetterCallback() { MOZ_COUNT_CTOR(GMPGetterCallback<T>); }
|
||||
virtual ~GMPGetterCallback() { MOZ_COUNT_DTOR(GMPGetterCallback<T>); }
|
||||
virtual void Done(T*) = 0;
|
||||
};
|
||||
template<class T>
|
||||
class GMPVideoGetterCallback
|
||||
{
|
||||
public:
|
||||
GMPVideoGetterCallback() { MOZ_COUNT_CTOR(GMPVideoGetterCallback<T>); }
|
||||
virtual ~GMPVideoGetterCallback() { MOZ_COUNT_DTOR(GMPVideoGetterCallback<T>); }
|
||||
virtual void Done(T*, GMPVideoHost*) = 0;
|
||||
};
|
||||
typedef GMPGetterCallback<GMPDecryptorProxy> GetGMPDecryptorCallback;
|
||||
typedef GMPGetterCallback<GMPAudioDecoderProxy> GetGMPAudioDecoderCallback;
|
||||
typedef GMPVideoGetterCallback<GMPVideoDecoderProxy> GetGMPVideoDecoderCallback;
|
||||
typedef GMPVideoGetterCallback<GMPVideoEncoderProxy> GetGMPVideoEncoderCallback;
|
||||
%}
|
||||
|
||||
[ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
|
||||
[ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
|
||||
[ptr] native GMPVideoHost(GMPVideoHost);
|
||||
[ptr] native TagArray(nsTArray<nsCString>);
|
||||
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
||||
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
||||
native GetGMPDecryptorCallback(mozilla::UniquePtr<GetGMPDecryptorCallback>&&);
|
||||
native GetGMPAudioDecoderCallback(mozilla::UniquePtr<GetGMPAudioDecoderCallback>&&);
|
||||
native GetGMPVideoDecoderCallback(mozilla::UniquePtr<GetGMPVideoDecoderCallback>&&);
|
||||
native GetGMPVideoEncoderCallback(mozilla::UniquePtr<GetGMPVideoEncoderCallback>&&);
|
||||
|
||||
[scriptable, uuid(fed4d2d8-87d8-42fe-a141-98c15b5f7a1e)]
|
||||
[scriptable, uuid(11bb248b-7a4b-4f62-bebb-8211551d8c20)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
|
||||
@ -52,35 +73,63 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
* The array of tags should at least contain a codec tag, and optionally
|
||||
* other tags such as for EME keysystem.
|
||||
* Callable only on GMP thread.
|
||||
* This is an asynchronous operation, the Done method of the callback object
|
||||
* will be called on the GMP thread with the result (which might be null in
|
||||
* the case of failure). This method always takes ownership of the callback
|
||||
* object, but if this method returns an error then the Done method of the
|
||||
* callback object will not be called at all.
|
||||
*/
|
||||
[noscript]
|
||||
GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
out GMPVideoHost outVideoHost);
|
||||
void getGMPVideoDecoder(in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
in GetGMPVideoDecoderCallback callback);
|
||||
|
||||
/**
|
||||
* Get a video encoder that supports the specified tags.
|
||||
* The array of tags should at least contain a codec tag, and optionally
|
||||
* other tags.
|
||||
* Callable only on GMP thread.
|
||||
* This is an asynchronous operation, the Done method of the callback object
|
||||
* will be called on the GMP thread with the result (which might be null in
|
||||
* the case of failure). This method always takes ownership of the callback
|
||||
* object, but if this method returns an error then the Done method of the
|
||||
* callback object will not be called at all.
|
||||
*/
|
||||
[noscript]
|
||||
GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
out GMPVideoHost outVideoHost);
|
||||
void getGMPVideoEncoder(in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
in GetGMPVideoEncoderCallback callback);
|
||||
|
||||
// Returns an audio decoder that supports the specified tags.
|
||||
// The array of tags should at least contain a codec tag, and optionally
|
||||
// other tags such as for EME keysystem.
|
||||
// Callable only on GMP thread.
|
||||
GMPAudioDecoderProxy getGMPAudioDecoder(in TagArray tags,
|
||||
[optional] in ACString nodeId);
|
||||
/**
|
||||
* Returns an audio decoder that supports the specified tags.
|
||||
* The array of tags should at least contain a codec tag, and optionally
|
||||
* other tags such as for EME keysystem.
|
||||
* Callable only on GMP thread.
|
||||
* This is an asynchronous operation, the Done method of the callback object
|
||||
* will be called on the GMP thread with the result (which might be null in
|
||||
* the case of failure). This method always takes ownership of the callback
|
||||
* object, but if this method returns an error then the Done method of the
|
||||
* callback object will not be called at all.
|
||||
*/
|
||||
[noscript]
|
||||
void getGMPAudioDecoder(in TagArray tags,
|
||||
[optional] in ACString nodeId,
|
||||
in GetGMPAudioDecoderCallback callback);
|
||||
|
||||
// Returns a decryption session manager that supports the specified tags.
|
||||
// The array of tags should at least contain a key system tag, and optionally
|
||||
// other tags.
|
||||
// Callable only on GMP thread.
|
||||
GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in ACString nodeId);
|
||||
/**
|
||||
* Returns a decryption session manager that supports the specified tags.
|
||||
* The array of tags should at least contain a key system tag, and optionally
|
||||
* other tags.
|
||||
* Callable only on GMP thread.
|
||||
* This is an asynchronous operation, the Done method of the callback object
|
||||
* will be called on the GMP thread with the result (which might be null in
|
||||
* the case of failure). This method always takes ownership of the callback
|
||||
* object, but if this method returns an error then the Done method of the
|
||||
* callback object will not be called at all.
|
||||
*/
|
||||
[noscript]
|
||||
void getGMPDecryptor(in TagArray tags, in ACString nodeId,
|
||||
in GetGMPDecryptorCallback callback);
|
||||
|
||||
/**
|
||||
* Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
|
||||
|
@ -28,87 +28,234 @@ using namespace std;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gmp;
|
||||
|
||||
class GMPTestMonitor
|
||||
{
|
||||
public:
|
||||
GMPTestMonitor()
|
||||
: mFinished(false)
|
||||
{
|
||||
}
|
||||
|
||||
void AwaitFinished()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
while (!mFinished) {
|
||||
NS_ProcessNextEvent(nullptr, true);
|
||||
}
|
||||
mFinished = false;
|
||||
}
|
||||
|
||||
private:
|
||||
void MarkFinished()
|
||||
{
|
||||
mFinished = true;
|
||||
}
|
||||
|
||||
public:
|
||||
void SetFinished()
|
||||
{
|
||||
NS_DispatchToMainThread(NS_NewNonOwningRunnableMethod(this,
|
||||
&GMPTestMonitor::MarkFinished));
|
||||
}
|
||||
|
||||
private:
|
||||
bool mFinished;
|
||||
};
|
||||
|
||||
struct GMPTestRunner
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPTestRunner)
|
||||
|
||||
void DoTest(void (GMPTestRunner::*aTestMethod)());
|
||||
void RunTestGMPTestCodec();
|
||||
void RunTestGMPCrossOrigin();
|
||||
void DoTest(void (GMPTestRunner::*aTestMethod)(GMPTestMonitor&));
|
||||
void RunTestGMPTestCodec1(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPTestCodec2(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPTestCodec3(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPCrossOrigin1(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPCrossOrigin2(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPCrossOrigin3(GMPTestMonitor& aMonitor);
|
||||
void RunTestGMPCrossOrigin4(GMPTestMonitor& aMonitor);
|
||||
|
||||
private:
|
||||
~GMPTestRunner() { }
|
||||
};
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPTestCodec()
|
||||
template<class T, class Base,
|
||||
nsresult (NS_STDCALL GeckoMediaPluginService::*Getter)(nsTArray<nsCString>*,
|
||||
const nsACString&,
|
||||
UniquePtr<Base>&&)>
|
||||
class RunTestGMPVideoCodec : public Base
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
public:
|
||||
virtual void Done(T* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
EXPECT_TRUE(aGMP);
|
||||
EXPECT_TRUE(aHost);
|
||||
if (aGMP) {
|
||||
aGMP->Close();
|
||||
}
|
||||
mMonitor.SetFinished();
|
||||
}
|
||||
|
||||
GMPVideoHost* host = nullptr;
|
||||
GMPVideoDecoderProxy* decoder = nullptr;
|
||||
GMPVideoDecoderProxy* decoder2 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder = nullptr;
|
||||
static void Run(GMPTestMonitor& aMonitor, const nsCString& aOrigin)
|
||||
{
|
||||
UniquePtr<GMPCallbackType> callback(new RunTestGMPVideoCodec(aMonitor));
|
||||
Get(aOrigin, Move(callback));
|
||||
}
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
protected:
|
||||
typedef T GMPCodecType;
|
||||
typedef Base GMPCallbackType;
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("o"), &host, &decoder2);
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING(""), &host, &decoder);
|
||||
explicit RunTestGMPVideoCodec(GMPTestMonitor& aMonitor)
|
||||
: mMonitor(aMonitor)
|
||||
{
|
||||
}
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING(""), &host, &encoder);
|
||||
static nsresult Get(const nsACString& aNodeId, UniquePtr<Base>&& aCallback)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
|
||||
EXPECT_TRUE(host);
|
||||
EXPECT_TRUE(decoder);
|
||||
EXPECT_TRUE(decoder2);
|
||||
EXPECT_TRUE(encoder);
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
return ((*service).*Getter)(&tags, aNodeId, Move(aCallback));
|
||||
}
|
||||
|
||||
if (decoder) decoder->Close();
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder) encoder->Close();
|
||||
protected:
|
||||
GMPTestMonitor& mMonitor;
|
||||
};
|
||||
|
||||
typedef RunTestGMPVideoCodec<GMPVideoDecoderProxy,
|
||||
GetGMPVideoDecoderCallback,
|
||||
&GeckoMediaPluginService::GetGMPVideoDecoder>
|
||||
RunTestGMPVideoDecoder;
|
||||
typedef RunTestGMPVideoCodec<GMPVideoEncoderProxy,
|
||||
GetGMPVideoEncoderCallback,
|
||||
&GeckoMediaPluginService::GetGMPVideoEncoder>
|
||||
RunTestGMPVideoEncoder;
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPTestCodec1(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoDecoder::Run(aMonitor, NS_LITERAL_CSTRING("o"));
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin()
|
||||
GMPTestRunner::RunTestGMPTestCodec2(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
RunTestGMPVideoDecoder::Run(aMonitor, NS_LITERAL_CSTRING(""));
|
||||
}
|
||||
|
||||
GMPVideoHost* host = nullptr;
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
void
|
||||
GMPTestRunner::RunTestGMPTestCodec3(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoEncoder::Run(aMonitor, NS_LITERAL_CSTRING(""));
|
||||
}
|
||||
|
||||
GMPVideoDecoderProxy* decoder1 = nullptr;
|
||||
GMPVideoDecoderProxy* decoder2 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder1 = nullptr;
|
||||
GMPVideoEncoderProxy* encoder2 = nullptr;
|
||||
template<class Base>
|
||||
class RunTestGMPCrossOrigin : public Base
|
||||
{
|
||||
public:
|
||||
virtual void Done(typename Base::GMPCodecType* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
EXPECT_TRUE(aGMP);
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder1);
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &decoder2);
|
||||
EXPECT_TRUE(!!decoder1 && !!decoder2 &&
|
||||
decoder1->ParentID() != decoder2->ParentID());
|
||||
UniquePtr<typename Base::GMPCallbackType> callback(
|
||||
new Step2(Base::mMonitor, aGMP, mShouldBeEqual));
|
||||
nsresult rv = Base::Get(mOrigin2, Move(callback));
|
||||
EXPECT_TRUE(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
Base::mMonitor.SetFinished();
|
||||
}
|
||||
}
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder1);
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &encoder2);
|
||||
EXPECT_TRUE(!!encoder1 && !!encoder2 &&
|
||||
encoder1->ParentID() != encoder2->ParentID());
|
||||
static void Run(GMPTestMonitor& aMonitor, const nsCString& aOrigin1,
|
||||
const nsCString& aOrigin2)
|
||||
{
|
||||
UniquePtr<typename Base::GMPCallbackType> callback(
|
||||
new RunTestGMPCrossOrigin<Base>(aMonitor, aOrigin1, aOrigin2));
|
||||
nsresult rv = Base::Get(aOrigin1, Move(callback));
|
||||
EXPECT_TRUE(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
aMonitor.SetFinished();
|
||||
}
|
||||
}
|
||||
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder2) encoder2->Close();
|
||||
private:
|
||||
RunTestGMPCrossOrigin(GMPTestMonitor& aMonitor, const nsCString& aOrigin1,
|
||||
const nsCString& aOrigin2)
|
||||
: Base(aMonitor),
|
||||
mGMP(nullptr),
|
||||
mOrigin2(aOrigin2),
|
||||
mShouldBeEqual(aOrigin1.Equals(aOrigin2))
|
||||
{
|
||||
}
|
||||
|
||||
service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder2);
|
||||
EXPECT_TRUE(!!decoder1 && !!decoder2 &&
|
||||
decoder1->ParentID() == decoder2->ParentID());
|
||||
class Step2 : public Base
|
||||
{
|
||||
public:
|
||||
Step2(GMPTestMonitor& aMonitor,
|
||||
typename Base::GMPCodecType* aGMP,
|
||||
bool aShouldBeEqual)
|
||||
: Base(aMonitor),
|
||||
mGMP(aGMP),
|
||||
mShouldBeEqual(aShouldBeEqual)
|
||||
{
|
||||
}
|
||||
virtual void Done(typename Base::GMPCodecType* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
EXPECT_TRUE(aGMP);
|
||||
if (aGMP) {
|
||||
EXPECT_TRUE(mGMP &&
|
||||
(mGMP->ParentID() == aGMP->ParentID()) == mShouldBeEqual);
|
||||
}
|
||||
if (mGMP) {
|
||||
mGMP->Close();
|
||||
}
|
||||
Base::Done(aGMP, aHost);
|
||||
}
|
||||
|
||||
service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder2);
|
||||
EXPECT_TRUE(!!encoder1 && !!encoder2 &&
|
||||
encoder1->ParentID() == encoder2->ParentID());
|
||||
private:
|
||||
typename Base::GMPCodecType* mGMP;
|
||||
bool mShouldBeEqual;
|
||||
};
|
||||
|
||||
if (decoder1) decoder1->Close();
|
||||
if (decoder2) decoder2->Close();
|
||||
if (encoder1) encoder1->Close();
|
||||
if (encoder2) encoder2->Close();
|
||||
typename Base::GMPCodecType* mGMP;
|
||||
nsCString mOrigin2;
|
||||
bool mShouldBeEqual;
|
||||
};
|
||||
|
||||
typedef RunTestGMPCrossOrigin<RunTestGMPVideoDecoder>
|
||||
RunTestGMPVideoDecoderCrossOrigin;
|
||||
typedef RunTestGMPCrossOrigin<RunTestGMPVideoEncoder>
|
||||
RunTestGMPVideoEncoderCrossOrigin;
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin1(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoDecoderCrossOrigin::Run(
|
||||
aMonitor, NS_LITERAL_CSTRING("origin1"), NS_LITERAL_CSTRING("origin2"));
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin2(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoEncoderCrossOrigin::Run(
|
||||
aMonitor, NS_LITERAL_CSTRING("origin1"), NS_LITERAL_CSTRING("origin2"));
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin3(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoDecoderCrossOrigin::Run(
|
||||
aMonitor, NS_LITERAL_CSTRING("origin1"), NS_LITERAL_CSTRING("origin1"));
|
||||
}
|
||||
|
||||
void
|
||||
GMPTestRunner::RunTestGMPCrossOrigin4(GMPTestMonitor& aMonitor)
|
||||
{
|
||||
RunTestGMPVideoEncoderCrossOrigin::Run(
|
||||
aMonitor, NS_LITERAL_CSTRING("origin1"), NS_LITERAL_CSTRING("origin1"));
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIThread>
|
||||
@ -438,9 +585,73 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
SetFinished();
|
||||
}
|
||||
|
||||
class CreateDecryptorDone : public GetGMPDecryptorCallback
|
||||
{
|
||||
public:
|
||||
CreateDecryptorDone(GMPStorageTest* aRunner, nsIRunnable* aContinuation)
|
||||
: mRunner(aRunner),
|
||||
mContinuation(aContinuation)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPDecryptorProxy* aDecryptor) override
|
||||
{
|
||||
mRunner->mDecryptor = aDecryptor;
|
||||
EXPECT_TRUE(!!mRunner->mDecryptor);
|
||||
|
||||
if (mRunner->mDecryptor) {
|
||||
mRunner->mDecryptor->Init(mRunner);
|
||||
}
|
||||
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
||||
thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<GMPStorageTest> mRunner;
|
||||
nsCOMPtr<nsIRunnable> mContinuation;
|
||||
};
|
||||
|
||||
void CreateDecryptor(const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPBMode) {
|
||||
bool aInPBMode,
|
||||
const nsCString& aUpdate)
|
||||
{
|
||||
nsTArray<nsCString> updates;
|
||||
updates.AppendElement(aUpdate);
|
||||
CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, Move(updates));
|
||||
}
|
||||
class Updates : public nsRunnable
|
||||
{
|
||||
public:
|
||||
Updates(GMPStorageTest* aRunner, nsTArray<nsCString>&& aUpdates)
|
||||
: mRunner(aRunner),
|
||||
mUpdates(aUpdates)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
for (auto& update : mUpdates) {
|
||||
mRunner->Update(update);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<GMPStorageTest> mRunner;
|
||||
nsTArray<nsCString> mUpdates;
|
||||
};
|
||||
void CreateDecryptor(const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPBMode,
|
||||
nsTArray<nsCString>&& aUpdates) {
|
||||
nsCOMPtr<nsIRunnable> updates(new Updates(this, Move(aUpdates)));
|
||||
CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, updates);
|
||||
}
|
||||
void CreateDecryptor(const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPBMode,
|
||||
nsIRunnable* aContinuation) {
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
EXPECT_TRUE(service);
|
||||
@ -451,13 +662,11 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("fake"));
|
||||
|
||||
nsresult rv = service->GetGMPDecryptor(&tags, mNodeId, &mDecryptor);
|
||||
UniquePtr<GetGMPDecryptorCallback> callback(
|
||||
new CreateDecryptorDone(this, aContinuation));
|
||||
nsresult rv =
|
||||
service->GetGMPDecryptor(&tags, mNodeId, Move(callback));
|
||||
EXPECT_TRUE(NS_SUCCEEDED(rv));
|
||||
EXPECT_TRUE(!!mDecryptor);
|
||||
|
||||
if (mDecryptor) {
|
||||
mDecryptor->Init(this);
|
||||
}
|
||||
}
|
||||
|
||||
void TestBasicStorage() {
|
||||
@ -467,16 +676,16 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false);
|
||||
|
||||
// Send a message to the fake GMP for it to run its own tests internally.
|
||||
// It sends us a "test-storage complete" message when its passed, or
|
||||
// some other message if its tests fail.
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -490,28 +699,28 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
EXPECT_TRUE(IsGMPStorageIsEmpty());
|
||||
|
||||
// Generate storage data for some site.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &GMPStorageTest::TestForgetThisSite_AnotherSite);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
void TestForgetThisSite_AnotherSite() {
|
||||
Shutdown();
|
||||
|
||||
// Generate storage data for another site.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
false);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &GMPStorageTest::TestForgetThisSite_CollectSiteInfo);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
struct NodeInfo {
|
||||
@ -623,16 +832,15 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
EXPECT_TRUE(IsGMPStorageIsEmpty());
|
||||
|
||||
// Generate storage data for some site.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &GMPStorageTest::TestClearRecentHistory1_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
}
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Generate some storage data.
|
||||
@ -646,15 +854,14 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
EXPECT_TRUE(IsGMPStorageIsEmpty());
|
||||
|
||||
// Generate storage data for some site.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &GMPStorageTest::TestClearRecentHistory2_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -669,15 +876,14 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
EXPECT_TRUE(IsGMPStorageIsEmpty());
|
||||
|
||||
// Generate storage data for some site.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &GMPStorageTest::TestClearRecentHistory3_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
Update(NS_LITERAL_CSTRING("test-storage"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
|
||||
class MaxMTimeFinder {
|
||||
@ -775,12 +981,6 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
void TestCrossOriginStorage() {
|
||||
EXPECT_TRUE(!mDecryptor);
|
||||
|
||||
// Open decryptor on one, origin, write a record, and test that that
|
||||
// record can't be read on another origin.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
false);
|
||||
|
||||
// Send the decryptor the message "store recordid $time"
|
||||
// Wait for the decrytor to send us "stored recordid $time"
|
||||
auto t = time(0);
|
||||
@ -791,7 +991,13 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
nsCString update("store crossOriginTestRecordId ");
|
||||
update.AppendInt((int64_t)t);
|
||||
Update(update);
|
||||
|
||||
// Open decryptor on one, origin, write a record, and test that that
|
||||
// record can't be read on another origin.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
|
||||
void TestCrossOriginStorage_RecordStoredContinuation() {
|
||||
@ -799,87 +1005,102 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
// and try to read the record.
|
||||
Shutdown();
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example5.com"),
|
||||
NS_LITERAL_STRING("example6.com"),
|
||||
false);
|
||||
|
||||
Expect(NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId succeeded (length 0 bytes)"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example5.com"),
|
||||
NS_LITERAL_STRING("example6.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId"));
|
||||
}
|
||||
|
||||
void TestPBStorage() {
|
||||
// Open decryptor on one, origin, write a record, close decryptor,
|
||||
// open another, and test that record can be read, close decryptor,
|
||||
// then send pb-last-context-closed notification, then open decryptor
|
||||
// and check that it can't read that data; it should have been purged.
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true);
|
||||
|
||||
// Send the decryptor the message "store recordid $time"
|
||||
// Wait for the decrytor to send us "stored recordid $time"
|
||||
nsCString response("stored pbdata test-pb-data");
|
||||
Expect(response, NS_NewRunnableMethod(this,
|
||||
&GMPStorageTest::TestPBStorage_RecordStoredContinuation));
|
||||
|
||||
nsCString update("store pbdata test-pb-data");
|
||||
Update(update);
|
||||
// Open decryptor on one, origin, write a record, close decryptor,
|
||||
// open another, and test that record can be read, close decryptor,
|
||||
// then send pb-last-context-closed notification, then open decryptor
|
||||
// and check that it can't read that data; it should have been purged.
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("store pbdata test-pb-data"));
|
||||
}
|
||||
|
||||
void TestPBStorage_RecordStoredContinuation() {
|
||||
Shutdown();
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true);
|
||||
|
||||
Expect(NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 12 bytes)"),
|
||||
NS_NewRunnableMethod(this,
|
||||
&GMPStorageTest::TestPBStorage_RecordRetrievedContinuation));
|
||||
Update(NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
}
|
||||
|
||||
void TestPBStorage_RecordRetrievedContinuation() {
|
||||
Shutdown();
|
||||
SimulatePBModeExit();
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true);
|
||||
|
||||
Expect(NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 0 bytes)"),
|
||||
NS_NewRunnableMethod(this,
|
||||
&GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
}
|
||||
|
||||
void NextAsyncShutdownTimeoutTest(nsIRunnable* aContinuation)
|
||||
{
|
||||
if (mDecryptor) {
|
||||
Update(NS_LITERAL_CSTRING("shutdown-mode timeout"));
|
||||
Shutdown();
|
||||
}
|
||||
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
||||
thread->Dispatch(aContinuation, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void CreateAsyncShutdownTimeoutGMP(const nsAString& aOrigin1,
|
||||
const nsAString& aOrigin2) {
|
||||
CreateDecryptor(aOrigin1, aOrigin2, false);
|
||||
Update(NS_LITERAL_CSTRING("shutdown-mode timeout"));
|
||||
Shutdown();
|
||||
const nsAString& aOrigin2,
|
||||
void (GMPStorageTest::*aCallback)()) {
|
||||
nsCOMPtr<nsIRunnable> continuation(
|
||||
NS_NewRunnableMethodWithArg<nsCOMPtr<nsIRunnable>>(
|
||||
this,
|
||||
&GMPStorageTest::NextAsyncShutdownTimeoutTest,
|
||||
NS_NewRunnableMethod(this, aCallback)));
|
||||
|
||||
CreateDecryptor(aOrigin1, aOrigin2, false, continuation);
|
||||
}
|
||||
|
||||
void TestAsyncShutdownTimeout() {
|
||||
// Create decryptors that timeout in their async shutdown.
|
||||
// If the gtest hangs on shutdown, test fails!
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example7.com"),
|
||||
NS_LITERAL_STRING("example8.com"));
|
||||
NS_LITERAL_STRING("example8.com"),
|
||||
&GMPStorageTest::TestAsyncShutdownTimeout2);
|
||||
};
|
||||
|
||||
void TestAsyncShutdownTimeout2() {
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example9.com"),
|
||||
NS_LITERAL_STRING("example10.com"));
|
||||
NS_LITERAL_STRING("example10.com"),
|
||||
&GMPStorageTest::TestAsyncShutdownTimeout3);
|
||||
};
|
||||
|
||||
void TestAsyncShutdownTimeout3() {
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example11.com"),
|
||||
NS_LITERAL_STRING("example12.com"));
|
||||
SetFinished();
|
||||
NS_LITERAL_STRING("example12.com"),
|
||||
&GMPStorageTest::SetFinished);
|
||||
};
|
||||
|
||||
void TestAsyncShutdownStorage() {
|
||||
// Test that a GMP can write to storage during shutdown, and retrieve
|
||||
// that written data in a subsequent session.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
false);
|
||||
|
||||
// Instruct the GMP to write a token (the current timestamp, so it's
|
||||
// unique) during async shutdown, then shutdown the plugin, re-create
|
||||
// it, and check that the token was successfully stored.
|
||||
@ -896,7 +1117,12 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(response, NS_NewRunnableMethodWithArg<nsCString>(this,
|
||||
&GMPStorageTest::TestAsyncShutdownStorage_ReceivedShutdownToken, token));
|
||||
|
||||
Update(update);
|
||||
// Test that a GMP can write to storage during shutdown, and retrieve
|
||||
// that written data in a subsequent session.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
|
||||
void TestAsyncShutdownStorage_ReceivedShutdownToken(const nsCString& aToken) {
|
||||
@ -907,37 +1133,39 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
void TestAsyncShutdownStorage_AsyncShutdownComplete(const nsCString& aToken) {
|
||||
// Create a new instance of the plugin, retrieve the token written
|
||||
// during shutdown and verify it is correct.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
false);
|
||||
nsCString response("retrieved shutdown-token ");
|
||||
response.Append(aToken);
|
||||
Expect(response,
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("retrieve-shutdown-token"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve-shutdown-token"));
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
void TestOutputProtection() {
|
||||
Shutdown();
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example15.com"),
|
||||
NS_LITERAL_STRING("example16.com"),
|
||||
false);
|
||||
|
||||
Expect(NS_LITERAL_CSTRING("OP tests completed"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("test-op-apis"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example15.com"),
|
||||
NS_LITERAL_STRING("example16.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-op-apis"));
|
||||
}
|
||||
#endif
|
||||
|
||||
void TestPluginVoucher() {
|
||||
CreateDecryptor(NS_LITERAL_STRING("example17.com"),
|
||||
NS_LITERAL_STRING("example18.com"),
|
||||
false);
|
||||
Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example17.com"),
|
||||
NS_LITERAL_STRING("example18.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
|
||||
}
|
||||
|
||||
void TestGetRecordNamesInMemoryStorage() {
|
||||
@ -954,12 +1182,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
}
|
||||
|
||||
void TestGetRecordNames(bool aPrivateBrowsing) {
|
||||
CreateDecryptor(NS_LITERAL_STRING("foo.com"),
|
||||
NS_LITERAL_STRING("bar.com"),
|
||||
aPrivateBrowsing);
|
||||
|
||||
// Create a number of records of different names.
|
||||
const uint32_t num = 100;
|
||||
nsTArray<nsCString> updates(num);
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
nsAutoCString response;
|
||||
response.AppendLiteral("stored data");
|
||||
@ -973,7 +1198,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
mRecordNames.AppendLiteral("data");
|
||||
AppendIntPadded(mRecordNames, i);
|
||||
|
||||
nsAutoCString update;
|
||||
nsCString& update = *updates.AppendElement();
|
||||
update.AppendLiteral("store data");
|
||||
AppendIntPadded(update, i);
|
||||
update.AppendLiteral(" test-data");
|
||||
@ -985,8 +1210,12 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames);
|
||||
}
|
||||
Expect(response, continuation);
|
||||
Update(update);
|
||||
}
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("foo.com"),
|
||||
NS_LITERAL_STRING("bar.com"),
|
||||
aPrivateBrowsing,
|
||||
Move(updates));
|
||||
}
|
||||
|
||||
void TestGetRecordNames_QueryNames() {
|
||||
@ -1026,10 +1255,6 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
MOZ_ASSERT(longRecordName.Length() < GMP_MAX_RECORD_NAME_SIZE);
|
||||
MOZ_ASSERT(longRecordName.Length() > 260); // Windows MAX_PATH
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("fuz.com"),
|
||||
NS_LITERAL_STRING("baz.com"),
|
||||
false);
|
||||
|
||||
nsCString response("stored ");
|
||||
response.Append(longRecordName);
|
||||
response.AppendLiteral(" ");
|
||||
@ -1040,7 +1265,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
update.Append(longRecordName);
|
||||
update.AppendLiteral(" ");
|
||||
update.Append(data);
|
||||
Update(update);
|
||||
CreateDecryptor(NS_LITERAL_STRING("fuz.com"),
|
||||
NS_LITERAL_STRING("baz.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
|
||||
void Expect(const nsCString& aMessage, nsIRunnable* aContinuation) {
|
||||
@ -1147,24 +1375,31 @@ private:
|
||||
};
|
||||
|
||||
void
|
||||
GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)())
|
||||
GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)(GMPTestMonitor&))
|
||||
{
|
||||
nsRefPtr<GeckoMediaPluginService> service =
|
||||
GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
||||
|
||||
service->GetThread(getter_AddRefs(thread));
|
||||
thread->Dispatch(NS_NewRunnableMethod(this, aTestMethod), NS_DISPATCH_SYNC);
|
||||
GMPTestMonitor monitor;
|
||||
thread->Dispatch(NS_NewRunnableMethodWithArg<GMPTestMonitor&>(this,
|
||||
aTestMethod,
|
||||
monitor),
|
||||
NS_DISPATCH_NORMAL);
|
||||
monitor.AwaitFinished();
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPTestCodec) {
|
||||
nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec1);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec2);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec3);
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPCrossOrigin) {
|
||||
nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin1);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin2);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin3);
|
||||
runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin4);
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPStorageGetNodeId) {
|
||||
|
@ -151,36 +151,57 @@ WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
mGMPThread->Dispatch(WrapRunnableRet(this,
|
||||
&WebrtcGmpVideoEncoder::InitEncode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize,
|
||||
&ret),
|
||||
NS_DISPATCH_SYNC);
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
MOZ_ASSERT(currentThread != mGMPThread);
|
||||
|
||||
return ret;
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
mGMPThread->Dispatch(WrapRunnable(this,
|
||||
&WebrtcGmpVideoEncoder::InitEncode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
return initDone->Result();
|
||||
}
|
||||
|
||||
int32_t
|
||||
void
|
||||
WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize)
|
||||
uint32_t aMaxPayloadSize,
|
||||
InitDoneRunnable* aInitDone)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
UniquePtr<GetGMPVideoEncoderCallback> callback(
|
||||
new InitDoneCallback(this, aInitDone, aCodecSettings, aMaxPayloadSize));
|
||||
nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mGMPThread = nullptr;
|
||||
mHost = nullptr;
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::GmpInitDone(GMPVideoEncoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
uint32_t aMaxPayloadSize)
|
||||
{
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
if (!mGMP || !mHost) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
@ -189,8 +210,6 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
memset(&mCodecParams, 0, sizeof(mCodecParams));
|
||||
|
||||
mCodecParams.mGMPApiVersion = 33;
|
||||
mCodecParams.mWidth = aCodecSettings->width;
|
||||
mCodecParams.mHeight = aCodecSettings->height;
|
||||
mCodecParams.mStartBitrate = aCodecSettings->startBitrate;
|
||||
mCodecParams.mMinBitrate = aCodecSettings->minBitrate;
|
||||
mCodecParams.mMaxBitrate = aCodecSettings->maxBitrate;
|
||||
@ -206,6 +225,14 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
mCodecParams.mMode = kGMPRealtimeVideo;
|
||||
}
|
||||
|
||||
return InitEncoderForSize(aCodecSettings->width, aCodecSettings->height);
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::InitEncoderForSize(unsigned short aWidth, unsigned short aHeight)
|
||||
{
|
||||
mCodecParams.mWidth = aWidth;
|
||||
mCodecParams.mHeight = aHeight;
|
||||
// Pass dummy codecSpecific data for now...
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
|
||||
@ -223,8 +250,37 @@ WebrtcGmpVideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
if (!mGMP) {
|
||||
// destroyed via Terminate()
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aInputImage.width() >= 0 && aInputImage.height() >= 0);
|
||||
if (static_cast<uint32_t>(aInputImage.width()) != mCodecParams.mWidth ||
|
||||
static_cast<uint32_t>(aInputImage.height()) != mCodecParams.mHeight) {
|
||||
LOGD(("GMP Encode: resolution change from %ux%u to %dx%d",
|
||||
mCodecParams.mWidth, mCodecParams.mHeight, aInputImage.width(), aInputImage.height()));
|
||||
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
WrapRunnable(this,
|
||||
&WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange,
|
||||
&aInputImage,
|
||||
initDone));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
if (initDone->Result() != WEBRTC_VIDEO_CODEC_OK) {
|
||||
return initDone->Result();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableRet(this,
|
||||
&WebrtcGmpVideoEncoder::Encode_g,
|
||||
@ -236,49 +292,38 @@ WebrtcGmpVideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange(const webrtc::I420VideoFrame* aInputImage,
|
||||
InitDoneRunnable* aInitDone)
|
||||
{
|
||||
mGMP->Close();
|
||||
|
||||
UniquePtr<GetGMPVideoEncoderCallback> callback(
|
||||
new InitDoneForResolutionChangeCallback(this, aInitDone,
|
||||
aInputImage->width(),
|
||||
aInputImage->height()));
|
||||
|
||||
// OpenH264 codec (at least) can't handle dynamic input resolution changes
|
||||
// re-init the plugin when the resolution changes
|
||||
// XXX allow codec to indicate it doesn't need re-init!
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback))))) {
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
if (!mGMP) {
|
||||
// destroyed via Terminate()
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aInputImage->width() >= 0 && aInputImage->height() >= 0);
|
||||
if (static_cast<uint32_t>(aInputImage->width()) != mCodecParams.mWidth ||
|
||||
static_cast<uint32_t>(aInputImage->height()) != mCodecParams.mHeight) {
|
||||
LOGD(("GMP Encode: resolution change from %ux%u to %dx%d",
|
||||
mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height()));
|
||||
|
||||
mGMP->Close();
|
||||
|
||||
// OpenH264 codec (at least) can't handle dynamic input resolution changes
|
||||
// re-init the plugin when the resolution changes
|
||||
// XXX allow codec to indicate it doesn't need re-init!
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
mCodecParams.mWidth = aInputImage->width();
|
||||
mCodecParams.mHeight = aInputImage->height();
|
||||
// Pass dummy codecSpecific data for now...
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
|
||||
GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize);
|
||||
if (err != GMPNoErr) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(mGMP);
|
||||
|
||||
GMPVideoFrame* ftmp = nullptr;
|
||||
GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp);
|
||||
@ -566,33 +611,48 @@ WebrtcGmpVideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings,
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
mGMPThread->Dispatch(WrapRunnableRet(this,
|
||||
&WebrtcGmpVideoDecoder::InitDecode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
&ret),
|
||||
NS_DISPATCH_SYNC);
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
mGMPThread->Dispatch(WrapRunnable(this,
|
||||
&WebrtcGmpVideoDecoder::InitDecode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
initDone.get()),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
return ret;
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
return initDone->Result();
|
||||
}
|
||||
|
||||
int32_t
|
||||
void
|
||||
WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores)
|
||||
int32_t aNumberOfCores,
|
||||
InitDoneRunnable* aInitDone)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
UniquePtr<GetGMPVideoDecoderCallback> callback(
|
||||
new InitDoneCallback(this, aInitDone));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
Move(callback))))) {
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mGMPThread = nullptr;
|
||||
mHost = nullptr;
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::GmpInitDone(GMPVideoDecoderProxy* aGMP,
|
||||
GMPVideoHost* aHost)
|
||||
{
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
mMPS = nullptr;
|
||||
|
||||
if (!mGMP || !mHost) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <queue>
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
@ -77,13 +78,131 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int32_t InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize);
|
||||
class InitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
InitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mResult(WEBRTC_VIDEO_CODEC_OK),
|
||||
mThread(do_GetCurrentThread())
|
||||
{
|
||||
}
|
||||
|
||||
virtual int32_t Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(mThread == nsCOMPtr<nsIThread>(do_GetCurrentThread()));
|
||||
mInitDone = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch(int32_t aResult)
|
||||
{
|
||||
mResult = aResult;
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
}
|
||||
|
||||
int32_t Result()
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
int32_t mResult;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
void InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize,
|
||||
InitDoneRunnable* aInitDone);
|
||||
int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
uint32_t aMaxPayloadSize);
|
||||
int32_t InitEncoderForSize(unsigned short aWidth, unsigned short aHeight);
|
||||
|
||||
class InitDoneCallback : public GetGMPVideoEncoderCallback
|
||||
{
|
||||
public:
|
||||
InitDoneCallback(WebrtcGmpVideoEncoder* aEncoder,
|
||||
InitDoneRunnable* aInitDone,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
uint32_t aMaxPayloadSize)
|
||||
: mEncoder(aEncoder),
|
||||
mInitDone(aInitDone),
|
||||
mCodecSettings(aCodecSettings),
|
||||
mMaxPayloadSize(aMaxPayloadSize)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
|
||||
{
|
||||
mEncoder->mGMP = aGMP;
|
||||
mEncoder->mHost = aHost;
|
||||
int32_t result;
|
||||
if (aGMP || aHost) {
|
||||
result = mEncoder->GmpInitDone(aGMP, aHost, mCodecSettings,
|
||||
mMaxPayloadSize);
|
||||
} else {
|
||||
result = WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoEncoder* mEncoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
const webrtc::VideoCodec* mCodecSettings;
|
||||
uint32_t mMaxPayloadSize;
|
||||
};
|
||||
|
||||
int32_t Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
|
||||
void RegetEncoderForResolutionChange(const webrtc::I420VideoFrame* aInputImage,
|
||||
InitDoneRunnable* aInitDone);
|
||||
|
||||
class InitDoneForResolutionChangeCallback : public GetGMPVideoEncoderCallback
|
||||
{
|
||||
public:
|
||||
InitDoneForResolutionChangeCallback(WebrtcGmpVideoEncoder* aEncoder,
|
||||
InitDoneRunnable* aInitDone,
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight)
|
||||
: mEncoder(aEncoder),
|
||||
mInitDone(aInitDone),
|
||||
mWidth(aWidth),
|
||||
mHeight(aHeight)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
|
||||
{
|
||||
mEncoder->mGMP = aGMP;
|
||||
mEncoder->mHost = aHost;
|
||||
int32_t result;
|
||||
if (aGMP && aHost) {
|
||||
result = mEncoder->InitEncoderForSize(mWidth, mHeight);
|
||||
} else {
|
||||
result = WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoEncoder* mEncoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
virtual int32_t SetRates_g(uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate);
|
||||
@ -151,8 +270,72 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int32_t InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores);
|
||||
class InitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
InitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mResult(WEBRTC_VIDEO_CODEC_OK),
|
||||
mThread(do_GetCurrentThread())
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(mThread == nsCOMPtr<nsIThread>(do_GetCurrentThread()));
|
||||
mInitDone = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch(int32_t aResult)
|
||||
{
|
||||
mResult = aResult;
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
}
|
||||
|
||||
int32_t Result()
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
int32_t mResult;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
void InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
InitDoneRunnable* aInitDone);
|
||||
int32_t GmpInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost);
|
||||
|
||||
class InitDoneCallback : public GetGMPVideoDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit InitDoneCallback(WebrtcGmpVideoDecoder* aDecoder,
|
||||
InitDoneRunnable* aInitDone)
|
||||
: mDecoder(aDecoder),
|
||||
mInitDone(aInitDone)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
int32_t result = mDecoder->GmpInitDone(aGMP, aHost);
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoDecoder* mDecoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
};
|
||||
|
||||
virtual int32_t Decode_g(const webrtc::EncodedImage& aInputImage,
|
||||
bool aMissingFrames,
|
||||
|
Loading…
Reference in New Issue
Block a user