mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
549 lines
18 KiB
C++
549 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* 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/. */
|
|
|
|
#include "mozilla/dom/GMPVideoDecoderTrialCreator.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "prsystem.h"
|
|
#include "GMPVideoHost.h"
|
|
#include "mozilla/EMEUtils.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "GMPService.h"
|
|
#include "VideoUtils.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "nsXULAppAPI.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
static already_AddRefed<nsIThread>
|
|
GetGMPThread()
|
|
{
|
|
nsCOMPtr<mozIGeckoMediaPluginService> gmps =
|
|
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
|
if (!gmps) {
|
|
return nullptr;
|
|
}
|
|
nsCOMPtr<nsIThread> gmpThread;
|
|
nsresult rv = gmps->GetThread(getter_AddRefs(gmpThread));
|
|
if (NS_FAILED(rv)) {
|
|
return nullptr;
|
|
}
|
|
return gmpThread.forget();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static bool
|
|
OnGMPThread()
|
|
{
|
|
nsCOMPtr<nsIThread> currentThread;
|
|
NS_GetCurrentThread(getter_AddRefs(currentThread));
|
|
nsCOMPtr<nsIThread> gmpThread(GetGMPThread());
|
|
return !!gmpThread && !!currentThread && gmpThread == currentThread;
|
|
}
|
|
#endif
|
|
|
|
static const char*
|
|
TrialCreatePrefName(const nsAString& aKeySystem)
|
|
{
|
|
if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
|
|
return "media.gmp-eme-adobe.trial-create";
|
|
}
|
|
if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
|
|
return "media.gmp-eme-clearkey.trial-create";
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/* static */
|
|
GMPVideoDecoderTrialCreator::TrialCreateState
|
|
GMPVideoDecoderTrialCreator::GetCreateTrialState(const nsAString& aKeySystem)
|
|
{
|
|
if (Preferences::GetBool("media.gmp.always-trial-create", false)) {
|
|
return Pending;
|
|
}
|
|
|
|
const char* pref = TrialCreatePrefName(aKeySystem);
|
|
if (!pref) {
|
|
return Pending;
|
|
}
|
|
switch (Preferences::GetInt(pref, (int)Pending)) {
|
|
case 0: return Pending;
|
|
case 1: return Succeeded;
|
|
case 2: return Failed;
|
|
default: return Pending;
|
|
}
|
|
}
|
|
|
|
void
|
|
GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(const nsAString& aKeySystem,
|
|
const nsACString& aReason)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(%s)",
|
|
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
|
|
|
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
data->mStatus = Failed;
|
|
const char* pref = TrialCreatePrefName(aKeySystem);
|
|
if (pref) {
|
|
Preferences::SetInt(pref, (int)Failed);
|
|
}
|
|
for (nsRefPtr<AbstractPromiseLike>& promise: data->mPending) {
|
|
promise->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, aReason);
|
|
}
|
|
data->mPending.Clear();
|
|
data->mTest = nullptr;
|
|
}
|
|
|
|
void
|
|
GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(const nsAString& aKeySystem)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(%s)",
|
|
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
|
|
|
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
data->mStatus = Succeeded;
|
|
const char* pref = TrialCreatePrefName(aKeySystem);
|
|
if (pref) {
|
|
Preferences::SetInt(pref, (int)Succeeded);
|
|
}
|
|
for (nsRefPtr<AbstractPromiseLike>& promise : data->mPending) {
|
|
promise->Resolve();
|
|
}
|
|
data->mPending.Clear();
|
|
data->mTest = nullptr;
|
|
}
|
|
|
|
nsresult
|
|
TestGMPVideoDecoder::Start()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
|
if (!mGMPService) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
|
if (!thread) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethod(this, &TestGMPVideoDecoder::CreateGMPVideoDecoder));
|
|
return thread->Dispatch(task, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
struct ExpectedPlaneDecodePlane {
|
|
GMPPlaneType mPlane;
|
|
size_t mLength;
|
|
uint8_t mValue;
|
|
int32_t mSize; // width & height
|
|
};
|
|
|
|
static const ExpectedPlaneDecodePlane sExpectedPlanes[3] = {
|
|
{
|
|
kGMPYPlane,
|
|
112 * 112, // 12544
|
|
0x4c,
|
|
112
|
|
},
|
|
{ // U
|
|
kGMPUPlane,
|
|
56 * 56, // 3136
|
|
0x55,
|
|
56,
|
|
},
|
|
{ // V
|
|
kGMPVPlane,
|
|
56 * 56, // 3136
|
|
0xff,
|
|
56,
|
|
}
|
|
};
|
|
|
|
static bool TestDecodedFrame(GMPVideoi420Frame* aDecodedFrame)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
if (aDecodedFrame->Width() != 112 || aDecodedFrame->Height() != 112) {
|
|
EME_LOG("TestDecodedFrame() - Invalid decoded frame dimensions");
|
|
return false;
|
|
}
|
|
for (const ExpectedPlaneDecodePlane& plane : sExpectedPlanes) {
|
|
int32_t stride = aDecodedFrame->Stride(plane.mPlane);
|
|
if (stride < plane.mSize) {
|
|
EME_LOG("TestDecodedFrame() - Insufficient decoded frame stride");
|
|
return false;
|
|
}
|
|
int32_t length = plane.mSize * plane.mSize;
|
|
if (aDecodedFrame->AllocatedSize(plane.mPlane) < length) {
|
|
EME_LOG("TestDecodedFrame() - Insufficient decoded frame allocated size");
|
|
return false;
|
|
}
|
|
const uint8_t* data = aDecodedFrame->Buffer(plane.mPlane);
|
|
for (int32_t row = 0; row < plane.mSize; row++) {
|
|
for (int32_t i = 0; i < plane.mSize; i++) {
|
|
size_t off = (stride * row) + i;
|
|
if (data[off] != plane.mValue) {
|
|
EME_LOG("TestDecodedFrame() - Invalid decoded frame contents");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
if (!mReceivedDecoded) {
|
|
mReceivedDecoded = true;
|
|
} else {
|
|
EME_LOG("Received multiple decoded frames");
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder received multiple decoded frames"));
|
|
return;
|
|
}
|
|
|
|
GMPUniquePtr<GMPVideoi420Frame> decodedFrame(aDecodedFrame);
|
|
if (!TestDecodedFrame(aDecodedFrame)) {
|
|
EME_LOG("decoded frame failed verification");
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder decoded frame failed verification"));
|
|
}
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::DrainComplete()
|
|
{
|
|
EME_LOG("TestGMPVideoDecoder::DrainComplete()");
|
|
MOZ_ASSERT(OnGMPThread());
|
|
ReportSuccess();
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::Error(GMPErr aErr)
|
|
{
|
|
EME_LOG("TestGMPVideoDecoder::ReceivedDecodedFrame()");
|
|
MOZ_ASSERT(OnGMPThread());
|
|
ReportFailure(nsPrintfCString("TestGMPVideoDecoder error %d", aErr));
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::Terminated()
|
|
{
|
|
EME_LOG("TestGMPVideoDecoder::Terminated()");
|
|
MOZ_ASSERT(OnGMPThread());
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMP terminated"));
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::ReportFailure(const nsACString& aReason)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
if (mGMP) {
|
|
mGMP->Close();
|
|
mGMP = nullptr;
|
|
}
|
|
|
|
nsRefPtr<nsIRunnable> task;
|
|
task = NS_NewRunnableMethodWithArgs<nsString, nsCString>(mInstance,
|
|
&GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed,
|
|
mKeySystem,
|
|
aReason);
|
|
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::ReportSuccess()
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
if (mGMP) {
|
|
mGMP->Close();
|
|
mGMP = nullptr;
|
|
}
|
|
|
|
nsRefPtr<nsIRunnable> task;
|
|
task = NS_NewRunnableMethodWithArg<nsString>(mInstance,
|
|
&GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded,
|
|
mKeySystem);
|
|
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
// A solid red, 112x112 frame. Display size 100x100 pixels.
|
|
// Generated with ImageMagick/ffmpeg
|
|
// $ convert -size 100x100 xc:rgb\(255, 0, 0\) red.png
|
|
// $ ffmpeg -f image2 -i red.png -r 24 -b:v 200k -c:v libx264 -profile:v baseline -level 1 -v:r 24 red.mp4 -y
|
|
static const uint8_t sTestH264Frame[] = {
|
|
0x00, 0x00, 0x02, 0x81, 0x06, 0x05, 0xff, 0xff, 0x7d, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9,
|
|
0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20,
|
|
0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x31, 0x33, 0x35, 0x20, 0x72, 0x32, 0x33, 0x34,
|
|
0x35, 0x20, 0x66, 0x30, 0x63, 0x31, 0x63, 0x35, 0x33, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32,
|
|
0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63,
|
|
0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74,
|
|
0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x2d, 0x20, 0x68, 0x74,
|
|
0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c,
|
|
0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d,
|
|
0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61,
|
|
0x62, 0x61, 0x63, 0x3d, 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x33, 0x20, 0x64, 0x65, 0x62,
|
|
0x6c, 0x6f, 0x63, 0x6b, 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c,
|
|
0x79, 0x73, 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d,
|
|
0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70,
|
|
0x73, 0x79, 0x3d, 0x31, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30,
|
|
0x30, 0x3a, 0x30, 0x2e, 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65,
|
|
0x66, 0x3d, 0x31, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36,
|
|
0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72,
|
|
0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d,
|
|
0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e,
|
|
0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73,
|
|
0x6b, 0x69, 0x70, 0x3d, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70,
|
|
0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65,
|
|
0x61, 0x64, 0x73, 0x3d, 0x31, 0x32, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61,
|
|
0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x20, 0x73, 0x6c, 0x69,
|
|
0x63, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e,
|
|
0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20,
|
|
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c,
|
|
0x75, 0x72, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63,
|
|
0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72,
|
|
0x61, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77,
|
|
0x65, 0x69, 0x67, 0x68, 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74,
|
|
0x3d, 0x32, 0x35, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e,
|
|
0x3d, 0x32, 0x34, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, 0x34, 0x30,
|
|
0x20, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3d,
|
|
0x30, 0x20, 0x72, 0x63, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x3d,
|
|
0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x6d, 0x62, 0x74, 0x72, 0x65,
|
|
0x65, 0x3d, 0x31, 0x20, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x32, 0x30, 0x30,
|
|
0x20, 0x72, 0x61, 0x74, 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63,
|
|
0x6f, 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, 0x6e, 0x3d,
|
|
0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x36, 0x39, 0x20, 0x71, 0x70, 0x73, 0x74,
|
|
0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31,
|
|
0x2e, 0x34, 0x30, 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
|
|
0x00, 0x00, 0x00, 0x39, 0x65, 0x88, 0x84, 0x0c, 0xf1, 0x18, 0xa0, 0x00, 0x23, 0xbf, 0x1c,
|
|
0x00, 0x04, 0x3c, 0x63, 0x80, 0x00, 0x98, 0x44, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x75,
|
|
0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75,
|
|
0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75,
|
|
0xe0
|
|
};
|
|
|
|
static GMPUniquePtr<GMPVideoEncodedFrame>
|
|
CreateFrame(GMPVideoHost* aHost)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
GMPVideoFrame* ftmp = nullptr;
|
|
GMPErr err = aHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
|
|
if (GMP_FAILED(err)) {
|
|
return nullptr;
|
|
}
|
|
|
|
GMPUniquePtr<GMPVideoEncodedFrame> frame(static_cast<GMPVideoEncodedFrame*>(ftmp));
|
|
err = frame->CreateEmptyFrame(MOZ_ARRAY_LENGTH(sTestH264Frame));
|
|
if (GMP_FAILED(err)) {
|
|
return nullptr;
|
|
}
|
|
|
|
memcpy(frame->Buffer(), sTestH264Frame, MOZ_ARRAY_LENGTH(sTestH264Frame));
|
|
frame->SetBufferType(GMP_BufferLength32);
|
|
|
|
frame->SetEncodedWidth(100);
|
|
frame->SetEncodedHeight(100);
|
|
frame->SetTimeStamp(0);
|
|
frame->SetCompleteFrame(true);
|
|
frame->SetDuration(41666);
|
|
frame->SetFrameType(kGMPKeyFrame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static const uint8_t sTestH264CodecSpecific[] = {
|
|
0x01, 0x42, 0xc0, 0x0a, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x42, 0xc0, 0x0a, 0xd9, 0x07, 0x3f,
|
|
0x9e, 0x79, 0xb2, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x60, 0x1e, 0x24,
|
|
0x4c, 0x90, 0x01, 0x00, 0x04, 0x68, 0xcb, 0x8c, 0xb2
|
|
};
|
|
|
|
void
|
|
TestGMPVideoDecoder::Callback::Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
if (!aHost || !aGMP) {
|
|
mInstance->ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder null host or GMP on Get"));
|
|
return;
|
|
}
|
|
|
|
nsRefPtr<nsIRunnable> task;
|
|
task = NS_NewRunnableMethodWithArgs<GMPVideoDecoderProxy*, GMPVideoHost*>(mInstance,
|
|
&TestGMPVideoDecoder::ActorCreated,
|
|
aGMP, aHost);
|
|
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::ActorCreated(GMPVideoDecoderProxy* aGMP,
|
|
GMPVideoHost* aHost)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aHost && aGMP);
|
|
|
|
// Add crash handler.
|
|
nsRefPtr<gmp::GeckoMediaPluginService> service =
|
|
gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
|
|
service->AddPluginCrashedEventTarget(aGMP->GetPluginId(), mWindow);
|
|
|
|
nsCOMPtr<nsIThread> thread(GetGMPThread());
|
|
if (!thread) {
|
|
mInstance->TrialCreateGMPVideoDecoderFailed(mKeySystem,
|
|
NS_LITERAL_CSTRING("Failed to get GMP thread in TestGMPVideoDecoder::ActorCreated"));
|
|
return;
|
|
}
|
|
|
|
nsRefPtr<nsIRunnable> task;
|
|
task = NS_NewRunnableMethodWithArgs<GMPVideoDecoderProxy*, GMPVideoHost*>(this,
|
|
&TestGMPVideoDecoder::InitGMPDone,
|
|
aGMP, aHost);
|
|
thread->Dispatch(task, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::InitGMPDone(GMPVideoDecoderProxy* aGMP,
|
|
GMPVideoHost* aHost)
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
MOZ_ASSERT(aHost && aGMP);
|
|
|
|
mGMP = aGMP;
|
|
mHost = aHost;
|
|
|
|
GMPVideoCodec codec;
|
|
memset(&codec, 0, sizeof(codec));
|
|
|
|
codec.mGMPApiVersion = kGMPVersion33;
|
|
|
|
codec.mCodecType = kGMPVideoCodecH264;
|
|
codec.mWidth = 100;
|
|
codec.mHeight = 100;
|
|
|
|
nsTArray<uint8_t> codecSpecific;
|
|
codecSpecific.AppendElement(0); // mPacketizationMode.
|
|
codecSpecific.AppendElements(sTestH264CodecSpecific,
|
|
MOZ_ARRAY_LENGTH(sTestH264CodecSpecific));
|
|
|
|
nsresult rv = mGMP->InitDecode(codec,
|
|
codecSpecific,
|
|
this,
|
|
PR_GetNumberOfProcessors());
|
|
if (NS_FAILED(rv)) {
|
|
EME_LOG("InitGMPDone() - InitDecode() failed!");
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder InitDecode() returned failure"));
|
|
return;
|
|
}
|
|
|
|
GMPUniquePtr<GMPVideoEncodedFrame> frame = CreateFrame(aHost);
|
|
nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
|
|
rv = mGMP->Decode(Move(frame), false, info, 0);
|
|
if (NS_FAILED(rv)) {
|
|
EME_LOG("InitGMPDone() - Decode() failed to send Decode message!");
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Decode() returned failure"));
|
|
return;
|
|
}
|
|
|
|
rv = mGMP->Drain();
|
|
if (NS_FAILED(rv)) {
|
|
EME_LOG("InitGMPDone() - Drain() failed to send Drain message!");
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Drain() returned failure"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
TestGMPVideoDecoder::CreateGMPVideoDecoder()
|
|
{
|
|
MOZ_ASSERT(OnGMPThread());
|
|
|
|
nsTArray<nsCString> tags;
|
|
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
|
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
|
|
|
|
UniquePtr<GetGMPVideoDecoderCallback> callback(new Callback(this));
|
|
nsCString fakeNodeId;
|
|
if (NS_FAILED(GenerateRandomName(fakeNodeId, 32)) ||
|
|
NS_FAILED(mGMPService->GetGMPVideoDecoder(&tags, fakeNodeId, Move(callback)))) {
|
|
ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMPService GetGMPVideoDecoder returned failure"));
|
|
}
|
|
}
|
|
|
|
void
|
|
GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(const nsAString& aKeySystem,
|
|
AbstractPromiseLike* aPromisey,
|
|
nsPIDOMWindow* aParent)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
|
// Currently broken with e10s...
|
|
aPromisey->Resolve();
|
|
return;
|
|
}
|
|
|
|
if (!mTestCreate.Contains(aKeySystem)) {
|
|
mTestCreate.Put(aKeySystem, new TrialCreateData(aKeySystem));
|
|
}
|
|
TrialCreateData* data = mTestCreate.Get(aKeySystem);
|
|
MOZ_ASSERT(data);
|
|
|
|
switch (data->mStatus) {
|
|
case TrialCreateState::Succeeded: {
|
|
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already succeeded",
|
|
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
|
aPromisey->Resolve();
|
|
break;
|
|
}
|
|
case TrialCreateState::Failed: {
|
|
// Something is broken about this configuration. Report as unsupported.
|
|
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already failed",
|
|
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
|
aPromisey->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
|
NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess trial CDM creation failed"));
|
|
break;
|
|
}
|
|
case TrialCreateState::Pending: {
|
|
EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) pending",
|
|
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
|
// Add request to the list of pending items waiting.
|
|
data->mPending.AppendElement(aPromisey);
|
|
if (!data->mTest) {
|
|
// Not already waiting for CDM to be created. Create and Init
|
|
// a CDM, to test whether it will work.
|
|
data->mTest = new TestGMPVideoDecoder(this, aKeySystem, aParent);
|
|
if (NS_FAILED(data->mTest->Start())) {
|
|
TrialCreateGMPVideoDecoderFailed(aKeySystem,
|
|
NS_LITERAL_CSTRING("TestGMPVideoDecoder::Start() failed"));
|
|
return;
|
|
}
|
|
|
|
// Promise will call InitMediaKeysPromiseHandler when Init()
|
|
// succeeds/fails.
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|