Bug 1279077 - Update GMP/EME path to support webm. r=cpearce
Update handling of VP8, VP9 to enable decryption and decoding via widevine.
Update handling with further validation to make sure that invalid video types
are rejected when trying to create widevine decryptor session or init widevine
decoders.
MozReview-Commit-ID: 8FOvUJfxr6L
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -475,21 +475,20 @@ GetSupportedKeySystems()
// decode content decrypted by the Widevine CDM.
if (WMFDecoderModule::HasAAC()) {
widevine.mMP4.SetCanDecrypt(GMP_CODEC_AAC);
}
#else
widevine.mMP4.SetCanDecrypt(GMP_CODEC_AAC);
#endif
widevine.mMP4.SetCanDecryptAndDecode(GMP_CODEC_H264);
- // TODO: Enable Widevine/WebM once bug 1279077 lands.
- //widevine.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS);
- //widevine.mWebM.SetCanDecrypt(GMP_CODEC_OPUS);
- //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP8);
- //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP9);
+ widevine.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS);
+ widevine.mWebM.SetCanDecrypt(GMP_CODEC_OPUS);
+ widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP8);
+ widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP9);
sKeySystemConfigs->AppendElement(Move(widevine));
}
{
KeySystemConfig primetime;
primetime.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemPrimetime);
primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
primetime.mPersistentState = KeySystemFeatureSupport::Required;
primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required;
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -948,16 +948,18 @@ GMPParent::ParseChromiumManifest(nsStrin
}
mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
GMPCapability video(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER));
video.mAPITags.AppendElement(NS_LITERAL_CSTRING("h264"));
+ video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+ video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp9"));
video.mAPITags.AppendElement(nsCString(kEMEKeySystemWidevine));
mCapabilities.AppendElement(Move(video));
GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
decrypt.mAPITags.AppendElement(nsCString(kEMEKeySystemWidevine));
mCapabilities.AppendElement(Move(decrypt));
MOZ_ASSERT(mName.EqualsLiteral("widevinecdm"));
--- a/dom/media/gmp/gmp-api/gmp-video-codec.h
+++ b/dom/media/gmp/gmp-api/gmp-video-codec.h
@@ -108,16 +108,17 @@ struct GMPVideoCodecH264
enum GMPVideoCodecType
{
kGMPVideoCodecVP8,
// Encoded frames are in AVCC format; NAL length field of 4 bytes, followed
// by frame data. May be multiple NALUs per sample. Codec specific extra data
// is the AVCC extra data (in AVCC format).
kGMPVideoCodecH264,
+ kGMPVideoCodecVP9,
kGMPVideoCodecInvalid // Should always be last.
};
// Simulcast is when the same stream is encoded multiple times with different
// settings such as resolution.
struct GMPSimulcastStream
{
uint32_t mWidth;
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -71,21 +71,33 @@ WidevineDecryptor::CreateSession(uint32_
uint32_t aPromiseId,
const char* aInitDataType,
uint32_t aInitDataTypeSize,
const uint8_t* aInitData,
uint32_t aInitDataSize,
GMPSessionType aSessionType)
{
Log("Decryptor::CreateSession(token=%d, pid=%d)", aCreateSessionToken, aPromiseId);
- MOZ_ASSERT(!strcmp(aInitDataType, "cenc"));
+ InitDataType initDataType;
+ if (!strcmp(aInitDataType, "cenc")) {
+ initDataType = kCenc;
+ } else if (!strcmp(aInitDataType, "webm")) {
+ initDataType = kWebM;
+ } else if (!strcmp(aInitDataType, "keyids")) {
+ initDataType = kKeyIds;
+ } else {
+ // Invalid init data type
+ const char* errorMsg = "Invalid init data type when creating session.";
+ OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg));
+ return;
+ }
mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken;
CDM()->CreateSessionAndGenerateRequest(aPromiseId,
ToCDMSessionType(aSessionType),
- kCenc,
+ initDataType,
aInitData, aInitDataSize);
}
void
WidevineDecryptor::LoadSession(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdLength)
{
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
@@ -15,16 +15,17 @@ using namespace cdm;
namespace mozilla {
WidevineVideoDecoder::WidevineVideoDecoder(GMPVideoHost* aVideoHost,
RefPtr<CDMWrapper> aCDMWrapper)
: mVideoHost(aVideoHost)
, mCDMWrapper(Move(aCDMWrapper))
, mExtraData(new MediaByteBuffer())
, mSentInput(false)
+ , mCodecType(kGMPVideoCodecInvalid)
, mReturnOutputCallDepth(0)
, mDrainPending(false)
, mResetInProgress(false)
{
// Expect to start with a CDM wrapper, will release it in DecodingComplete().
MOZ_ASSERT(mCDMWrapper);
Log("WidevineVideoDecoder created this=%p", this);
@@ -57,19 +58,31 @@ void
WidevineVideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings,
const uint8_t* aCodecSpecific,
uint32_t aCodecSpecificLength,
GMPVideoDecoderCallback* aCallback,
int32_t aCoreCount)
{
mCallback = aCallback;
VideoDecoderConfig config;
- config.codec = VideoDecoderConfig::kCodecH264; // TODO: others.
- const GMPVideoCodecH264* h264 = (const GMPVideoCodecH264*)(aCodecSpecific);
- config.profile = ToCDMH264Profile(h264->mAVCC.mProfile);
+ mCodecType = aCodecSettings.mCodecType;
+ if (mCodecType == kGMPVideoCodecH264) {
+ config.codec = VideoDecoderConfig::kCodecH264;
+ const GMPVideoCodecH264* h264 = (const GMPVideoCodecH264*)(aCodecSpecific);
+ config.profile = ToCDMH264Profile(h264->mAVCC.mProfile);
+ } else if (mCodecType == kGMPVideoCodecVP8) {
+ config.codec = VideoDecoderConfig::kCodecVp8;
+ config.profile = VideoDecoderConfig::kProfileNotNeeded;
+ } else if (mCodecType == kGMPVideoCodecVP9) {
+ config.codec = VideoDecoderConfig::kCodecVp9;
+ config.profile = VideoDecoderConfig::kProfileNotNeeded;
+ } else {
+ mCallback->Error(GMPInvalidArgErr);
+ return;
+ }
config.format = kYv12;
config.coded_size = Size(aCodecSettings.mWidth, aCodecSettings.mHeight);
mExtraData->AppendElements(aCodecSpecific + 1, aCodecSpecificLength);
config.extra_data = mExtraData->Elements();
config.extra_data_size = mExtraData->Length();
Status rv = CDM()->InitializeVideoDecoder(config);
if (rv != kSuccess) {
mCallback->Error(ToGMPErr(rv));
@@ -95,28 +108,30 @@ WidevineVideoDecoder::Decode(GMPVideoEnc
mFrameDurations[aInputFrame->TimeStamp()] = aInputFrame->Duration();
mSentInput = true;
InputBuffer sample;
RefPtr<MediaRawData> raw(new MediaRawData(aInputFrame->Buffer(), aInputFrame->Size()));
raw->mExtraData = mExtraData;
raw->mKeyframe = (aInputFrame->FrameType() == kGMPKeyFrame);
- // Convert input from AVCC, which GMPAPI passes in, to AnnexB, which
- // Chromium uses internally.
- mp4_demuxer::AnnexB::ConvertSampleToAnnexB(raw);
+ if (mCodecType == kGMPVideoCodecH264) {
+ // Convert input from AVCC, which GMPAPI passes in, to AnnexB, which
+ // Chromium uses internally.
+ mp4_demuxer::AnnexB::ConvertSampleToAnnexB(raw);
+ }
const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData();
nsTArray<SubsampleEntry> subsamples;
InitInputBuffer(crypto, aInputFrame->TimeStamp(), raw->Data(), raw->Size(), sample, subsamples);
// For keyframes, ConvertSampleToAnnexB will stick the AnnexB extra data
// at the start of the input. So we need to account for that as clear data
// in the subsamples.
- if (raw->mKeyframe && !subsamples.IsEmpty()) {
+ if (raw->mKeyframe && !subsamples.IsEmpty() && mCodecType == kGMPVideoCodecH264) {
subsamples[0].clear_bytes += mAnnexB->Length();
}
WidevineVideoFrame frame;
Status rv = CDM()->DecryptAndDecodeFrame(sample, &frame);
Log("WidevineVideoDecoder::Decode(timestamp=%lld) rv=%d", sample.timestamp, rv);
// Destroy frame, so that the shmem is now free to be used to return
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
@@ -57,16 +57,17 @@ private:
GMPVideoHost* mVideoHost;
RefPtr<CDMWrapper> mCDMWrapper;
RefPtr<MediaByteBuffer> mExtraData;
RefPtr<MediaByteBuffer> mAnnexB;
GMPVideoDecoderCallback* mCallback;
std::map<uint64_t, uint64_t> mFrameDurations;
bool mSentInput;
+ GMPVideoCodecType mCodecType;
// Frames waiting on allocation
std::deque<WidevineVideoFrame> mFrameAllocationQueue;
// Number of calls of ReturnOutput currently in progress.
int32_t mReturnOutputCallDepth;
// If we're waiting to drain. Used to prevent drain completing while
// ReturnOutput calls are still on the stack.
bool mDrainPending;
// If a reset is being performed. Used to track if ReturnOutput should
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -227,10 +227,24 @@ bool
VPXDecoder::IsVPX(const nsACString& aMimeType, uint8_t aCodecMask)
{
return ((aCodecMask & VPXDecoder::VP8) &&
aMimeType.EqualsLiteral("video/webm; codecs=vp8")) ||
((aCodecMask & VPXDecoder::VP9) &&
aMimeType.EqualsLiteral("video/webm; codecs=vp9"));
}
+/* static */
+bool
+VPXDecoder::IsVP8(const nsACString& aMimeType)
+{
+ return IsVPX(aMimeType, VPXDecoder::VP8);
+}
+
+/* static */
+bool
+VPXDecoder::IsVP9(const nsACString& aMimeType)
+{
+ return IsVPX(aMimeType, VPXDecoder::VP9);
+}
+
} // namespace mozilla
#undef LOG
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -36,16 +36,18 @@ public:
enum Codec: uint8_t {
VP8 = 1 << 0,
VP9 = 1 << 1
};
// Return true if mimetype is a VPX codec of given types.
static bool IsVPX(const nsACString& aMimeType, uint8_t aCodecMask=VP8|VP9);
+ static bool IsVP8(const nsACString& aMimeType);
+ static bool IsVP9(const nsACString& aMimeType);
private:
void ProcessDecode(MediaRawData* aSample);
int DoDecode(MediaRawData* aSample);
void ProcessDrain();
const RefPtr<ImageContainer> mImageContainer;
const RefPtr<TaskQueue> mTaskQueue;
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -287,17 +287,19 @@ EMEDecoderModule::CreateAudioDecoder(con
mProxy,
AbstractThread::GetCurrent()->AsTaskQueue()));
return emeDecoder.forget();
}
PlatformDecoderModule::ConversionRequired
EMEDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
{
- if (aConfig.IsVideo()) {
+ if (aConfig.IsVideo() &&
+ (aConfig.mMimeType.EqualsLiteral("video/avc") ||
+ aConfig.mMimeType.EqualsLiteral("video/mp4"))) {
return kNeedAVCC;
} else {
return kNeedNone;
}
}
bool
EMEDecoderModule::SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
@@ -3,16 +3,17 @@
/* 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 "EMEVideoDecoder.h"
#include "GMPVideoEncodedFrameImpl.h"
#include "mozilla/CDMProxy.h"
#include "MediaData.h"
+#include "VPXDecoder.h"
namespace mozilla {
void
EMEVideoCallbackAdapter::Error(GMPErr aErr)
{
if (aErr == GMPNoKeyErr) {
// The GMP failed to decrypt a frame due to not having a key. This can
@@ -30,17 +31,25 @@ EMEVideoDecoder::EMEVideoDecoder(CDMProx
VideoInfo(aParams.mConfig.mDisplay),
aParams.mImageContainer)))
, mProxy(aProxy)
{}
void
EMEVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
{
- aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
+ VideoInfo config = GetConfig();
+ if (config.mMimeType.EqualsLiteral("video/avc") ||
+ config.mMimeType.EqualsLiteral("video/mp4")) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
+ } else if (VPXDecoder::IsVP8(config.mMimeType)) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+ } else if (VPXDecoder::IsVP9(config.mMimeType)) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("vp9"));
+ }
aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
}
nsCString
EMEVideoDecoder::GetNodeId()
{
return mProxy->GetNodeId();
}
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -11,16 +11,17 @@
#include "MediaDataDecoderProxy.h"
#include "MediaPrefs.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/EMEUtils.h"
#include "mozilla/StaticMutex.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
+#include "VPXDecoder.h"
#ifdef XP_WIN
#include "WMFDecoderModule.h"
#endif
namespace mozilla {
GMPDecoderModule::GMPDecoderModule()
{
@@ -43,17 +44,20 @@ CreateDecoderWrapper(MediaDataDecoderCal
}
RefPtr<MediaDataDecoderProxy> decoder(new MediaDataDecoderProxy(thread.forget(), aCallback));
return decoder.forget();
}
already_AddRefed<MediaDataDecoder>
GMPDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
{
- if (!aParams.mConfig.mMimeType.EqualsLiteral("video/avc")) {
+ if (!aParams.mConfig.mMimeType.EqualsLiteral("video/avc") &&
+ !aParams.mConfig.mMimeType.EqualsLiteral("video/mp4") &&
+ !VPXDecoder::IsVP8(aParams.mConfig.mMimeType) &&
+ !VPXDecoder::IsVP9(aParams.mConfig.mMimeType)) {
return nullptr;
}
if (aParams.mDiagnostics) {
const Maybe<nsCString> preferredGMP = PreferredGMP(aParams.mConfig.mMimeType);
if (preferredGMP.isSome()) {
aParams.mDiagnostics->SetGMP(preferredGMP.value());
}
@@ -84,17 +88,19 @@ GMPDecoderModule::CreateAudioDecoder(con
wrapper->SetProxyTarget(new GMPAudioDecoder(params));
return wrapper.forget();
}
PlatformDecoderModule::ConversionRequired
GMPDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
{
// GMPVideoCodecType::kGMPVideoCodecH264 specifies that encoded frames must be in AVCC format.
- if (aConfig.IsVideo()) {
+ if (aConfig.IsVideo() &&
+ (aConfig.mMimeType.EqualsLiteral("video/avc") ||
+ aConfig.mMimeType.EqualsLiteral("video/mp4"))) {
return kNeedAVCC;
} else {
return kNeedNone;
}
}
static bool
HasGMPFor(const nsACString& aAPI,
@@ -136,37 +142,45 @@ HasGMPFor(const nsACString& aAPI,
}
StaticMutex sGMPCodecsMutex;
struct GMPCodecs {
const char* mKeySystem;
bool mHasAAC;
bool mHasH264;
+ bool mHasVP8;
+ bool mHasVP9;
};
static GMPCodecs sGMPCodecs[] = {
- { kEMEKeySystemClearkey, false, false },
- { kEMEKeySystemWidevine, false, false },
- { kEMEKeySystemPrimetime, false, false },
+ { kEMEKeySystemClearkey, false, false, false, false },
+ { kEMEKeySystemWidevine, false, false, false, false },
+ { kEMEKeySystemPrimetime, false, false, false, false },
};
void
GMPDecoderModule::UpdateUsableCodecs()
{
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sGMPCodecsMutex);
for (GMPCodecs& gmp : sGMPCodecs) {
gmp.mHasAAC = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
NS_LITERAL_CSTRING("aac"),
nsDependentCString(gmp.mKeySystem));
gmp.mHasH264 = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
NS_LITERAL_CSTRING("h264"),
nsDependentCString(gmp.mKeySystem));
+ gmp.mHasVP8 = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp8"),
+ nsDependentCString(gmp.mKeySystem));
+ gmp.mHasVP9 = HasGMPFor(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp9"),
+ nsDependentCString(gmp.mKeySystem));
}
}
/* static */
void
GMPDecoderModule::Init()
{
MOZ_ASSERT(NS_IsMainThread());
@@ -204,24 +218,25 @@ GMPDecoderModule::PreferredGMP(const nsA
/* static */
bool
GMPDecoderModule::SupportsMimeType(const nsACString& aMimeType,
const Maybe<nsCString>& aGMP)
{
const bool isAAC = aMimeType.EqualsLiteral("audio/mp4a-latm");
const bool isH264 = aMimeType.EqualsLiteral("video/avc") ||
aMimeType.EqualsLiteral("video/mp4");
+ const bool isVP8 = VPXDecoder::IsVP8(aMimeType);
+ const bool isVP9 = VPXDecoder::IsVP9(aMimeType);
StaticMutexAutoLock lock(sGMPCodecsMutex);
for (GMPCodecs& gmp : sGMPCodecs) {
- if (isAAC && gmp.mHasAAC &&
- (aGMP.isNothing() || aGMP.value().EqualsASCII(gmp.mKeySystem))) {
- return true;
- }
- if (isH264 && gmp.mHasH264 &&
+ if (((isAAC && gmp.mHasAAC) ||
+ (isH264 && gmp.mHasH264) ||
+ (isVP8 && gmp.mHasVP8) ||
+ (isVP9 && gmp.mHasVP9)) &&
(aGMP.isNothing() || aGMP.value().EqualsASCII(gmp.mKeySystem))) {
return true;
}
}
return false;
}
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoDecoder.h"
#include "GMPVideoHost.h"
#include "mozilla/EndianUtils.h"
#include "prsystem.h"
#include "MediaData.h"
#include "GMPDecoderModule.h"
+#include "VPXDecoder.h"
namespace mozilla {
#if defined(DEBUG)
extern bool IsOnGMPThread();
#endif
void
@@ -95,17 +96,17 @@ VideoCallbackAdapter::Error(GMPErr aErr)
MOZ_ASSERT(IsOnGMPThread());
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
}
void
VideoCallbackAdapter::Terminated()
{
// Note that this *may* be called from the proxy thread also.
- NS_WARNING("H.264 GMP decoder terminated.");
+ NS_WARNING("GMP decoder terminated.");
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
}
GMPVideoDecoderParams::GMPVideoDecoderParams(const CreateDecoderParams& aParams)
: mConfig(aParams.VideoConfig())
, mTaskQueue(aParams.mTaskQueue)
, mCallback(nullptr)
, mAdapter(nullptr)
@@ -150,21 +151,28 @@ GMPVideoDecoder::GMPVideoDecoder(const G
mConfig.mDisplay.height),
aParams.mImageContainer);
}
}
void
GMPVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
{
- aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
- const Maybe<nsCString> gmp(
- GMPDecoderModule::PreferredGMP(NS_LITERAL_CSTRING("video/avc")));
- if (gmp.isSome()) {
- aTags.AppendElement(gmp.value());
+ if (mConfig.mMimeType.EqualsLiteral("video/avc") ||
+ mConfig.mMimeType.EqualsLiteral("video/mp4")) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
+ const Maybe<nsCString> gmp(
+ GMPDecoderModule::PreferredGMP(NS_LITERAL_CSTRING("video/avc")));
+ if (gmp.isSome()) {
+ aTags.AppendElement(gmp.value());
+ }
+ } else if (VPXDecoder::IsVP8(mConfig.mMimeType)) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+ } else if (VPXDecoder::IsVP9(mConfig.mMimeType)) {
+ aTags.AppendElement(NS_LITERAL_CSTRING("vp9"));
}
}
nsCString
GMPVideoDecoder::GetNodeId()
{
return SHARED_GMP_DECODING_NODE_ID;
}
@@ -207,16 +215,22 @@ GMPVideoDecoder::CreateFrame(MediaRawDat
frame->SetTimeStamp(aSample->mTime);
frame->SetCompleteFrame(true);
frame->SetDuration(aSample->mDuration);
frame->SetFrameType(aSample->mKeyframe ? kGMPKeyFrame : kGMPDeltaFrame);
return frame;
}
+const VideoInfo&
+GMPVideoDecoder::GetConfig() const
+{
+ return mConfig;
+}
+
void
GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
{
MOZ_ASSERT(IsOnGMPThread());
if (!aGMP) {
mInitPromise.RejectIfExists(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
return;
@@ -229,26 +243,36 @@ GMPVideoDecoder::GMPInitDone(GMPVideoDec
aGMP->Close();
return;
}
GMPVideoCodec codec;
memset(&codec, 0, sizeof(codec));
codec.mGMPApiVersion = kGMPVersion33;
-
- codec.mCodecType = kGMPVideoCodecH264;
+ nsTArray<uint8_t> codecSpecific;
+ if (mConfig.mMimeType.EqualsLiteral("video/avc") ||
+ mConfig.mMimeType.EqualsLiteral("video/mp4")) {
+ codec.mCodecType = kGMPVideoCodecH264;
+ codecSpecific.AppendElement(0); // mPacketizationMode.
+ codecSpecific.AppendElements(mConfig.mExtraData->Elements(),
+ mConfig.mExtraData->Length());
+ } else if (VPXDecoder::IsVP8(mConfig.mMimeType)) {
+ codec.mCodecType = kGMPVideoCodecVP8;
+ } else if (VPXDecoder::IsVP9(mConfig.mMimeType)) {
+ codec.mCodecType = kGMPVideoCodecVP9;
+ } else {
+ // Unrecognized mime type
+ aGMP->Close();
+ mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
+ return;
+ }
codec.mWidth = mConfig.mImage.width;
codec.mHeight = mConfig.mImage.height;
- nsTArray<uint8_t> codecSpecific;
- codecSpecific.AppendElement(0); // mPacketizationMode.
- codecSpecific.AppendElements(mConfig.mExtraData->Elements(),
- mConfig.mExtraData->Length());
-
nsresult rv = aGMP->InitDecode(codec,
codecSpecific,
mAdapter,
PR_GetNumberOfProcessors());
if (NS_FAILED(rv)) {
aGMP->Close();
mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
return;
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -78,16 +78,17 @@ public:
{
return "GMP video decoder";
}
protected:
virtual void InitTags(nsTArray<nsCString>& aTags);
virtual nsCString GetNodeId();
virtual GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(MediaRawData* aSample);
+ virtual const VideoInfo& GetConfig() const;
private:
class GMPInitDoneCallback : public GetGMPVideoDecoderCallback
{
public:
explicit GMPInitDoneCallback(GMPVideoDecoder* aDecoder)
: mDecoder(aDecoder)