Bug 1279077 - Update GMP/EME path to support webm. r=cpearce draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Fri, 29 Jul 2016 15:53:22 +1200
changeset 394692 0f6aed8256d7f106a598b09e6f11efe80f0e4bb2
parent 394131 97b1b6e04bc92e1efa31b66603fe4f060d161aca
child 526864 65fe96c6c0cca5141a3a1639c0e1736e199397c4
push id24628
push userbvandyk@mozilla.com
push dateSun, 31 Jul 2016 02:09:09 +0000
reviewerscpearce
bugs1279077
milestone50.0a1
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
dom/media/eme/MediaKeySystemAccess.cpp
dom/media/gmp/GMPParent.cpp
dom/media/gmp/gmp-api/gmp-video-codec.h
dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
dom/media/platforms/agnostic/VPXDecoder.cpp
dom/media/platforms/agnostic/VPXDecoder.h
dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
--- 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)