Bug 1020760 - Update GMP APIs to support EME plugins. r=jesup
authorChris Pearce <cpearce@mozilla.com>
Fri, 11 Jul 2014 15:35:56 +1200
changeset 215443 54bd83c54daf91ea8df2799e9122c28c489cfeb3
parent 215442 b1ba940ea14bde7c2a198c85c785eda39c0b4d85
child 215444 a95fee89e4be813283f495bda7978af682a7faf8
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1020760
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1020760 - Update GMP APIs to support EME plugins. r=jesup
content/media/gmp/GMPMessageUtils.h
content/media/gmp/GMPPlatform.cpp
content/media/gmp/GMPPlatform.h
content/media/gmp/GMPService.cpp
content/media/gmp/GMPService.h
content/media/gmp/GMPTypes.ipdlh
content/media/gmp/GMPVideoDecoderChild.cpp
content/media/gmp/GMPVideoDecoderChild.h
content/media/gmp/GMPVideoDecoderParent.cpp
content/media/gmp/GMPVideoDecoderParent.h
content/media/gmp/GMPVideoDecoderProxy.h
content/media/gmp/GMPVideoEncodedFrameImpl.cpp
content/media/gmp/GMPVideoEncodedFrameImpl.h
content/media/gmp/GMPVideoEncoderChild.cpp
content/media/gmp/GMPVideoEncoderChild.h
content/media/gmp/GMPVideoEncoderParent.cpp
content/media/gmp/GMPVideoEncoderParent.h
content/media/gmp/GMPVideoEncoderProxy.h
content/media/gmp/GMPVideoHost.cpp
content/media/gmp/GMPVideoHost.h
content/media/gmp/GMPVideoPlaneImpl.cpp
content/media/gmp/GMPVideoPlaneImpl.h
content/media/gmp/GMPVideoi420FrameImpl.cpp
content/media/gmp/GMPVideoi420FrameImpl.h
content/media/gmp/PGMPVideoDecoder.ipdl
content/media/gmp/PGMPVideoEncoder.ipdl
content/media/gmp/gmp-api/gmp-async-shutdown.h
content/media/gmp/gmp-api/gmp-audio-codec.h
content/media/gmp/gmp-api/gmp-audio-decode.h
content/media/gmp/gmp-api/gmp-audio-host.h
content/media/gmp/gmp-api/gmp-audio-samples.h
content/media/gmp/gmp-api/gmp-decryption.h
content/media/gmp/gmp-api/gmp-errors.h
content/media/gmp/gmp-api/gmp-platform.h
content/media/gmp/gmp-api/gmp-storage.h
content/media/gmp/gmp-api/gmp-video-codec.h
content/media/gmp/gmp-api/gmp-video-decode.h
content/media/gmp/gmp-api/gmp-video-encode.h
content/media/gmp/gmp-api/gmp-video-errors.h
content/media/gmp/gmp-api/gmp-video-frame-encoded.h
content/media/gmp/gmp-api/gmp-video-frame-i420.h
content/media/gmp/gmp-api/gmp-video-frame.h
content/media/gmp/gmp-api/gmp-video-host.h
content/media/gmp/gmp-api/gmp-video-plane.h
content/media/gmp/moz.build
content/media/gmp/mozIGeckoMediaPluginService.idl
media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
--- a/content/media/gmp/GMPMessageUtils.h
+++ b/content/media/gmp/GMPMessageUtils.h
@@ -2,20 +2,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GMPMessageUtils_h_
 #define GMPMessageUtils_h_
 
 #include "gmp-video-codec.h"
+#include "gmp-video-frame-encoded.h"
 
 namespace IPC {
 
 template <>
+struct ParamTraits<GMPErr>
+: public ContiguousEnumSerializer<GMPErr,
+                                  GMPNoErr,
+                                  GMPLastErr>
+{};
+
+template <>
+struct ParamTraits<GMPVideoFrameType>
+: public ContiguousEnumSerializer<GMPVideoFrameType,
+                                  kGMPKeyFrame,
+                                  kGMPSkipFrame>
+{};
+
+template <>
 struct ParamTraits<GMPVideoCodecComplexity>
 : public ContiguousEnumSerializer<GMPVideoCodecComplexity,
                                   kGMPComplexityNormal,
                                   kGMPComplexityInvalid>
 {};
 
 template <>
 struct ParamTraits<GMPVP8ResilienceMode>
@@ -34,67 +49,21 @@ struct ParamTraits<GMPVideoCodecType>
 template <>
 struct ParamTraits<GMPVideoCodecMode>
 : public ContiguousEnumSerializer<GMPVideoCodecMode,
                                   kGMPRealtimeVideo,
                                   kGMPCodecModeInvalid>
 {};
 
 template <>
-struct ParamTraits<GMPVideoCodecVP8>
-{
-  typedef GMPVideoCodecVP8 paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, aParam.mPictureLossIndicationOn);
-    WriteParam(aMsg, aParam.mFeedbackModeOn);
-    WriteParam(aMsg, aParam.mComplexity);
-    WriteParam(aMsg, aParam.mResilience);
-    WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
-    WriteParam(aMsg, aParam.mDenoisingOn);
-    WriteParam(aMsg, aParam.mErrorConcealmentOn);
-    WriteParam(aMsg, aParam.mAutomaticResizeOn);
-    WriteParam(aMsg, aParam.mFrameDroppingOn);
-    WriteParam(aMsg, aParam.mKeyFrameInterval);
-  }
-
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
-  {
-    if (ReadParam(aMsg, aIter, &(aResult->mPictureLossIndicationOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mFeedbackModeOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mComplexity)) &&
-        ReadParam(aMsg, aIter, &(aResult->mResilience)) &&
-        ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
-        ReadParam(aMsg, aIter, &(aResult->mDenoisingOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mErrorConcealmentOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mAutomaticResizeOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) &&
-        ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
-      return true;
-    }
-
-    return false;
-  }
-
-  static void Log(const paramType& aParam, std::wstring* aLog)
-  {
-    aLog->append(StringPrintf(L"[%d, %d, %d, %d, %u, %d, %d, %d, %d, %d]",
-                              aParam.mPictureLossIndicationOn,
-                              aParam.mFeedbackModeOn,
-                              aParam.mComplexity,
-                              aParam.mResilience,
-                              aParam.mNumberOfTemporalLayers,
-                              aParam.mDenoisingOn,
-                              aParam.mErrorConcealmentOn,
-                              aParam.mAutomaticResizeOn,
-                              aParam.mFrameDroppingOn,
-                              aParam.mKeyFrameInterval));
-  }
-};
+struct ParamTraits<GMPBufferType>
+: public ContiguousEnumSerializer<GMPBufferType,
+                                  GMP_BufferSingle,
+                                  GMP_BufferInvalid>
+{};
 
 template <>
 struct ParamTraits<GMPSimulcastStream>
 {
   typedef GMPSimulcastStream paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
@@ -131,40 +100,43 @@ struct ParamTraits<GMPSimulcastStream>
 
 template <>
 struct ParamTraits<GMPVideoCodec>
 {
   typedef GMPVideoCodec paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
+    WriteParam(aMsg, aParam.mGMPApiVersion);
     WriteParam(aMsg, aParam.mCodecType);
     WriteParam(aMsg, nsAutoCString(aParam.mPLName));
     WriteParam(aMsg, aParam.mPLType);
     WriteParam(aMsg, aParam.mWidth);
     WriteParam(aMsg, aParam.mHeight);
     WriteParam(aMsg, aParam.mStartBitrate);
     WriteParam(aMsg, aParam.mMaxBitrate);
     WriteParam(aMsg, aParam.mMinBitrate);
     WriteParam(aMsg, aParam.mMaxFramerate);
-    if (aParam.mCodecType == kGMPVideoCodecVP8) {
-      WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
-    } else {
-      MOZ_ASSERT(false, "Serializing unknown codec type!");
-    }
+    WriteParam(aMsg, aParam.mFrameDroppingOn);
+    WriteParam(aMsg, aParam.mKeyFrameInterval);
     WriteParam(aMsg, aParam.mQPMax);
     WriteParam(aMsg, aParam.mNumberOfSimulcastStreams);
     for (uint32_t i = 0; i < aParam.mNumberOfSimulcastStreams; i++) {
       WriteParam(aMsg, aParam.mSimulcastStream[i]);
     }
     WriteParam(aMsg, aParam.mMode);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
+    // NOTE: make sure this matches any versions supported
+    if (!ReadParam(aMsg, aIter, &(aResult->mGMPApiVersion)) ||
+      aResult->mGMPApiVersion != kGMPVersion33) {
+        return false;
+    }
     if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
       return false;
     }
 
     nsAutoCString plName;
     if (!ReadParam(aMsg, aIter, &plName) ||
         plName.Length() > kGMPPayloadNameSize - 1) {
       return false;
@@ -173,26 +145,19 @@ struct ParamTraits<GMPVideoCodec>
     memset(aResult->mPLName + plName.Length(), 0, kGMPPayloadNameSize - plName.Length());
 
     if (!ReadParam(aMsg, aIter, &(aResult->mPLType)) ||
         !ReadParam(aMsg, aIter, &(aResult->mWidth)) ||
         !ReadParam(aMsg, aIter, &(aResult->mHeight)) ||
         !ReadParam(aMsg, aIter, &(aResult->mStartBitrate)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mMaxFramerate))) {
-      return false;
-    }
-
-    if (aResult->mCodecType == kGMPVideoCodecVP8) {
-      if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
-        return false;
-      }
-    } else {
-      MOZ_ASSERT(false, "De-serializing unknown codec type!");
+        !ReadParam(aMsg, aIter, &(aResult->mMaxFramerate)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
       return false;
     }
 
     if (!ReadParam(aMsg, aIter, &(aResult->mQPMax)) ||
         !ReadParam(aMsg, aIter, &(aResult->mNumberOfSimulcastStreams))) {
       return false;
     }
 
@@ -277,53 +242,91 @@ struct ParamTraits<GMPCodecSpecificInfoV
                               aParam.mTemporalIdx,
                               aParam.mLayerSync,
                               aParam.mTL0PicIdx,
                               aParam.mKeyIdx));
   }
 };
 
 template <>
+struct ParamTraits<GMPCodecSpecificInfoH264>
+{
+  typedef GMPCodecSpecificInfoH264 paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mSimulcastIdx);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    if (ReadParam(aMsg, aIter, &(aResult->mSimulcastIdx))) {
+      return true;
+    }
+    return false;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(StringPrintf(L"[%u]",
+                              aParam.mSimulcastIdx));
+  }
+};
+
+template <>
 struct ParamTraits<GMPCodecSpecificInfo>
 {
   typedef GMPCodecSpecificInfo paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mCodecType);
+    WriteParam(aMsg, aParam.mBufferType);
     if (aParam.mCodecType == kGMPVideoCodecVP8) {
       WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
+    } else if (aParam.mCodecType == kGMPVideoCodecH264) {
+      WriteParam(aMsg, aParam.mCodecSpecific.mH264);
     } else {
       MOZ_ASSERT(false, "Serializing unknown codec type!");
     }
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
       return false;
     }
+    if (!ReadParam(aMsg, aIter, &(aResult->mBufferType))) {
+      return false;
+    }
 
     if (aResult->mCodecType == kGMPVideoCodecVP8) {
       if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
         return false;
       }
+    } else if (aResult->mCodecType == kGMPVideoCodecH264) {
+      if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mH264))) {
+        return false;
+      }
     } else {
       MOZ_ASSERT(false, "De-serializing unknown codec type!");
       return false;
     }
 
     return true;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     const char* codecName = nullptr;
     if (aParam.mCodecType == kGMPVideoCodecVP8) {
       codecName = "VP8";
     }
+    else if (aParam.mCodecType == kGMPVideoCodecH264) {
+      codecName = "H264";
+    }
     aLog->append(StringPrintf(L"[%s]", codecName));
   }
 };
 
 } // namespace IPC
 
 #endif // GMPMessageUtils_h_
--- a/content/media/gmp/GMPPlatform.cpp
+++ b/content/media/gmp/GMPPlatform.cpp
@@ -22,25 +22,26 @@ public:
   : mTask(aTask)
   {
     MOZ_ASSERT(mTask);
   }
 
   void Run()
   {
     mTask->Run();
+    mTask->Destroy();
     mTask = nullptr;
   }
 
 private:
   ~Runnable()
   {
   }
 
-  nsAutoPtr<GMPTask> mTask;
+  GMPTask* mTask;
 };
 
 class SyncRunnable MOZ_FINAL
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SyncRunnable)
 
   SyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
@@ -66,29 +67,30 @@ public:
     while (!mDone) {
       lock.Wait();
     }
   }
 
   void Run()
   {
     mTask->Run();
+    mTask->Destroy();
     mTask = nullptr;
     MonitorAutoLock lock(mMonitor);
     mDone = true;
     lock.Notify();
   }
 
 private:
   ~SyncRunnable()
   {
   }
 
   bool mDone;
-  nsAutoPtr<GMPTask> mTask;
+  GMPTask* mTask;
   MessageLoop* mMessageLoop;
   Monitor mMonitor;
 };
 
 GMPErr
 CreateThread(GMPThread** aThread)
 {
   if (!aThread) {
@@ -103,17 +105,16 @@ CreateThread(GMPThread** aThread)
 GMPErr
 RunOnMainThread(GMPTask* aTask)
 {
   if (!aTask || !sMainLoop) {
     return GMPGenericErr;
   }
 
   nsRefPtr<Runnable> r = new Runnable(aTask);
-
   sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
 
   return GMPNoErr;
 }
 
 GMPErr
 SyncRunOnMainThread(GMPTask* aTask)
 {
@@ -147,16 +148,19 @@ InitPlatformAPI(GMPPlatformAPI& aPlatfor
     sMainLoop = MessageLoop::current();
   }
 
   aPlatformAPI.version = 0;
   aPlatformAPI.createthread = &CreateThread;
   aPlatformAPI.runonmainthread = &RunOnMainThread;
   aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
   aPlatformAPI.createmutex = &CreateMutex;
+  aPlatformAPI.createrecord = nullptr;
+  aPlatformAPI.settimer = nullptr;
+  aPlatformAPI.getcurrenttime = nullptr;
 }
 
 GMPThreadImpl::GMPThreadImpl()
 : mMutex("GMPThreadImpl"),
   mThread("GMPThread")
 {
 }
 
--- a/content/media/gmp/GMPPlatform.h
+++ b/content/media/gmp/GMPPlatform.h
@@ -8,16 +8,18 @@
 
 #include "mozilla/Mutex.h"
 #include "gmp-platform.h"
 #include "base/thread.h"
 
 namespace mozilla {
 namespace gmp {
 
+class GMPChild;
+
 void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
 
 class GMPThreadImpl : public GMPThread
 {
 public:
   GMPThreadImpl();
   virtual ~GMPThreadImpl();
 
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -178,17 +178,17 @@ GeckoMediaPluginService::GetThread(nsITh
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
                                             const nsAString& aOrigin,
                                             GMPVideoHost** aOutVideoHost,
-                                            GMPVideoDecoder** aGMPVD)
+                                            GMPVideoDecoderProxy** aGMPVD)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aOutVideoHost);
   NS_ENSURE_ARG(aGMPVD);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
@@ -212,17 +212,17 @@ GeckoMediaPluginService::GetGMPVideoDeco
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
                                             const nsAString& aOrigin,
                                             GMPVideoHost** aOutVideoHost,
-                                            GMPVideoEncoder** aGMPVE)
+                                            GMPVideoEncoderProxy** aGMPVE)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aOutVideoHost);
   NS_ENSURE_ARG(aGMPVE);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GMPService_h_
 #define GMPService_h_
 
+#include "nsString.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
--- a/content/media/gmp/GMPTypes.ipdlh
+++ b/content/media/gmp/GMPTypes.ipdlh
@@ -3,20 +3,20 @@
  * 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/. */
 
 namespace mozilla {
 namespace gmp {
 
 struct GMPVideoEncodedFrameData
 {
-  int64_t mCaptureTime_ms;
   uint32_t mEncodedWidth;
   uint32_t mEncodedHeight;
-  uint32_t mTimeStamp;
+  uint64_t mTimestamp; // microseconds
+  uint64_t mDuration; // microseconds
   uint32_t mFrameType;
   uint32_t mSize;
   Shmem mBuffer;
   bool mCompleteFrame;
 };
 
 struct GMPPlaneData
 {
@@ -27,14 +27,14 @@ struct GMPPlaneData
 
 struct GMPVideoi420FrameData
 {
   GMPPlaneData mYPlane;
   GMPPlaneData mUPlane;
   GMPPlaneData mVPlane;
   int32_t mWidth;
   int32_t mHeight;
-  uint32_t mTimestamp;
-  int64_t mRenderTime_ms;
+  uint64_t mTimestamp; // microseconds
+  uint64_t mDuration; // microseconds
 };
 
 }
 }
--- a/content/media/gmp/GMPVideoDecoderChild.cpp
+++ b/content/media/gmp/GMPVideoDecoderChild.cpp
@@ -76,32 +76,52 @@ void
 GMPVideoDecoderChild::InputDataExhausted()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 
   SendInputDataExhausted();
 }
 
 void
+GMPVideoDecoderChild::DrainComplete()
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  SendDrainComplete();
+}
+
+void
+GMPVideoDecoderChild::ResetComplete()
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  SendResetComplete();
+}
+
+void
 GMPVideoDecoderChild::CheckThread()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 }
 
 bool
 GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
+                                     const nsTArray<uint8_t>& aCodecSpecific,
                                      const int32_t& aCoreCount)
 {
   if (!mVideoDecoder) {
     return false;
   }
 
   // Ignore any return code. It is OK for this to fail without killing the process.
-  mVideoDecoder->InitDecode(aCodecSettings, this, aCoreCount);
-
+  mVideoDecoder->InitDecode(aCodecSettings,
+                            aCodecSpecific.Elements(),
+                            aCodecSpecific.Length(),
+                            this,
+                            aCoreCount);
   return true;
 }
 
 bool
 GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
                                  const bool& aMissingFrames,
                                  const GMPCodecSpecificInfo& aCodecSpecificInfo,
                                  const int64_t& aRenderTimeMs)
@@ -110,18 +130,16 @@ GMPVideoDecoderChild::RecvDecode(const G
     return false;
   }
 
   auto f = new GMPVideoEncodedFrameImpl(aInputFrame, &mVideoHost);
 
   // Ignore any return code. It is OK for this to fail without killing the process.
   mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo, aRenderTimeMs);
 
-  // Return SHM to sender to recycle
-  //SendDecodeReturn(aInputFrame, aCodecSpecificInfo);
   return true;
 }
 
 bool
 GMPVideoDecoderChild::RecvChildShmemForPool(Shmem& aFrameBuffer)
 {
   if (aFrameBuffer.IsWritable()) {
     mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData,
--- a/content/media/gmp/GMPVideoDecoderChild.h
+++ b/content/media/gmp/GMPVideoDecoderChild.h
@@ -6,38 +6,41 @@
 #ifndef GMPVideoDecoderChild_h_
 #define GMPVideoDecoderChild_h_
 
 #include "nsString.h"
 #include "mozilla/gmp/PGMPVideoDecoderChild.h"
 #include "gmp-video-decode.h"
 #include "GMPSharedMemManager.h"
 #include "GMPVideoHost.h"
+#include "mozilla/gmp/GMPTypes.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPChild;
 
 class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
-                             public GMPDecoderCallback,
+                             public GMPVideoDecoderCallback,
                              public GMPSharedMemManager
 {
 public:
   GMPVideoDecoderChild(GMPChild* aPlugin);
   virtual ~GMPVideoDecoderChild();
 
   void Init(GMPVideoDecoder* aDecoder);
   GMPVideoHostImpl& Host();
 
-  // GMPDecoderCallback
+  // GMPVideoDecoderCallback
   virtual void Decoded(GMPVideoi420Frame* decodedFrame) MOZ_OVERRIDE;
   virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) MOZ_OVERRIDE;
   virtual void ReceivedDecodedFrame(const uint64_t pictureId) MOZ_OVERRIDE;
   virtual void InputDataExhausted() MOZ_OVERRIDE;
+  virtual void DrainComplete() MOZ_OVERRIDE;
+  virtual void ResetComplete() MOZ_OVERRIDE;
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifndef SHMEM_ALLOC_IN_CHILD
     return CallNeedShmem(aSize, aMem);
 #else
@@ -55,16 +58,17 @@ public:
 #else
     DeallocShmem(aMem);
 #endif
   }
 
 private:
   // PGMPVideoDecoderChild
   virtual bool RecvInitDecode(const GMPVideoCodec& codecSettings,
+                              const nsTArray<uint8_t>& aCodecSpecific,
                               const int32_t& coreCount) MOZ_OVERRIDE;
   virtual bool RecvDecode(const GMPVideoEncodedFrameData& inputFrame,
                           const bool& missingFrames,
                           const GMPCodecSpecificInfo& codecSpecificInfo,
                           const int64_t& renderTimeMs) MOZ_OVERRIDE;
   virtual bool RecvChildShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
   virtual bool RecvReset() MOZ_OVERRIDE;
   virtual bool RecvDrain() MOZ_OVERRIDE;
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -7,16 +7,17 @@
 #include "GMPVideoEncodedFrameImpl.h"
 #include "GMPVideoi420FrameImpl.h"
 #include "GMPParent.h"
 #include <stdio.h>
 #include "mozilla/unused.h"
 #include "GMPMessageUtils.h"
 #include "nsAutoRef.h"
 #include "nsThreadUtils.h"
+#include "mozilla/gmp/GMPTypes.h"
 
 template <>
 class nsAutoRefTraits<GMPVideoEncodedFrame> : public nsPointerRefTraits<GMPVideoEncodedFrame>
 {
 public:
   static void Release(GMPVideoEncodedFrame* aFrame) { aFrame->Destroy(); }
 };
 
@@ -37,134 +38,137 @@ GMPVideoDecoderParent::~GMPVideoDecoderP
 }
 
 GMPVideoHostImpl&
 GMPVideoDecoderParent::Host()
 {
   return mVideoHost;
 }
 
-GMPVideoErr
+nsresult
 GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
-                                  GMPDecoderCallback* aCallback,
+                                  const nsTArray<uint8_t>& aCodecSpecific,
+                                  GMPVideoDecoderCallback* aCallback,
                                   int32_t aCoreCount)
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video decoder!");
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!aCallback) {
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
   mCallback = aCallback;
 
-  if (!SendInitDecode(aCodecSettings, aCoreCount)) {
-    return GMPVideoGenericErr;
+  if (!SendInitDecode(aCodecSettings, aCodecSpecific, aCoreCount)) {
+    return NS_ERROR_FAILURE;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return NS_OK;
 }
 
-GMPVideoErr
+nsresult
 GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
                               bool aMissingFrames,
                               const GMPCodecSpecificInfo& aCodecSpecificInfo,
                               int64_t aRenderTimeMs)
 {
   nsAutoRef<GMPVideoEncodedFrame> autoDestroy(aInputFrame);
 
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video decoder!");
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   auto inputFrameImpl = static_cast<GMPVideoEncodedFrameImpl*>(aInputFrame);
 
   GMPVideoEncodedFrameData frameData;
   inputFrameImpl->RelinquishFrameData(frameData);
 
   // Very rough kill-switch if the plugin stops processing.  If it's merely
   // hung and continues, we'll come back to life eventually.
   // 3* is because we're using 3 buffers per frame for i420 data for now.
   if (NumInUse(kGMPFrameData) > 3*GMPSharedMemManager::kGMPBufLimit ||
       NumInUse(kGMPEncodedData) > GMPSharedMemManager::kGMPBufLimit) {
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   if (!SendDecode(frameData,
                   aMissingFrames,
                   aCodecSpecificInfo,
                   aRenderTimeMs)) {
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return NS_OK;
 }
 
-GMPVideoErr
+nsresult
 GMPVideoDecoderParent::Reset()
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video decoder!");
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!SendReset()) {
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return NS_OK;
 }
 
-GMPVideoErr
+nsresult
 GMPVideoDecoderParent::Drain()
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video decoder!");
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!SendDrain()) {
-    return GMPVideoGenericErr;
+    return NS_ERROR_FAILURE;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return NS_OK;
 }
 
 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
-void
+nsresult
 GMPVideoDecoderParent::DecodingComplete()
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video decoder!");
-    return;
+    return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   mCanSendMessages = false;
 
   mCallback = nullptr;
 
   mVideoHost.DoneWithAPI();
 
   unused << SendDecodingComplete();
+
+  return NS_OK;
 }
 
 // Note: Keep this sync'd up with DecodingComplete
 void
 GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (mPlugin) {
     // Ignore any return code. It is OK for this to fail without killing the process.
@@ -232,16 +236,42 @@ GMPVideoDecoderParent::RecvInputDataExha
 
   // Ignore any return code. It is OK for this to fail without killing the process.
   mCallback->InputDataExhausted();
 
   return true;
 }
 
 bool
+GMPVideoDecoderParent::RecvDrainComplete()
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->DrainComplete();
+
+  return true;
+}
+
+bool
+GMPVideoDecoderParent::RecvResetComplete()
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->ResetComplete();
+
+  return true;
+}
+
+bool
 GMPVideoDecoderParent::RecvParentShmemForPool(Shmem& aEncodedBuffer)
 {
   if (aEncodedBuffer.IsWritable()) {
     mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData,
                                                aEncodedBuffer);
   }
   return true;
 }
--- a/content/media/gmp/GMPVideoDecoderParent.h
+++ b/content/media/gmp/GMPVideoDecoderParent.h
@@ -7,44 +7,46 @@
 #define GMPVideoDecoderParent_h_
 
 #include "mozilla/RefPtr.h"
 #include "gmp-video-decode.h"
 #include "mozilla/gmp/PGMPVideoDecoderParent.h"
 #include "GMPMessageUtils.h"
 #include "GMPSharedMemManager.h"
 #include "GMPVideoHost.h"
+#include "GMPVideoDecoderProxy.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
-class GMPVideoDecoderParent MOZ_FINAL : public GMPVideoDecoder
-                                      , public PGMPVideoDecoderParent
+class GMPVideoDecoderParent MOZ_FINAL : public PGMPVideoDecoderParent
                                       , public GMPSharedMemManager
+                                      , public GMPVideoDecoderProxy
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(GMPVideoDecoderParent)
 
   GMPVideoDecoderParent(GMPParent *aPlugin);
 
   GMPVideoHostImpl& Host();
 
   // GMPVideoDecoder
-  virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
-                                 GMPDecoderCallback* aCallback,
-                                 int32_t aCoreCount) MOZ_OVERRIDE;
-  virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
-                             bool aMissingFrames,
-                             const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                             int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
-  virtual GMPVideoErr Reset() MOZ_OVERRIDE;
-  virtual GMPVideoErr Drain() MOZ_OVERRIDE;
-  virtual void DecodingComplete() MOZ_OVERRIDE;
+  virtual nsresult InitDecode(const GMPVideoCodec& aCodecSettings,
+                              const nsTArray<uint8_t>& aCodecSpecific,
+                              GMPVideoDecoderCallback* aCallback,
+                              int32_t aCoreCount);
+  virtual nsresult Decode(GMPVideoEncodedFrame* aInputFrame,
+                          bool aMissingFrames,
+                          const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                          int64_t aRenderTimeMs = -1);
+  virtual nsresult Reset();
+  virtual nsresult Drain();
+  virtual nsresult DecodingComplete();
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifdef GMP_SAFE_SHMEM
     return AllocShmem(aSize, aType, aMem);
 #else
@@ -60,23 +62,25 @@ private:
   ~GMPVideoDecoderParent();
 
   // PGMPVideoDecoderParent
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual bool RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame) MOZ_OVERRIDE;
   virtual bool RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
   virtual bool RecvReceivedDecodedFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
   virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
+  virtual bool RecvDrainComplete() MOZ_OVERRIDE;
+  virtual bool RecvResetComplete() MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mCanSendMessages;
   GMPParent* mPlugin;
-  GMPDecoderCallback* mCallback;
+  GMPVideoDecoderCallback* mCallback;
   GMPVideoHostImpl mVideoHost;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoDecoderParent_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPVideoDecoderProxy.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPVideoDecoderProxy_h_
+#define GMPVideoDecoderProxy_h_
+
+#include "nsTArray.h"
+#include "gmp-video-decode.h"
+#include "gmp-video-frame-i420.h"
+#include "gmp-video-frame-encoded.h"
+
+// A proxy to GMPVideoDecoder in the child process.
+// GMPVideoDecoderParent exposes this to users the GMP.
+// This enables Gecko to pass nsTArrays to the child GMP and avoid
+// an extra copy when doing so.
+class GMPVideoDecoderProxy {
+public:
+  virtual nsresult InitDecode(const GMPVideoCodec& aCodecSettings,
+                              const nsTArray<uint8_t>& aCodecSpecific,
+                              GMPVideoDecoderCallback* aCallback,
+                              int32_t aCoreCount) = 0;
+  virtual nsresult Decode(GMPVideoEncodedFrame* aInputFrame,
+                          bool aMissingFrames,
+                          const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                          int64_t aRenderTimeMs = -1) = 0;
+  virtual nsresult Reset() = 0;
+  virtual nsresult Drain() = 0;
+  virtual nsresult DecodingComplete() = 0;
+};
+
+#endif
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
@@ -9,33 +9,33 @@
 #include "GMPSharedMemManager.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost)
 : mEncodedWidth(0),
   mEncodedHeight(0),
-  mTimeStamp(0),
-  mCaptureTime_ms(0),
+  mTimeStamp(0ll),
+  mDuration(0ll),
   mFrameType(kGMPDeltaFrame),
   mSize(0),
   mCompleteFrame(false),
   mHost(aHost)
 {
   MOZ_ASSERT(aHost);
   aHost->EncodedFrameCreated(this);
 }
 
 GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData,
                                                    GMPVideoHostImpl* aHost)
 : mEncodedWidth(aFrameData.mEncodedWidth()),
   mEncodedHeight(aFrameData.mEncodedHeight()),
-  mTimeStamp(aFrameData.mTimeStamp()),
-  mCaptureTime_ms(aFrameData.mCaptureTime_ms()),
+  mTimeStamp(aFrameData.mTimestamp()),
+  mDuration(aFrameData.mDuration()),
   mFrameType(static_cast<GMPVideoFrameType>(aFrameData.mFrameType())),
   mSize(aFrameData.mSize()),
   mCompleteFrame(aFrameData.mCompleteFrame()),
   mHost(aHost),
   mBuffer(aFrameData.mBuffer())
 {
   MOZ_ASSERT(aHost);
   aHost->EncodedFrameCreated(this);
@@ -44,16 +44,22 @@ GMPVideoEncodedFrameImpl::GMPVideoEncode
 GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
 {
   DestroyBuffer();
   if (mHost) {
     mHost->EncodedFrameDestroyed(this);
   }
 }
 
+const GMPEncryptedBufferData*
+GMPVideoEncodedFrameImpl::GetDecryptionData() const
+{
+  return nullptr;
+}
+
 GMPVideoFrameFormat
 GMPVideoEncodedFrameImpl::GetFrameFormat()
 {
   return kGMPEncodedVideoFrame;
 }
 
 void
 GMPVideoEncodedFrameImpl::DoneWithAPI()
@@ -75,18 +81,18 @@ GMPVideoEncodedFrameImpl::ActorDestroyed
   mHost = nullptr;
 }
 
 bool
 GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData)
 {
   aFrameData.mEncodedWidth() = mEncodedWidth;
   aFrameData.mEncodedHeight() = mEncodedHeight;
-  aFrameData.mTimeStamp() = mTimeStamp;
-  aFrameData.mCaptureTime_ms() = mCaptureTime_ms;
+  aFrameData.mTimestamp() = mTimeStamp;
+  aFrameData.mDuration() = mDuration;
   aFrameData.mFrameType() = mFrameType;
   aFrameData.mSize() = mSize;
   aFrameData.mCompleteFrame() = mCompleteFrame;
   aFrameData.mBuffer() = mBuffer;
 
   // This method is called right before Shmem is sent to another process.
   // We need to effectively zero out our member copy so that we don't
   // try to delete Shmem we don't own later.
@@ -99,56 +105,56 @@ void
 GMPVideoEncodedFrameImpl::DestroyBuffer()
 {
   if (mHost && mBuffer.IsWritable()) {
     mHost->SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData, mBuffer);
   }
   mBuffer = ipc::Shmem();
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
 {
   if (aSize == 0) {
     DestroyBuffer();
   } else if (aSize > AllocatedSize()) {
     DestroyBuffer();
     if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPEncodedData, aSize,
                                               ipc::SharedMemory::TYPE_BASIC, &mBuffer) ||
         !Buffer()) {
-      return GMPVideoAllocErr;
+      return GMPAllocErr;
     }
   }
   mSize = aSize;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
 {
   auto& f = static_cast<const GMPVideoEncodedFrameImpl&>(aFrame);
 
   if (f.mSize != 0) {
-    GMPVideoErr err = CreateEmptyFrame(f.mSize);
-    if (err != GMPVideoNoErr) {
+    GMPErr err = CreateEmptyFrame(f.mSize);
+    if (err != GMPNoErr) {
       return err;
     }
     memcpy(Buffer(), f.Buffer(), f.mSize);
   }
   mEncodedWidth = f.mEncodedWidth;
   mEncodedHeight = f.mEncodedHeight;
   mTimeStamp = f.mTimeStamp;
-  mCaptureTime_ms = f.mCaptureTime_ms;
+  mDuration = f.mDuration;
   mFrameType = f.mFrameType;
   mSize = f.mSize; // already set...
   mCompleteFrame = f.mCompleteFrame;
   // Don't copy host, that should have been set properly on object creation via host.
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 void
 GMPVideoEncodedFrameImpl::SetEncodedWidth(uint32_t aEncodedWidth)
 {
   mEncodedWidth = aEncodedWidth;
 }
 
@@ -166,37 +172,37 @@ GMPVideoEncodedFrameImpl::SetEncodedHeig
 
 uint32_t
 GMPVideoEncodedFrameImpl::EncodedHeight()
 {
   return mEncodedHeight;
 }
 
 void
-GMPVideoEncodedFrameImpl::SetTimeStamp(uint32_t aTimeStamp)
+GMPVideoEncodedFrameImpl::SetTimeStamp(uint64_t aTimeStamp)
 {
   mTimeStamp = aTimeStamp;
 }
 
-uint32_t
+uint64_t
 GMPVideoEncodedFrameImpl::TimeStamp()
 {
   return mTimeStamp;
 }
 
 void
-GMPVideoEncodedFrameImpl::SetCaptureTime(int64_t aCaptureTime)
+GMPVideoEncodedFrameImpl::SetDuration(uint64_t aDuration)
 {
-  mCaptureTime_ms = aCaptureTime;
+  mDuration = aDuration;
 }
 
-int64_t
-GMPVideoEncodedFrameImpl::CaptureTime()
+uint64_t
+GMPVideoEncodedFrameImpl::Duration() const
 {
-  return mCaptureTime_ms;
+  return mDuration;
 }
 
 void
 GMPVideoEncodedFrameImpl::SetFrameType(GMPVideoFrameType aFrameType)
 {
   mFrameType = aFrameType;
 }
 
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.h
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.h
@@ -26,19 +26,20 @@
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMPVideoEncodedFrameImpl_h_
 #define GMPVideoEncodedFrameImpl_h_
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include "gmp-video-frame.h"
 #include "gmp-video-frame-encoded.h"
+#include "gmp-decryption.h"
 #include "mozilla/ipc/Shmem.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPVideoHostImpl;
 class GMPVideoEncodedFrameData;
 
@@ -58,44 +59,50 @@ public:
 
   bool RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData);
 
   // GMPVideoFrame
   virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
   virtual void Destroy() MOZ_OVERRIDE;
 
   // GMPVideoEncodedFrame
-  virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
-  virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
+  virtual GMPErr   CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
+  virtual GMPErr   CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
   virtual void     SetEncodedWidth(uint32_t aEncodedWidth) MOZ_OVERRIDE;
   virtual uint32_t EncodedWidth() MOZ_OVERRIDE;
   virtual void     SetEncodedHeight(uint32_t aEncodedHeight) MOZ_OVERRIDE;
   virtual uint32_t EncodedHeight() MOZ_OVERRIDE;
-  virtual void     SetTimeStamp(uint32_t aTimeStamp) MOZ_OVERRIDE;
-  virtual uint32_t TimeStamp() MOZ_OVERRIDE;
-  virtual void     SetCaptureTime(int64_t aCaptureTime) MOZ_OVERRIDE;
-  virtual int64_t  CaptureTime() MOZ_OVERRIDE;
+  // Microseconds
+  virtual void     SetTimeStamp(uint64_t aTimeStamp) MOZ_OVERRIDE;
+  virtual uint64_t TimeStamp() MOZ_OVERRIDE;
+  // Set frame duration (microseconds)
+  // NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
+  // depending on rounding to avoid having to track roundoff errors
+  // and dropped/missing frames(!) (which may leave a large gap)
+  virtual void     SetDuration(uint64_t aDuration) MOZ_OVERRIDE;
+  virtual uint64_t Duration() const MOZ_OVERRIDE;
   virtual void     SetFrameType(GMPVideoFrameType aFrameType) MOZ_OVERRIDE;
   virtual GMPVideoFrameType FrameType() MOZ_OVERRIDE;
   virtual void     SetAllocatedSize(uint32_t aNewSize) MOZ_OVERRIDE;
   virtual uint32_t AllocatedSize() MOZ_OVERRIDE;
   virtual void     SetSize(uint32_t aSize) MOZ_OVERRIDE;
   virtual uint32_t Size() MOZ_OVERRIDE;
   virtual void     SetCompleteFrame(bool aCompleteFrame) MOZ_OVERRIDE;
   virtual bool     CompleteFrame() MOZ_OVERRIDE;
   virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
   virtual uint8_t* Buffer() MOZ_OVERRIDE;
+  virtual const    GMPEncryptedBufferData* GetDecryptionData() const MOZ_OVERRIDE;
 
 private:
   void DestroyBuffer();
 
   uint32_t mEncodedWidth;
   uint32_t mEncodedHeight;
-  uint32_t mTimeStamp;
-  int64_t  mCaptureTime_ms;
+  uint64_t mTimeStamp;
+  uint64_t mDuration;
   GMPVideoFrameType mFrameType;
   uint32_t mSize;
   bool     mCompleteFrame;
   GMPVideoHostImpl* mHost;
   ipc::Shmem mBuffer;
 };
 
 } // namespace gmp
--- a/content/media/gmp/GMPVideoEncoderChild.cpp
+++ b/content/media/gmp/GMPVideoEncoderChild.cpp
@@ -5,18 +5,16 @@
 
 #include "GMPVideoEncoderChild.h"
 #include "GMPChild.h"
 #include <stdio.h>
 #include "mozilla/unused.h"
 #include "GMPVideoEncodedFrameImpl.h"
 #include "GMPVideoi420FrameImpl.h"
 
-using mozilla::ipc::ProcessChild;
-
 namespace mozilla {
 namespace gmp {
 
 GMPVideoEncoderChild::GMPVideoEncoderChild(GMPChild* aPlugin)
 : mPlugin(aPlugin),
   mVideoEncoder(nullptr),
   mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
 {
@@ -59,46 +57,48 @@ GMPVideoEncoderChild::Encoded(GMPVideoEn
 void
 GMPVideoEncoderChild::CheckThread()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 }
 
 bool
 GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
+                                     const nsTArray<uint8_t>& aCodecSpecific,
                                      const int32_t& aNumberOfCores,
                                      const uint32_t& aMaxPayloadSize)
 {
   if (!mVideoEncoder) {
     return false;
   }
 
   // Ignore any return code. It is OK for this to fail without killing the process.
-  mVideoEncoder->InitEncode(aCodecSettings, this, aNumberOfCores, aMaxPayloadSize);
+  mVideoEncoder->InitEncode(aCodecSettings,
+                            aCodecSpecific.Elements(),
+                            aCodecSpecific.Length(),
+                            this,
+                            aNumberOfCores,
+                            aMaxPayloadSize);
 
   return true;
 }
 
 bool
 GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
                                  const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                                 const InfallibleTArray<int>& aFrameTypes)
+                                 const nsTArray<GMPVideoFrameType>& aFrameTypes)
 {
   if (!mVideoEncoder) {
     return false;
   }
 
   auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost);
 
-  std::vector<GMPVideoFrameType> frameTypes(aFrameTypes.Length());
-  for (uint32_t i = 0; i < aFrameTypes.Length(); i++) {
-    frameTypes[i] = static_cast<GMPVideoFrameType>(aFrameTypes[i]);
-  }
   // Ignore any return code. It is OK for this to fail without killing the process.
-  mVideoEncoder->Encode(f, aCodecSpecificInfo, frameTypes);
+  mVideoEncoder->Encode(f, aCodecSpecificInfo, aFrameTypes.Elements(), aFrameTypes.Length());
 
   return true;
 }
 
 bool
 GMPVideoEncoderChild::RecvChildShmemForPool(Shmem& aEncodedBuffer)
 {
   if (aEncodedBuffer.IsWritable()) {
--- a/content/media/gmp/GMPVideoEncoderChild.h
+++ b/content/media/gmp/GMPVideoEncoderChild.h
@@ -13,27 +13,27 @@
 #include "GMPVideoHost.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPChild;
 
 class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
-                             public GMPEncoderCallback,
+                             public GMPVideoEncoderCallback,
                              public GMPSharedMemManager
 {
 public:
   GMPVideoEncoderChild(GMPChild* aPlugin);
   virtual ~GMPVideoEncoderChild();
 
   void Init(GMPVideoEncoder* aEncoder);
   GMPVideoHostImpl& Host();
 
-  // GMPEncoderCallback
+  // GMPVideoEncoderCallback
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifndef SHMEM_ALLOC_IN_CHILD
@@ -53,21 +53,22 @@ public:
 #else
     DeallocShmem(aMem);
 #endif
   }
 
 private:
   // PGMPVideoEncoderChild
   virtual bool RecvInitEncode(const GMPVideoCodec& aCodecSettings,
+                              const nsTArray<uint8_t>& aCodecSpecific,
                               const int32_t& aNumberOfCores,
                               const uint32_t& aMaxPayloadSize) MOZ_OVERRIDE;
   virtual bool RecvEncode(const GMPVideoi420FrameData& aInputFrame,
                           const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                          const InfallibleTArray<int>& aFrameTypes) MOZ_OVERRIDE;
+                          const nsTArray<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
   virtual bool RecvChildShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
   virtual bool RecvSetChannelParameters(const uint32_t& aPacketLoss,
                                         const uint32_t& aRTT) MOZ_OVERRIDE;
   virtual bool RecvSetRates(const uint32_t& aNewBitRate,
                             const uint32_t& aFrameRate) MOZ_OVERRIDE;
   virtual bool RecvSetPeriodicKeyFrames(const bool& aEnable) MOZ_OVERRIDE;
   virtual bool RecvEncodingComplete() MOZ_OVERRIDE;
 
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -38,137 +38,132 @@ GMPVideoEncoderParent::~GMPVideoEncoderP
 }
 
 GMPVideoHostImpl&
 GMPVideoEncoderParent::Host()
 {
   return mVideoHost;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncoderParent::InitEncode(const GMPVideoCodec& aCodecSettings,
-                                  GMPEncoderCallback* aCallback,
+                                  const nsTArray<uint8_t>& aCodecSpecific,
+                                  GMPVideoEncoderCallback* aCallback,
                                   int32_t aNumberOfCores,
                                   uint32_t aMaxPayloadSize)
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!aCallback) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
   mCallback = aCallback;
 
-  if (!SendInitEncode(aCodecSettings, aNumberOfCores, aMaxPayloadSize)) {
-    return GMPVideoGenericErr;
+  if (!SendInitEncode(aCodecSettings, aCodecSpecific, aNumberOfCores, aMaxPayloadSize)) {
+    return GMPGenericErr;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
                               const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                              const std::vector<GMPVideoFrameType>& aFrameTypes)
+                              const nsTArray<GMPVideoFrameType>& aFrameTypes)
 {
   nsAutoRef<GMPVideoi420Frame> frameRef(aInputFrame);
 
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   auto inputFrameImpl = static_cast<GMPVideoi420FrameImpl*>(aInputFrame);
 
   GMPVideoi420FrameData frameData;
   inputFrameImpl->InitFrameData(frameData);
 
   // Very rough kill-switch if the plugin stops processing.  If it's merely
   // hung and continues, we'll come back to life eventually.
   // 3* is because we're using 3 buffers per frame for i420 data for now.
   if (NumInUse(kGMPFrameData) > 3*GMPSharedMemManager::kGMPBufLimit ||
       NumInUse(kGMPEncodedData) > GMPSharedMemManager::kGMPBufLimit) {
-    return GMPVideoGenericErr;
-  }
-
-  InfallibleTArray<int> frameTypes;
-  frameTypes.SetCapacity(aFrameTypes.size());
-  for (std::vector<int>::size_type i = 0; i != aFrameTypes.size(); i++) {
-    frameTypes.AppendElement(static_cast<int>(aFrameTypes[i]));
+    return GMPGenericErr;
   }
 
   if (!SendEncode(frameData,
                   aCodecSpecificInfo,
-                  frameTypes)) {
-    return GMPVideoGenericErr;
+                  aFrameTypes)) {
+    return GMPGenericErr;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncoderParent::SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT)
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!SendSetChannelParameters(aPacketLoss, aRTT)) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncoderParent::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate)
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!SendSetRates(aNewBitRate, aFrameRate)) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoEncoderParent::SetPeriodicKeyFrames(bool aEnable)
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
   if (!SendSetPeriodicKeyFrames(aEnable)) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   // Async IPC, we don't have access to a return value.
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
 void
 GMPVideoEncoderParent::EncodingComplete()
 {
   if (!mCanSendMessages) {
     NS_WARNING("Trying to use an invalid GMP video encoder!");
--- a/content/media/gmp/GMPVideoEncoderParent.h
+++ b/content/media/gmp/GMPVideoEncoderParent.h
@@ -7,44 +7,46 @@
 #define GMPVideoEncoderParent_h_
 
 #include "mozilla/RefPtr.h"
 #include "gmp-video-encode.h"
 #include "mozilla/gmp/PGMPVideoEncoderParent.h"
 #include "GMPMessageUtils.h"
 #include "GMPSharedMemManager.h"
 #include "GMPVideoHost.h"
+#include "GMPVideoEncoderProxy.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
-class GMPVideoEncoderParent : public GMPVideoEncoder,
+class GMPVideoEncoderParent : public GMPVideoEncoderProxy,
                               public PGMPVideoEncoderParent,
                               public GMPSharedMemManager
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(GMPVideoEncoderParent)
 
   GMPVideoEncoderParent(GMPParent *aPlugin);
 
   GMPVideoHostImpl& Host();
 
-  // GMPVideoEncoder
-  virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
-                                 GMPEncoderCallback* aCallback,
-                                 int32_t aNumberOfCores,
-                                 uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
-  virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
-                             const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                             const std::vector<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
-  virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
-  virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
-  virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
+  // GMPVideoEncoderProxy
+  virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
+                            const nsTArray<uint8_t>& aCodecSpecific,
+                            GMPVideoEncoderCallback* aCallback,
+                            int32_t aNumberOfCores,
+                            uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
+  virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
+                        const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                        const nsTArray<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
+  virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
+  virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
+  virtual GMPErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
   virtual void EncodingComplete() MOZ_OVERRIDE;
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifdef GMP_SAFE_SHMEM
     return AllocShmem(aSize, aType, aMem);
@@ -66,16 +68,16 @@ private:
                            const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mCanSendMessages;
   GMPParent* mPlugin;
-  GMPEncoderCallback* mCallback;
+  GMPVideoEncoderCallback* mCallback;
   GMPVideoHostImpl mVideoHost;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoEncoderParent_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/GMPVideoEncoderProxy.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GMPVideoEncoderProxy_h_
+#define GMPVideoEncoderProxy_h_
+
+#include "nsTArray.h"
+#include "gmp-video-encode.h"
+#include "gmp-video-frame-i420.h"
+#include "gmp-video-frame-encoded.h"
+
+// A proxy to GMPVideoEncoder in the child process.
+// GMPVideoEncoderParent exposes this to users the GMP.
+// This enables Gecko to pass nsTArrays to the child GMP and avoid
+// an extra copy when doing so.
+class GMPVideoEncoderProxy {
+public:
+  virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
+                            const nsTArray<uint8_t>& aCodecSpecific,
+                            GMPVideoEncoderCallback* aCallback,
+                            int32_t aNumberOfCores,
+                            uint32_t aMaxPayloadSize) = 0;
+  virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
+                        const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                        const nsTArray<GMPVideoFrameType>& aFrameTypes) = 0;
+  virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
+  virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
+  virtual GMPErr SetPeriodicKeyFrames(bool aEnable) = 0;
+  virtual void EncodingComplete() = 0;
+};
+
+#endif // GMPVideoEncoderProxy_h_
--- a/content/media/gmp/GMPVideoHost.cpp
+++ b/content/media/gmp/GMPVideoHost.cpp
@@ -15,59 +15,59 @@ GMPVideoHostImpl::GMPVideoHostImpl(GMPSh
 : mSharedMemMgr(aSharedMemMgr)
 {
 }
 
 GMPVideoHostImpl::~GMPVideoHostImpl()
 {
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoHostImpl::CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame)
 {
   if (!mSharedMemMgr) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   if (!aFrame) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
   *aFrame = nullptr;
 
   switch (aFormat) {
     case kGMPI420VideoFrame:
       *aFrame = new GMPVideoi420FrameImpl(this);
-      return GMPVideoNoErr;
+      return GMPNoErr;
     case kGMPEncodedVideoFrame:
       *aFrame = new GMPVideoEncodedFrameImpl(this);
-      return GMPVideoNoErr;
+      return GMPNoErr;
     default:
       NS_NOTREACHED("Unknown frame format!");
   }
 
-  return GMPVideoGenericErr;
+  return GMPGenericErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
 {
   if (!mSharedMemMgr) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   if (!aPlane) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
   *aPlane = nullptr;
 
   auto p = new GMPPlaneImpl(this);
 
   *aPlane = p;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 GMPSharedMemManager*
 GMPVideoHostImpl::SharedMemMgr()
 {
   return mSharedMemMgr;
 }
 
--- a/content/media/gmp/GMPVideoHost.h
+++ b/content/media/gmp/GMPVideoHost.h
@@ -30,18 +30,18 @@ public:
   void DoneWithAPI();
   void ActorDestroyed();
   void PlaneCreated(GMPPlaneImpl* aPlane);
   void PlaneDestroyed(GMPPlaneImpl* aPlane);
   void EncodedFrameCreated(GMPVideoEncodedFrameImpl* aEncodedFrame);
   void EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame);
 
   // GMPVideoHost
-  virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
-  virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
+  virtual GMPErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
+  virtual GMPErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
 
 private:
   // All shared memory allocations have to be made by an IPDL actor.
   // This is a reference to the owning actor. If this reference is
   // null then the actor has died and all allocations must fail.
   GMPSharedMemManager* mSharedMemMgr;
 
   // We track all of these things because they need to handle further
--- a/content/media/gmp/GMPVideoPlaneImpl.cpp
+++ b/content/media/gmp/GMPVideoPlaneImpl.cpp
@@ -68,107 +68,107 @@ GMPPlaneImpl::InitPlaneData(GMPPlaneData
   // This method is called right before Shmem is sent to another process.
   // We need to effectively zero out our member copy so that we don't
   // try to delete memory we don't own later.
   mBuffer = ipc::Shmem();
 
   return true;
 }
 
-GMPVideoErr
+GMPErr
 GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
   if (aNewSize <= AllocatedSize()) {
-    return GMPVideoNoErr;
+    return GMPNoErr;
   }
 
   if (!mHost) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   ipc::Shmem new_mem;
   if (!mHost->SharedMemMgr()->MgrAllocShmem(GMPSharedMemManager::kGMPFrameData, aNewSize,
                                             ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
       !new_mem.get<uint8_t>()) {
-    return GMPVideoAllocErr;
+    return GMPAllocErr;
   }
 
   if (mBuffer.IsReadable()) {
     memcpy(new_mem.get<uint8_t>(), Buffer(), mSize);
   }
 
   DestroyBuffer();
 
   mBuffer = new_mem;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 void
 GMPPlaneImpl::DestroyBuffer()
 {
   if (mHost && mBuffer.IsWritable()) {
     mHost->SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData, mBuffer);
   }
   mBuffer = ipc::Shmem();
 }
 
-GMPVideoErr
+GMPErr
 GMPPlaneImpl::CreateEmptyPlane(int32_t aAllocatedSize, int32_t aStride, int32_t aPlaneSize)
 {
   if (aAllocatedSize < 1 || aStride < 1 || aPlaneSize < 1) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
-  GMPVideoErr err = MaybeResize(aAllocatedSize);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = MaybeResize(aAllocatedSize);
+  if (err != GMPNoErr) {
     return err;
   }
 
   mSize = aPlaneSize;
   mStride = aStride;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPPlaneImpl::Copy(const GMPPlane& aPlane)
 {
   auto& planeimpl = static_cast<const GMPPlaneImpl&>(aPlane);
 
-  GMPVideoErr err = MaybeResize(planeimpl.mSize);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = MaybeResize(planeimpl.mSize);
+  if (err != GMPNoErr) {
     return err;
   }
 
   if (planeimpl.Buffer() && planeimpl.mSize > 0) {
     memcpy(Buffer(), planeimpl.Buffer(), mSize);
   }
 
   mSize = planeimpl.mSize;
   mStride = planeimpl.mStride;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
 {
-  GMPVideoErr err = MaybeResize(aSize);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = MaybeResize(aSize);
+  if (err != GMPNoErr) {
     return err;
   }
 
   if (aBuffer && aSize > 0) {
     memcpy(Buffer(), aBuffer, aSize);
   }
 
   mSize = aSize;
   mStride = aStride;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 void
 GMPPlaneImpl::Swap(GMPPlane& aPlane)
 {
   auto& planeimpl = static_cast<GMPPlaneImpl&>(aPlane);
 
   std::swap(mStride, planeimpl.mStride);
--- a/content/media/gmp/GMPVideoPlaneImpl.h
+++ b/content/media/gmp/GMPVideoPlaneImpl.h
@@ -29,34 +29,34 @@ public:
   // This is called when something has gone wrong - specicifically,
   // a child process has crashed. Does not attempt to release Shmem,
   // as the Shmem has already been released.
   void ActorDestroyed();
 
   bool InitPlaneData(GMPPlaneData& aPlaneData);
 
   // GMPPlane
-  virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
-                                       int32_t aStride,
-                                       int32_t aPlaneSize) MOZ_OVERRIDE;
-  virtual GMPVideoErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
-  virtual GMPVideoErr Copy(int32_t aSize,
-                           int32_t aStride,
-                           const uint8_t* aBuffer) MOZ_OVERRIDE;
+  virtual GMPErr CreateEmptyPlane(int32_t aAllocatedSize,
+                                  int32_t aStride,
+                                  int32_t aPlaneSize) MOZ_OVERRIDE;
+  virtual GMPErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
+  virtual GMPErr Copy(int32_t aSize,
+                      int32_t aStride,
+                      const uint8_t* aBuffer) MOZ_OVERRIDE;
   virtual void Swap(GMPPlane& aPlane) MOZ_OVERRIDE;
   virtual int32_t AllocatedSize() const MOZ_OVERRIDE;
   virtual void ResetSize() MOZ_OVERRIDE;
   virtual bool IsZeroSize() const MOZ_OVERRIDE;
   virtual int32_t Stride() const MOZ_OVERRIDE;
   virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
   virtual uint8_t* Buffer() MOZ_OVERRIDE;
   virtual void Destroy() MOZ_OVERRIDE;
 
 private:
-  GMPVideoErr MaybeResize(int32_t aNewSize);
+  GMPErr MaybeResize(int32_t aNewSize);
   void DestroyBuffer();
 
   ipc::Shmem mBuffer;
   int32_t mSize;
   int32_t mStride;
   GMPVideoHostImpl* mHost;
 };
 
--- a/content/media/gmp/GMPVideoi420FrameImpl.cpp
+++ b/content/media/gmp/GMPVideoi420FrameImpl.cpp
@@ -10,31 +10,31 @@ namespace mozilla {
 namespace gmp {
 
 GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost)
 : mYPlane(aHost),
   mUPlane(aHost),
   mVPlane(aHost),
   mWidth(0),
   mHeight(0),
-  mTimestamp(0),
-  mRenderTime_ms(0)
+  mTimestamp(0ll),
+  mDuration(0ll)
 {
   MOZ_ASSERT(aHost);
 }
 
 GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData,
                                              GMPVideoHostImpl* aHost)
 : mYPlane(aFrameData.mYPlane(), aHost),
   mUPlane(aFrameData.mUPlane(), aHost),
   mVPlane(aFrameData.mVPlane(), aHost),
   mWidth(aFrameData.mWidth()),
   mHeight(aFrameData.mHeight()),
   mTimestamp(aFrameData.mTimestamp()),
-  mRenderTime_ms(aFrameData.mRenderTime_ms())
+  mDuration(aFrameData.mDuration())
 {
   MOZ_ASSERT(aHost);
 }
 
 GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl()
 {
 }
 
@@ -42,17 +42,17 @@ bool
 GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData)
 {
   mYPlane.InitPlaneData(aFrameData.mYPlane());
   mUPlane.InitPlaneData(aFrameData.mUPlane());
   mVPlane.InitPlaneData(aFrameData.mVPlane());
   aFrameData.mWidth() = mWidth;
   aFrameData.mHeight() = mHeight;
   aFrameData.mTimestamp() = mTimestamp;
-  aFrameData.mRenderTime_ms() = mRenderTime_ms;
+  aFrameData.mDuration() = mDuration;
   return true;
 }
 
 GMPVideoFrameFormat
 GMPVideoi420FrameImpl::GetFrameFormat()
 {
   return kGMPI420VideoFrame;
 }
@@ -101,127 +101,127 @@ GMPVideoi420FrameImpl::GetPlane(GMPPlane
     case kGMPVPlane :
       return &mVPlane;
     default:
       MOZ_CRASH("Unknown plane type!");
   }
   return nullptr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
                                         int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
 {
   if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   int32_t size_y = aStride_y * aHeight;
   int32_t half_height = (aHeight + 1) / 2;
   int32_t size_u = aStride_u * half_height;
   int32_t size_v = aStride_v * half_height;
 
-  GMPVideoErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
+  if (err != GMPNoErr) {
     return err;
   }
   err = mUPlane.CreateEmptyPlane(size_u, aStride_u, size_u);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
   err = mVPlane.CreateEmptyPlane(size_v, aStride_v, size_v);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
 
   mWidth = aWidth;
   mHeight = aHeight;
-  mTimestamp = 0;
-  mRenderTime_ms = 0;
+  mTimestamp = 0ll;
+  mDuration = 0ll;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
                                    int32_t aSize_u, const uint8_t* aBuffer_u,
                                    int32_t aSize_v, const uint8_t* aBuffer_v,
                                    int32_t aWidth, int32_t aHeight,
                                    int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
 {
   MOZ_ASSERT(aBuffer_y);
   MOZ_ASSERT(aBuffer_u);
   MOZ_ASSERT(aBuffer_v);
 
   if (aSize_y < 1 || aSize_u < 1 || aSize_v < 1) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
   if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
 
-  GMPVideoErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
+  if (err != GMPNoErr) {
     return err;
   }
   err = mUPlane.Copy(aSize_u, aStride_u, aBuffer_u);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
   err = mVPlane.Copy(aSize_v, aStride_v, aBuffer_v);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
 
   mWidth = aWidth;
   mHeight = aHeight;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame)
 {
   auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);
 
-  GMPVideoErr err = mYPlane.Copy(f.mYPlane);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mYPlane.Copy(f.mYPlane);
+  if (err != GMPNoErr) {
     return err;
   }
 
   err = mUPlane.Copy(f.mUPlane);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
 
   err = mVPlane.Copy(f.mVPlane);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
 
   mWidth = f.mWidth;
   mHeight = f.mHeight;
   mTimestamp = f.mTimestamp;
-  mRenderTime_ms = f.mRenderTime_ms;
+  mDuration = f.mDuration;
 
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 void
 GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame)
 {
   auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame);
   mYPlane.Swap(f->mYPlane);
   mUPlane.Swap(f->mUPlane);
   mVPlane.Swap(f->mVPlane);
   std::swap(mWidth, f->mWidth);
   std::swap(mHeight, f->mHeight);
   std::swap(mTimestamp, f->mTimestamp);
-  std::swap(mRenderTime_ms, f->mRenderTime_ms);
+  std::swap(mDuration, f->mDuration);
 }
 
 uint8_t*
 GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType)
 {
   GMPPlane* p = GetPlane(aType);
   if (p) {
     return p->Buffer();
@@ -254,74 +254,74 @@ GMPVideoi420FrameImpl::Stride(GMPPlaneTy
 {
   const GMPPlane* p = GetPlane(aType);
   if (p) {
     return p->Stride();
   }
   return -1;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoi420FrameImpl::SetWidth(int32_t aWidth)
 {
   if (!CheckDimensions(aWidth, mHeight,
                        mYPlane.Stride(), mUPlane.Stride(),
                        mVPlane.Stride())) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
   mWidth = aWidth;
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
-GMPVideoErr
+GMPErr
 GMPVideoi420FrameImpl::SetHeight(int32_t aHeight)
 {
   if (!CheckDimensions(mWidth, aHeight,
                        mYPlane.Stride(), mUPlane.Stride(),
                        mVPlane.Stride())) {
-    return GMPVideoGenericErr;
+    return GMPGenericErr;
   }
   mHeight = aHeight;
-  return GMPVideoNoErr;
+  return GMPNoErr;
 }
 
 int32_t
 GMPVideoi420FrameImpl::Width() const
 {
   return mWidth;
 }
 
 int32_t
 GMPVideoi420FrameImpl::Height() const
 {
   return mHeight;
 }
 
 void
-GMPVideoi420FrameImpl::SetTimestamp(uint32_t aTimestamp)
+GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp)
 {
   mTimestamp = aTimestamp;
 }
 
-uint32_t
+uint64_t
 GMPVideoi420FrameImpl::Timestamp() const
 {
   return mTimestamp;
 }
 
 void
-GMPVideoi420FrameImpl::SetRenderTime_ms(int64_t aRenderTime_ms)
+GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration)
 {
-  mRenderTime_ms = aRenderTime_ms;
+  mDuration = aDuration;
 }
 
-int64_t
-GMPVideoi420FrameImpl::RenderTime_ms() const
+uint64_t
+GMPVideoi420FrameImpl::Duration() const
 {
-  return mRenderTime_ms;
+  return mDuration;
 }
 
 bool
 GMPVideoi420FrameImpl::IsZeroSize() const
 {
   return (mYPlane.IsZeroSize() && mUPlane.IsZeroSize() && mVPlane.IsZeroSize());
 }
 
--- a/content/media/gmp/GMPVideoi420FrameImpl.h
+++ b/content/media/gmp/GMPVideoi420FrameImpl.h
@@ -27,55 +27,55 @@ public:
   const GMPPlaneImpl* GetPlane(GMPPlaneType aType) const;
   GMPPlaneImpl* GetPlane(GMPPlaneType aType);
 
   // GMPVideoFrame
   virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
   virtual void Destroy() MOZ_OVERRIDE;
 
   // GMPVideoi420Frame
-  virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth,
-                                       int32_t aHeight,
-                                       int32_t aStride_y,
-                                       int32_t aStride_u,
-                                       int32_t aStride_v) MOZ_OVERRIDE;
-  virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
-                                  int32_t aSize_u, const uint8_t* aBuffer_u,
-                                  int32_t aSize_v, const uint8_t* aBuffer_v,
-                                  int32_t aWidth,
+  virtual GMPErr CreateEmptyFrame(int32_t aWidth,
                                   int32_t aHeight,
                                   int32_t aStride_y,
                                   int32_t aStride_u,
                                   int32_t aStride_v) MOZ_OVERRIDE;
-  virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
+  virtual GMPErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
+                             int32_t aSize_u, const uint8_t* aBuffer_u,
+                             int32_t aSize_v, const uint8_t* aBuffer_v,
+                             int32_t aWidth,
+                             int32_t aHeight,
+                             int32_t aStride_y,
+                             int32_t aStride_u,
+                             int32_t aStride_v) MOZ_OVERRIDE;
+  virtual GMPErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
   virtual void SwapFrame(GMPVideoi420Frame* aFrame) MOZ_OVERRIDE;
   virtual uint8_t* Buffer(GMPPlaneType aType) MOZ_OVERRIDE;
   virtual const uint8_t* Buffer(GMPPlaneType aType) const MOZ_OVERRIDE;
   virtual int32_t AllocatedSize(GMPPlaneType aType) const MOZ_OVERRIDE;
   virtual int32_t Stride(GMPPlaneType aType) const MOZ_OVERRIDE;
-  virtual GMPVideoErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
-  virtual GMPVideoErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
+  virtual GMPErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
+  virtual GMPErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
   virtual int32_t Width() const MOZ_OVERRIDE;
   virtual int32_t Height() const MOZ_OVERRIDE;
-  virtual void SetTimestamp(uint32_t aTimestamp) MOZ_OVERRIDE;
-  virtual uint32_t Timestamp() const MOZ_OVERRIDE;
-  virtual void SetRenderTime_ms(int64_t aRenderTime_ms) MOZ_OVERRIDE;
-  virtual int64_t RenderTime_ms() const MOZ_OVERRIDE;
+  virtual void SetTimestamp(uint64_t aTimestamp) MOZ_OVERRIDE;
+  virtual uint64_t Timestamp() const MOZ_OVERRIDE;
+  virtual void SetDuration(uint64_t aDuration) MOZ_OVERRIDE;
+  virtual uint64_t Duration() const MOZ_OVERRIDE;
   virtual bool IsZeroSize() const MOZ_OVERRIDE;
   virtual void ResetSize() MOZ_OVERRIDE;
 
 private:
   bool CheckDimensions(int32_t aWidth, int32_t aHeight,
                        int32_t aStride_y, int32_t aStride_u, int32_t aStride_v);
 
   GMPPlaneImpl mYPlane;
   GMPPlaneImpl mUPlane;
   GMPPlaneImpl mVPlane;
   int32_t mWidth;
   int32_t mHeight;
-  uint32_t mTimestamp;
-  int64_t mRenderTime_ms;
+  uint64_t mTimestamp;
+  uint64_t mDuration;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPVideoi420FrameImpl_h_
--- a/content/media/gmp/PGMPVideoDecoder.ipdl
+++ b/content/media/gmp/PGMPVideoDecoder.ipdl
@@ -14,32 +14,35 @@ include "GMPMessageUtils.h";
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPVideoDecoder
 {
   manager PGMP;
 child:
   async InitDecode(GMPVideoCodec aCodecSettings,
+                   uint8_t[] aCodecSpecific,
                    int32_t aCoreCount);
   async Decode(GMPVideoEncodedFrameData aInputFrame,
                bool aMissingFrames,
                GMPCodecSpecificInfo aCodecSpecificInfo,
                int64_t aRenderTimeMs);
   async Reset();
   async Drain();
   async DecodingComplete();
   async ChildShmemForPool(Shmem aFrameBuffer);
 
 parent:
   async __delete__();
   async Decoded(GMPVideoi420FrameData aDecodedFrame);
   async ReceivedDecodedReferenceFrame(uint64_t aPictureId);
   async ReceivedDecodedFrame(uint64_t aPictureId);
   async InputDataExhausted();
+  async DrainComplete();
+  async ResetComplete();
   async ParentShmemForPool(Shmem aEncodedBuffer);
   // MUST be intr - if sync and we create a new Shmem, when the returned
   // Shmem is received in the Child it will fail to Deserialize
   intr NeedShmem(uint32_t aFrameBufferSize) returns (Shmem aMem);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/PGMPVideoEncoder.ipdl
+++ b/content/media/gmp/PGMPVideoEncoder.ipdl
@@ -3,32 +3,34 @@
  * 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 protocol PGMP;
 include GMPTypes;
 
 using GMPVideoCodec from "gmp-video-codec.h";
 using GMPCodecSpecificInfo from "gmp-video-codec.h";
+using GMPVideoFrameType from "gmp-video-frame-encoded.h";
 
 include "GMPMessageUtils.h";
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPVideoEncoder
 {
   manager PGMP;
 child:
   async InitEncode(GMPVideoCodec aCodecSettings,
+                   uint8_t[] aCodecSpecific,
                    int32_t aNumberOfCores,
                    uint32_t aMaxPayloadSize);
   async Encode(GMPVideoi420FrameData aInputFrame,
                GMPCodecSpecificInfo aCodecSpecificInfo,
-               int[] aFrameTypes);
+               GMPVideoFrameType[] aFrameTypes);
   async SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT);
   async SetRates(uint32_t aNewBitRate, uint32_t aFrameRate);
   async SetPeriodicKeyFrames(bool aEnable);
   async EncodingComplete();
   async ChildShmemForPool(Shmem aEncodedBuffer);
 
 parent:
   async __delete__();
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-async-shutdown.h
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_ASYNC_SHUTDOWN_H_
+#define GMP_ASYNC_SHUTDOWN_H_
+
+// API exposed by the plugin library to manage asynchronous shutdown.
+// Some plugins require special cleanup which may need to make calls
+// to host services and wait for async responses.
+//
+// To enable a plugins to block shutdown until its async shutdown is
+// complete, implement the GMPAsyncShutdown interface and return it when
+// your plugin's GMPGetAPI function is called with "async-shutdown".
+// When your GMPAsyncShutdown's BeginShutdown() implementation is called
+// by the GMP host, you should initate your async shutdown process.
+// Once you have completed shutdown, call the ShutdownComplete() function
+// of the GMPAsyncShutdownHost that is passed as the host argument to the
+// GMPGetAPI() call.
+//
+// Note: Your GMP's GMPShutdown function will still be called after your
+// call to ShutdownComplete().
+//
+// API name: "async-shutdown"
+// Host API: GMPAsyncShutdownHost
+class GMPAsyncShutdown {
+public:
+  virtual ~GMPAsyncShutdown() {}
+
+  virtual void BeginShutdown() = 0;
+};
+
+class GMPAsyncShutdownHost {
+public:
+  virtual ~GMPAsyncShutdownHost() {}
+
+  virtual void ShutdownComplete() = 0;
+};
+
+#endif // GMP_ASYNC_SHUTDOWN_H_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-audio-codec.h
@@ -0,0 +1,43 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_AUDIO_CODEC_h_
+#define GMP_AUDIO_CODEC_h_
+
+#include <stdint.h>
+
+enum GMPAudioCodecType
+{
+  kGMPAudioCodecAAC,
+  kGMPAudioCodecVorbis,
+  kGMPAudioCodecInvalid // Should always be last.
+};
+
+struct GMPAudioCodec
+{
+  GMPAudioCodecType mCodecType;
+  uint32_t mChannelCount;
+  uint32_t mBitsPerChannel;
+  uint32_t mSamplesPerSecond;
+
+  // Codec extra data, such as vorbis setup header, or
+  // AAC AudioSpecificConfig.
+  // These are null/0 if not externally negotiated
+  const uint8_t* mExtraData;
+  size_t         mExtraDataLen;
+};
+
+#endif // GMP_AUDIO_CODEC_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-audio-decode.h
@@ -0,0 +1,72 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_AUDIO_DECODE_h_
+#define GMP_AUDIO_DECODE_h_
+
+#include "gmp-errors.h"
+#include "gmp-audio-samples.h"
+#include "gmp-audio-codec.h"
+#include <stdint.h>
+
+// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
+class GMPAudioDecoderCallback
+{
+public:
+  virtual ~GMPAudioDecoderCallback() {}
+
+  virtual void Decoded(GMPAudioSamples* aDecodedSamples) = 0;
+
+  virtual void InputDataExhausted() = 0;
+
+  virtual void DrainComplete() = 0;
+
+  virtual void ResetComplete() = 0;
+};
+
+// ALL METHODS MUST BE CALLED ON THE MAIN THREAD
+class GMPAudioDecoder
+{
+public:
+  virtual ~GMPAudioDecoder() {}
+
+  // aCallback: Subclass should retain reference to it until DecodingComplete
+  //            is called. Do not attempt to delete it, host retains ownership.
+  // TODO: Pass AudioHost so decoder can create GMPAudioEncodedFrame objects?
+  virtual GMPErr InitDecode(const GMPAudioCodec& aCodecSettings,
+                            GMPAudioDecoderCallback* aCallback) = 0;
+
+  // Decode encoded audio frames (as a part of an audio stream). The decoded
+  // frames must be returned to the user through the decode complete callback.
+  virtual GMPErr Decode(GMPAudioSamples* aEncodedSamples) = 0;
+
+  // Reset decoder state and prepare for a new call to Decode(...).
+  // Flushes the decoder pipeline.
+  // The decoder should enqueue a task to run ResetComplete() on the main
+  // thread once the reset has finished.
+  virtual GMPErr Reset() = 0;
+
+  // Output decoded frames for any data in the pipeline, regardless of ordering.
+  // All remaining decoded frames should be immediately returned via callback.
+  // The decoder should enqueue a task to run DrainComplete() on the main
+  // thread once the reset has finished.
+  virtual GMPErr Drain() = 0;
+
+  // May free decoder memory.
+  virtual void DecodingComplete() = 0;
+};
+
+#endif // GMP_VIDEO_DECODE_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-audio-host.h
@@ -0,0 +1,32 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_AUDIO_HOST_h_
+#define GMP_AUDIO_HOST_h_
+
+#include "gmp-errors.h"
+#include "gmp-audio-samples.h"
+
+class GMPAudioHost
+{
+public:
+  // Construct various Audio API objects. Host does not retain reference,
+  // caller is owner and responsible for deleting.
+  virtual GMPErr CreateSamples(GMPAudioFormat aFormat,
+                               GMPAudioSamples** aSamples) = 0;
+};
+
+#endif // GMP_AUDIO_HOST_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-audio-samples.h
@@ -0,0 +1,57 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_AUDIO_FRAME_h_
+#define GMP_AUDIO_FRAME_h_
+
+#include <stdint.h>
+#include "gmp-errors.h"
+#include "gmp-decryption.h"
+
+enum GMPAudioFormat
+{
+  kGMPAudioEncodedSamples, // Raw compressed data, i.e. an AAC/Vorbis packet.
+  kGMPAudioIS16Samples, // Interleaved int16_t PCM samples.
+  kGMPAudioSamplesFormatInvalid // Should always be last.
+};
+
+class GMPAudioSamples {
+public:
+  // The format of the buffer.
+  virtual GMPAudioFormat GetFormat() = 0;
+  virtual void Destroy() = 0;
+
+  // MAIN THREAD ONLY
+  // Buffer size must be exactly what's required to contain all samples in
+  // the buffer; every byte is assumed to be part of a sample.
+  virtual GMPErr SetBufferSize(uint32_t aSize) = 0;
+
+  // Size of the buffer in bytes.
+  virtual uint32_t Size() = 0;
+
+  // Timestamps are in microseconds, and are the playback start time of the
+  // first sample in the buffer.
+  virtual void SetTimeStamp(uint64_t aTimeStamp) = 0;
+  virtual uint64_t TimeStamp() = 0;
+  virtual const uint8_t* Buffer() const = 0;
+  virtual uint8_t*       Buffer() = 0;
+
+  // Get data describing how this frame is encrypted, or nullptr if the
+  // buffer is not encrypted.
+  virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
+};
+
+#endif // GMP_AUDIO_FRAME_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-decryption.h
@@ -0,0 +1,208 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_DECRYPTION_h_
+#define GMP_DECRYPTION_h_
+
+#include "gmp-platform.h"
+
+class GMPEncryptedBufferData {
+public:
+  // Key ID to identify the decryption key.
+  virtual const uint8_t* KeyId() const = 0;
+
+  // Size (in bytes) of |KeyId()|.
+  virtual uint32_t KeyIdSize() const = 0;
+
+  // Initialization vector.
+  virtual const uint8_t* IV() const = 0;
+
+  // Size (in bytes) of |IV|.
+  virtual uint32_t IVSize() const = 0;
+
+  // Number of enties returned by ClearBytes and CipherBytes().
+  virtual uint32_t NumSubsamples() const = 0;
+
+  virtual const uint32_t* ClearBytes() const = 0;
+
+  virtual const uint32_t* CipherBytes() const = 0;
+};
+
+// These match to the DOMException codes as per:
+// http://www.w3.org/TR/dom/#domexception
+enum GMPDOMException {
+  kGMPNoModificationAllowedError = 7,
+  kGMPNotFoundError = 8,
+  kGMPNotSupportedError = 9,
+  kGMPInvalidStateError = 11,
+  kGMPSyntaxError = 12,
+  kGMPInvalidModificationError = 13,
+  kGMPInvalidAccessError = 15,
+  kGMPSecurityError = 18,
+  kGMPAbortError = 20,
+  kGMPQuotaExceededError = 22,
+  kGMPTimeoutError = 23
+};
+
+// Time in milliseconds, as offset from epoch, 1 Jan 1970.
+typedef int64_t GMPTimestamp;
+
+class GMPDecryptorCallback {
+public:
+  // Resolves a promise for a session created or loaded.
+  // Passes the session id to be exposed to JavaScript.
+  // Must be called before OnSessionMessage().
+  // aSessionId must be null terminated.
+  virtual void OnResolveNewSessionPromise(uint32_t aPromiseId,
+                                          const char* aSessionId,
+                                          uint32_t aSessionIdLength) = 0;
+
+  // Called to resolve a specified promise with "undefined".
+  virtual void OnResolvePromise(uint32_t aPromiseId) = 0;
+
+  // Called to reject a promise with a DOMException.
+  // aMessage is logged to the WebConsole.
+  // aMessage is optional, but if present must be null terminated.
+  virtual void OnRejectPromise(uint32_t aPromiseId,
+                               GMPDOMException aException,
+                               const char* aMessage,
+                               uint32_t aMessageLength) = 0;
+
+  // Called by the CDM when it has a message for session |session_id|.
+  // Length parameters should not include null termination.
+  // aSessionId must be null terminated.
+  virtual void OnSessionMessage(const char* aSessionId,
+                                uint32_t aSessionIdLength,
+                                const uint8_t* aMessage,
+                                uint32_t aMessageLength,
+                                const char* aDestinationURL,
+                                uint32_t aDestinationURLLength) = 0;
+
+  // aSessionId must be null terminated.
+   virtual void OnExpirationChange(const char* aSessionId,
+                                   uint32_t aSessionIdLength,
+                                   GMPTimestamp aExpiryTime) = 0;
+
+  // Called by the GMP when a session is closed. All file IO
+  // that a session requires should be complete before calling this.
+  // aSessionId must be null terminated.
+  virtual void OnSessionClosed(const char* aSessionId,
+                               uint32_t aSessionIdLength) = 0;
+
+  // Called by the GMP when an error occurs in a session.
+  // aSessionId must be null terminated.
+  // aMessage is logged to the WebConsole.
+  // aMessage is optional, but if present must be null terminated.
+  virtual void OnSessionError(const char* aSessionId,
+                              uint32_t aSessionIdLength,
+                              GMPDOMException aException,
+                              uint32_t aSystemCode,
+                              const char* aMessage,
+                              uint32_t aMessageLength) = 0;
+
+  virtual void OnKeyIdUsable(const char* aSessionId,
+                             uint32_t aSessionIdLength,
+                             const uint8_t* aKeyId,
+                             uint32_t aKeyIdLength) = 0;
+
+  // Marks a key as no longer usable.
+  // Note: Keys are assumed to be not usable when a session is closed or removed.
+  virtual void OnKeyIdNotUsable(const char* aSessionId,
+                                uint32_t aSessionIdLength,
+                                const uint8_t* aKeyId,
+                                uint32_t aKeyIdLength) = 0;
+
+};
+
+// Host interface, passed to GetAPIFunc(), with "decrypt".
+class GMPDecryptorHost {
+public:
+
+  // Returns an origin specific string uniquely identifying the device.
+  // The node id contains a random component, and is consistent between
+  // plugin instantiations, unless the user clears it.
+  // Different origins have different node ids.
+  // The node id pointer returned here remains valid for the until shutdown
+  // begins.
+  // *aOutNodeId is null terminated.
+  virtual void GetNodeId(const char** aOutNodeId,
+                         uint32_t* aOutNodeIdLength) = 0;
+
+  virtual void GetSandboxVoucher(const uint8_t** aVoucher,
+                                 uint8_t* aVoucherLength) = 0;
+
+  virtual void GetPluginVoucher(const uint8_t** aVoucher,
+                                uint8_t* aVoucherLength) = 0;
+};
+
+enum GMPSessionType {
+  kGMPTemporySession = 0,
+  kGMPPersistentSession = 1
+};
+
+// API exposed by plugin library to manage decryption sessions.
+// When the Host requests this by calling GMPGetAPIFunc().
+//
+// API name: "eme-decrypt".
+// Host API: GMPDecryptorHost
+class GMPDecryptor {
+public:
+
+  // Sets the callback to use with the decryptor to return results
+  // to Gecko.
+  virtual void Init(GMPDecryptorCallback* aCallback) = 0;
+
+  // Requests the creation of a session given |aType| and |aInitData|.
+  // Decryptor should callback GMPDecryptorCallback::OnSessionCreated()
+  // with the web session ID on success, or OnSessionError() on failure,
+  // and then call OnSessionReady() once all keys for that session are
+  // available.
+  virtual void CreateSession(uint32_t aPromiseId,
+                             const char* aInitDataType,
+                             uint32_t aInitDataTypeSize,
+                             const uint8_t* aInitData,
+                             uint32_t aInitDataSize,
+                             GMPSessionType aSessionType) = 0;
+
+  // Loads a previously loaded persistent session.
+  virtual void LoadSession(uint32_t aPromiseId,
+                           const char* aSessionId,
+                           uint32_t aSessionIdLength) = 0;
+
+  // Updates the session with |aResponse|.
+  virtual void UpdateSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdLength,
+                             const uint8_t* aResponse,
+                             uint32_t aResponseSize) = 0;
+
+  // Releases the resources (keys) for the specified session.
+  virtual void CloseSession(uint32_t aPromiseId,
+                            const char* aSessionId,
+                            uint32_t aSessionIdLength) = 0;
+
+  // Removes the resources (keys) for the specified session.
+  virtual void RemoveSession(uint32_t aPromiseId,
+                             const char* aSessionId,
+                             uint32_t aSessionIdLength) = 0;
+
+  // Resolve/reject promise on completion.
+  virtual void SetServerCertificate(uint32_t aPromiseId,
+                                    const uint8_t* aServerCert,
+                                    uint32_t aServerCertSize) = 0;
+};
+
+#endif // GMP_DECRYPTION_h_
--- a/content/media/gmp/gmp-api/gmp-errors.h
+++ b/content/media/gmp/gmp-api/gmp-errors.h
@@ -30,12 +30,21 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_ERRORS_h_
 #define GMP_ERRORS_h_
 
 typedef enum {
   GMPNoErr = 0,
-  GMPGenericErr = 1
+  GMPGenericErr = 1,
+  GMPClosedErr = 2,
+  GMPAllocErr = 3,
+  GMPNotImplementedErr = 4,
+  GMPNotClosedErr = 5,
+  GMPQuotaExceededErr = 6,
+  GMPLastErr // Placeholder, must be last. This enum's values must remain consecutive!
 } GMPErr;
 
+#define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
+#define GMP_FAILED(x) ((x) != GMPNoErr)
+
 #endif // GMP_ERRORS_h_
--- a/content/media/gmp/gmp-api/gmp-platform.h
+++ b/content/media/gmp/gmp-api/gmp-platform.h
@@ -29,22 +29,24 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_PLATFORM_h_
 #define GMP_PLATFORM_h_
 
 #include "gmp-errors.h"
+#include "gmp-storage.h"
 #include <stdint.h>
 
 /* Platform helper API. */
 
 class GMPTask {
 public:
+  virtual void Destroy() = 0;
   virtual ~GMPTask() {}
   virtual void Run() = 0;
 };
 
 class GMPThread {
 public:
   virtual ~GMPThread() {}
   virtual void Post(GMPTask* aTask) = 0;
@@ -53,27 +55,40 @@ public:
 
 class GMPMutex {
 public:
   virtual ~GMPMutex() {}
   virtual void Acquire() = 0;
   virtual void Release() = 0;
 };
 
+// Time is defined as the number of milliseconds since the
+// Epoch (00:00:00 UTC, January 1, 1970).
+typedef int64_t GMPTimestamp;
+
 typedef GMPErr (*GMPCreateThreadPtr)(GMPThread** aThread);
 typedef GMPErr (*GMPRunOnMainThreadPtr)(GMPTask* aTask);
 typedef GMPErr (*GMPSyncRunOnMainThreadPtr)(GMPTask* aTask);
 typedef GMPErr (*GMPCreateMutexPtr)(GMPMutex** aMutex);
+typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName,
+                                     uint32_t aRecordNameSize,
+                                     GMPRecord** aOutRecord,
+                                     GMPRecordClient* aClient);
+typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
+typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);
 
 struct GMPPlatformAPI {
   // Increment the version when things change. Can only add to the struct,
   // do not change what already exists. Pointers to functions may be NULL
   // when passed to plugins, but beware backwards compat implications of
   // doing that.
   uint16_t version; // Currently version 0
 
   GMPCreateThreadPtr createthread;
   GMPRunOnMainThreadPtr runonmainthread;
   GMPSyncRunOnMainThreadPtr syncrunonmainthread;
   GMPCreateMutexPtr createmutex;
+  GMPCreateRecordPtr createrecord;
+  GMPSetTimerOnMainThreadPtr settimer;
+  GMPGetCurrentTimePtr getcurrenttime;
 };
 
 #endif // GMP_PLATFORM_h_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/gmp-api/gmp-storage.h
@@ -0,0 +1,90 @@
+/*
+* Copyright 2013, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef GMP_STORAGE_h_
+#define GMP_STORAGE_h_
+
+#include "gmp-errors.h"
+#include <stdint.h>
+
+// Provides basic per-origin storage for CDMs. GMPRecord instances can be
+// retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecord
+// can be open at once. This interface is asynchronous, with results
+// being returned via callbacks to the GMPRecordClient pointer provided
+// to the GMPPlatformAPI->openstorage call, on the main thread.
+class GMPRecord {
+public:
+
+  // Opens the record. Calls OnOpenComplete() once the record is open.
+  // Note: OnReadComplete() is only called if this returns GMPNoErr.
+  virtual GMPErr Open() = 0;
+
+  // Reads the entire contents of the file, and calls
+  // GMPRecordClient::OnReadComplete() once the operation is complete.
+  // Note: OnReadComplete() is only called if this returns GMPNoErr.
+  virtual GMPErr Read() = 0;
+
+  // Writes aDataSize bytes of aData into the file, overwritting the contents
+  // of the file. Overwriting with 0 bytes "deletes" the file.
+  // Write 0 bytes to "delete" a file.
+  // Note: OnWriteComplete is only called if this returns GMPNoErr.
+  virtual GMPErr Write(const uint8_t* aData, uint32_t aDataSize) = 0;
+
+  // Closes a file. File must not be used after this is called. Cancels all
+  // callbacks.
+  virtual GMPErr Close() = 0;
+
+  virtual ~GMPRecord() {}
+};
+
+// Callback object that receives the results of GMPRecord calls. Callbacks
+// run asynchronously to the GMPRecord call, on the main thread.
+class GMPRecordClient {
+ public:
+
+  // Response to a GMPRecord::Open() call with the open |status|.
+  // aStatus values:
+  // - GMPNoErr - File opened successfully. File may be empty.
+  // - GMPFileInUse - There file is in use by another client.
+  // - GMPGenericErr - Unspecified error.
+  // Do not use the GMPRecord if aStatus is not GMPNoErr.
+  virtual void OnOpenComplete(GMPErr aStatus) = 0;
+
+  // Response to a GMPRecord::Read() call, where aData is the file contents,
+  // of length aDataSize.
+  // aData is only valid for the duration of the call to OnReadComplete.
+  // Copy it if you want to hang onto it!
+  // aStatus values:
+  // - GMPNoErr - File contents read successfully, aDataSize 0 means file
+  //   is empty.
+  // - GMPFileInUse - There are other operations or clients in use on this file.
+  // - GMPGenericErr - Unspecified error.
+  // Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
+  virtual void OnReadComplete(GMPErr aStatus,
+                              const uint8_t* aData,
+                              uint32_t aDataSize) = 0;
+
+  // Response to a GMPRecord::Write() call.
+  // - GMPNoErr - File contents written successfully.
+  // - GMPFileInUse - There are other operations or clients in use on this file.
+  // - GMPGenericErr - Unspecified error. File should be regarded as corrupt.
+  // Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
+  virtual void OnWriteComplete(GMPErr aStatus) = 0;
+
+  virtual ~GMPRecordClient() {}
+};
+
+#endif // GMP_STORAGE_h_
--- a/content/media/gmp/gmp-api/gmp-video-codec.h
+++ b/content/media/gmp/gmp-api/gmp-video-codec.h
@@ -67,83 +67,103 @@ struct GMPVideoCodecVP8
   bool mPictureLossIndicationOn;
   bool mFeedbackModeOn;
   GMPVideoCodecComplexity mComplexity;
   GMPVP8ResilienceMode mResilience;
   uint32_t mNumberOfTemporalLayers;
   bool mDenoisingOn;
   bool mErrorConcealmentOn;
   bool mAutomaticResizeOn;
-  bool mFrameDroppingOn;
-  int32_t mKeyFrameInterval;
 };
 
 // H264 specific
-struct GMPVideoCodecH264
+
+// Needs to match a binary spec for this structure.
+// Note: the mSPS at the end of this structure is variable length.
+struct GMPVideoCodecH264AVCC
 {
-  uint8_t        mProfile;
+  uint8_t        mVersion; // == 0x01
+  uint8_t        mProfile; // these 3 are profile_level_id
   uint8_t        mConstraints;
   uint8_t        mLevel;
+  uint8_t        mLengthSizeMinusOne; // lower 2 bits (== GMPBufferType-1). Top 6 reserved (1's)
+
+  // SPS/PPS will not generally be present for interactive use unless SDP
+  // parameter-sets are used.
+  uint8_t        mNumSPS; // lower 5 bits; top 5 reserved (1's)
+
+  /*** uint8_t   mSPS[];  (Not defined due to compiler warnings and warnings-as-errors ...) **/
+  // Following mNumSPS is a variable number of bytes, which is the SPS and PPS.
+  // Each SPS == 16 bit size, ("N"), then "N" bytes,
+  // then uint8_t mNumPPS, then each PPS == 16 bit size ("N"), then "N" bytes.
+};
+
+// Codec specific data for H.264 decoding/encoding.
+// Cast the "aCodecSpecific" parameter of GMPVideoDecoder::InitDecode() and
+// GMPVideoEncoder::InitEncode() to this structure.
+struct GMPVideoCodecH264
+{
   uint8_t        mPacketizationMode; // 0 or 1
-  bool           mFrameDroppingOn;
-  int32_t        mKeyFrameInterval;
-  // These are null/0 if not externally negotiated
-  const uint8_t* mSPSData;
-  size_t         mSPSLen;
-  const uint8_t* mPPSData;
-  size_t         mPPSLen;
+  struct GMPVideoCodecH264AVCC mAVCC; // holds a variable-sized struct GMPVideoCodecH264AVCC mAVCC;
 };
 
 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,
   kGMPVideoCodecInvalid // Should always be last.
 };
 
-union GMPVideoCodecUnion
-{
-  GMPVideoCodecVP8 mVP8;
-  GMPVideoCodecH264 mH264;
-};
-
 // Simulcast is when the same stream is encoded multiple times with different
 // settings such as resolution.
 struct GMPSimulcastStream
 {
   uint32_t mWidth;
   uint32_t mHeight;
   uint32_t mNumberOfTemporalLayers;
   uint32_t mMaxBitrate; // kilobits/sec.
   uint32_t mTargetBitrate; // kilobits/sec.
   uint32_t mMinBitrate; // kilobits/sec.
   uint32_t mQPMax; // minimum quality
 };
 
 enum GMPVideoCodecMode {
   kGMPRealtimeVideo,
   kGMPScreensharing,
+  kGMPStreamingVideo,
   kGMPCodecModeInvalid // Should always be last.
 };
 
+enum GMPApiVersion {
+  kGMPVersion32 = 1, // leveraging that V32 had mCodecType first, and only supported H264
+  kGMPVersion33 = 33,
+};
+
 struct GMPVideoCodec
 {
+  uint32_t mGMPApiVersion;
+
   GMPVideoCodecType mCodecType;
   char mPLName[kGMPPayloadNameSize]; // Must be NULL-terminated!
   uint32_t mPLType;
 
   uint32_t mWidth;
   uint32_t mHeight;
 
   uint32_t mStartBitrate; // kilobits/sec.
   uint32_t mMaxBitrate; // kilobits/sec.
   uint32_t mMinBitrate; // kilobits/sec.
   uint32_t mMaxFramerate;
 
-  GMPVideoCodecUnion mCodecSpecific;
+  bool mFrameDroppingOn;
+  int32_t mKeyFrameInterval;
 
   uint32_t mQPMax;
   uint32_t mNumberOfSimulcastStreams;
   GMPSimulcastStream mSimulcastStream[kGMPMaxSimulcastStreams];
 
   GMPVideoCodecMode mMode;
 };
 
@@ -152,16 +172,17 @@ struct GMPVideoCodec
 // entry; one should check the overall end-of-buffer against where the next
 // length would be.
 enum GMPBufferType {
   GMP_BufferSingle = 0,
   GMP_BufferLength8,
   GMP_BufferLength16,
   GMP_BufferLength24,
   GMP_BufferLength32,
+  GMP_BufferInvalid,
 };
 
 struct GMPCodecSpecificInfoGeneric {
   uint8_t mSimulcastIdx;
 };
 
 struct GMPCodecSpecificInfoH264 {
   uint8_t mSimulcastIdx;
@@ -183,16 +204,17 @@ struct GMPCodecSpecificInfoVP8
   int32_t mTL0PicIdx; // negative value to skip tl0PicIdx
   int8_t mKeyIdx; // negative value to skip keyIdx
 };
 
 union GMPCodecSpecificInfoUnion
 {
   GMPCodecSpecificInfoGeneric mGeneric;
   GMPCodecSpecificInfoVP8 mVP8;
+  GMPCodecSpecificInfoH264 mH264;
 };
 
 // Note: if any pointers are added to this struct or its sub-structs, it
 // must be fitted with a copy-constructor. This is because it is copied
 // in the copy-constructor of VCMEncodedFrame.
 struct GMPCodecSpecificInfo
 {
   GMPVideoCodecType mCodecType;
--- a/content/media/gmp/gmp-api/gmp-video-decode.h
+++ b/content/media/gmp/gmp-api/gmp-video-decode.h
@@ -29,72 +29,84 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_DECODE_h_
 #define GMP_VIDEO_DECODE_h_
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 #include "gmp-video-codec.h"
 #include <stdint.h>
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
-class GMPDecoderCallback
+class GMPVideoDecoderCallback
 {
 public:
-  virtual ~GMPDecoderCallback() {}
+  virtual ~GMPVideoDecoderCallback() {}
 
   virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) = 0;
 
   virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) = 0;
 
   virtual void ReceivedDecodedFrame(const uint64_t aPictureId) = 0;
 
   virtual void InputDataExhausted() = 0;
+
+  virtual void DrainComplete() = 0;
+
+  virtual void ResetComplete() = 0;
 };
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
 class GMPVideoDecoder
 {
 public:
   virtual ~GMPVideoDecoder() {}
 
   // aCallback: Subclass should retain reference to it until DecodingComplete
   //            is called. Do not attempt to delete it, host retains ownership.
-  virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
-                                 GMPDecoderCallback* aCallback,
-                                 int32_t aCoreCount) = 0;
+  virtual GMPErr InitDecode(const GMPVideoCodec& aCodecSettings,
+                            const uint8_t* aCodecSpecific,
+                            uint32_t aCodecSpecificLength,
+                            GMPVideoDecoderCallback* aCallback,
+                            int32_t aCoreCount) = 0;
 
   // Decode encoded frame (as a part of a video stream). The decoded frame
   // will be returned to the user through the decode complete callback.
   //
   // inputFrame:        Frame to decode.
   //
   // missingFrames:     True if one or more frames have been lost since the previous decode call.
   //
   // fragmentation:     Specifies where the encoded frame can be split into separate fragments.
   //                    The meaning of fragment is codec specific, but often means that each
   //                    fragment is decodable by itself.
   //
   // codecSpecificInfo: Codec-specific data
   //
   // renderTimeMs :     System time to render in milliseconds. Only used by decoders with internal
   //                    rendering.
-  virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
-                             bool aMissingFrames,
-                             const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                             int64_t aRenderTimeMs = -1) = 0;
+  virtual GMPErr Decode(GMPVideoEncodedFrame* aInputFrame,
+                        bool aMissingFrames,
+                        const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                        int64_t aRenderTimeMs = -1) = 0;
 
-  // Reset decoder state and prepare for a new call to Decode(...). Flushes the decoder pipeline.
-  virtual GMPVideoErr Reset() = 0;
+  // Reset decoder state and prepare for a new call to Decode(...).
+  // Flushes the decoder pipeline.
+  // The decoder should enqueue a task to run ResetComplete() on the main
+  // thread once the reset has finished.
+  virtual GMPErr Reset() = 0;
 
   // Output decoded frames for any data in the pipeline, regardless of ordering.
-  virtual GMPVideoErr Drain() = 0;
+  // All remaining decoded frames should be immediately returned via callback.
+  // The decoder should enqueue a task to run DrainComplete() on the main
+  // thread once the reset has finished.
+  virtual GMPErr Drain() = 0;
 
   // May free decoder memory.
   virtual void DecodingComplete() = 0;
 };
 
 #endif // GMP_VIDEO_DECODE_h_
--- a/content/media/gmp/gmp-api/gmp-video-encode.h
+++ b/content/media/gmp/gmp-api/gmp-video-encode.h
@@ -32,79 +32,85 @@
  */
 
 #ifndef GMP_VIDEO_ENCODE_h_
 #define GMP_VIDEO_ENCODE_h_
 
 #include <vector>
 #include <stdint.h>
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 #include "gmp-video-codec.h"
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
-class GMPEncoderCallback
+class GMPVideoEncoderCallback
 {
 public:
-  virtual ~GMPEncoderCallback() {}
+  virtual ~GMPVideoEncoderCallback() {}
 
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const GMPCodecSpecificInfo& aCodecSpecificInfo) = 0;
 };
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
 class GMPVideoEncoder
 {
 public:
   virtual ~GMPVideoEncoder() {}
 
   // Initialize the encoder with the information from the VideoCodec.
   //
   // Input:
   // - codecSettings : Codec settings
+  // - aCodecSpecific : codec specific data
+  // - aCodecSpecificLength : number of bytes in aCodecSpecific
   // - aCallback: Subclass should retain reference to it until EncodingComplete
   //              is called. Do not attempt to delete it, host retains ownership.
-  // - numberOfCores : Number of cores available for the encoder
-  // - maxPayloadSize : The maximum size each payload is allowed
+  // - aNnumberOfCores : Number of cores available for the encoder
+  // - aMaxPayloadSize : The maximum size each payload is allowed
   //                    to have. Usually MTU - overhead.
-  virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
-                                 GMPEncoderCallback* aCallback,
-                                 int32_t aNumberOfCores,
-                                 uint32_t aMaxPayloadSize) = 0;
+  virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
+                            const uint8_t* aCodecSpecific,
+                            uint32_t aCodecSpecificLength,
+                            GMPVideoEncoderCallback* aCallback,
+                            int32_t aNumberOfCores,
+                            uint32_t aMaxPayloadSize) = 0;
 
   // Encode an I420 frame (as a part of a video stream). The encoded frame
   // will be returned to the user through the encode complete callback.
   //
   // Input:
-  // - inputFrame : Frame to be encoded
-  // - codecSpecificInfo : Pointer to codec specific data
-  // - frame_types : The frame type to encode
-  virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
-                             const GMPCodecSpecificInfo& aCodecSpecificInfo,
-                             const std::vector<GMPVideoFrameType>& aFrameTypes) = 0;
+  // - aInputFrame : Frame to be encoded
+  // - aCodecSpecificInfo : Pointer to codec specific data
+  // - aFrameTypes : The frame type to encode
+  // - aFrameTypesLength : The number of elements in aFrameTypes array.
+  virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
+                        const GMPCodecSpecificInfo& aCodecSpecificInfo,
+                        const GMPVideoFrameType* aFrameTypes,
+                        uint32_t aFrameTypesLength) = 0;
 
   // Inform the encoder about the packet loss and round trip time on the
   // network used to decide the best pattern and signaling.
   //
   // - packetLoss : Fraction lost (loss rate in percent =
   // 100 * packetLoss / 255)
   // - rtt : Round-trip time in milliseconds
-  virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
+  virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
 
   // Inform the encoder about the new target bit rate.
   //
   // - newBitRate : New target bit rate
   // - frameRate : The target frame rate
-  virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
+  virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
 
   // Use this function to enable or disable periodic key frames. Can be useful for codecs
   // which have other ways of stopping error propagation.
   //
   // - enable : Enable or disable periodic key frames
-  virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) = 0;
+  virtual GMPErr SetPeriodicKeyFrames(bool aEnable) = 0;
 
   // May free Encoder memory.
   virtual void EncodingComplete() = 0;
 };
 
 #endif // GMP_VIDEO_ENCODE_h_
deleted file mode 100644
--- a/content/media/gmp/gmp-api/gmp-video-errors.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* Copyright (c) 2011, The WebRTC project authors. All rights reserved.
- * Copyright (c) 2014, Mozilla
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- ** Redistributions of source code must retain the above copyright
- *  notice, this list of conditions and the following disclaimer.
- *
- ** Redistributions in binary form must reproduce the above copyright
- *  notice, this list of conditions and the following disclaimer in
- *  the documentation and/or other materials provided with the
- *  distribution.
- *
- ** Neither the name of Google nor the names of its contributors may
- *  be used to endorse or promote products derived from this software
- *  without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef GMP_VIDEO_ERRORS_h_
-#define GMP_VIDEO_ERRORS_h_
-
-enum GMPVideoErr {
-  GMPVideoNoErr = 0,
-  GMPVideoGenericErr = 1,
-  GMPVideoAllocErr = 2
-};
-
-#endif // GMP_VIDEO_ERRORS_h_
--- a/content/media/gmp/gmp-api/gmp-video-frame-encoded.h
+++ b/content/media/gmp/gmp-api/gmp-video-frame-encoded.h
@@ -30,16 +30,18 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_FRAME_ENCODED_h_
 #define GMP_VIDEO_FRAME_ENCODED_h_
 
 #include <stdint.h>
+#include "gmp-decryption.h"
+#include "gmp-video-frame.h"
 
 enum GMPVideoFrameType
 {
   kGMPKeyFrame = 0,
   kGMPDeltaFrame = 1,
   kGMPGoldenFrame = 2,
   kGMPAltRefFrame = 3,
   kGMPSkipFrame = 4
@@ -53,32 +55,40 @@ enum GMPVideoFrameType
 // access the underlying buffer(s).
 //
 // Methods that create or destroy shared memory must be called on the main
 // thread. They are marked below.
 class GMPVideoEncodedFrame : public GMPVideoFrame
 {
 public:
   // MAIN THREAD ONLY
-  virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) = 0;
+  virtual GMPErr CreateEmptyFrame(uint32_t aSize) = 0;
   // MAIN THREAD ONLY
-  virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aVideoFrame) = 0;
+  virtual GMPErr CopyFrame(const GMPVideoEncodedFrame& aVideoFrame) = 0;
   virtual void     SetEncodedWidth(uint32_t aEncodedWidth) = 0;
   virtual uint32_t EncodedWidth() = 0;
   virtual void     SetEncodedHeight(uint32_t aEncodedHeight) = 0;
   virtual uint32_t EncodedHeight() = 0;
-  virtual void     SetTimeStamp(uint32_t aTimeStamp) = 0;
-  virtual uint32_t TimeStamp() = 0;
-  virtual void     SetCaptureTime(int64_t aCaptureTime) = 0;
-  virtual int64_t  CaptureTime() = 0;
+  // Microseconds
+  virtual void     SetTimeStamp(uint64_t aTimeStamp) = 0;
+  virtual uint64_t TimeStamp() = 0;
+  // Set frame duration (microseconds)
+  // NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
+  // depending on rounding to avoid having to track roundoff errors
+  // and dropped/missing frames(!) (which may leave a large gap)
+  virtual void     SetDuration(uint64_t aDuration) = 0;
+  virtual uint64_t Duration() const = 0;
   virtual void     SetFrameType(GMPVideoFrameType aFrameType) = 0;
   virtual GMPVideoFrameType FrameType() = 0;
   virtual void     SetAllocatedSize(uint32_t aNewSize) = 0;
   virtual uint32_t AllocatedSize() = 0;
   virtual void     SetSize(uint32_t aSize) = 0;
   virtual uint32_t Size() = 0;
   virtual void     SetCompleteFrame(bool aCompleteFrame) = 0;
   virtual bool     CompleteFrame() = 0;
   virtual const uint8_t* Buffer() const = 0;
   virtual uint8_t*       Buffer() = 0;
+  // Get data describing how this frame is encrypted, or nullptr if the
+  // frame is not encrypted.
+  virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
 };
 
 #endif // GMP_VIDEO_FRAME_ENCODED_h_
--- a/content/media/gmp/gmp-api/gmp-video-frame-i420.h
+++ b/content/media/gmp/gmp-api/gmp-video-frame-i420.h
@@ -29,17 +29,17 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_FRAME_I420_h_
 #define GMP_VIDEO_FRAME_I420_h_
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include "gmp-video-frame.h"
 #include "gmp-video-plane.h"
 
 #include <stdint.h>
 
 enum GMPPlaneType {
   kGMPYPlane = 0,
   kGMPUPlane = 1,
@@ -58,32 +58,32 @@ enum GMPPlaneType {
 // thread. They are marked below.
 class GMPVideoi420Frame : public GMPVideoFrame {
 public:
   // MAIN THREAD ONLY
   // CreateEmptyFrame: Sets frame dimensions and allocates buffers based
   // on set dimensions - height and plane stride.
   // If required size is bigger than the allocated one, new buffers of adequate
   // size will be allocated.
-  virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
-                                       int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
+  virtual GMPErr CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
+                                  int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
 
   // MAIN THREAD ONLY
   // CreateFrame: Sets the frame's members and buffers. If required size is
   // bigger than allocated one, new buffers of adequate size will be allocated.
-  virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
-                                  int32_t aSize_u, const uint8_t* aBuffer_u,
-                                  int32_t aSize_v, const uint8_t* aBuffer_v,
-                                  int32_t aWidth, int32_t aHeight,
-                                  int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
+  virtual GMPErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
+                             int32_t aSize_u, const uint8_t* aBuffer_u,
+                             int32_t aSize_v, const uint8_t* aBuffer_v,
+                             int32_t aWidth, int32_t aHeight,
+                             int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) = 0;
 
   // MAIN THREAD ONLY
   // Copy frame: If required size is bigger than allocated one, new buffers of
   // adequate size will be allocated.
-  virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aVideoFrame) = 0;
+  virtual GMPErr CopyFrame(const GMPVideoi420Frame& aVideoFrame) = 0;
 
   // Swap Frame.
   virtual void SwapFrame(GMPVideoi420Frame* aVideoFrame) = 0;
 
   // Get pointer to buffer per plane.
   virtual uint8_t* Buffer(GMPPlaneType aType) = 0;
 
   // Overloading with const.
@@ -91,38 +91,41 @@ public:
 
   // Get allocated size per plane.
   virtual int32_t AllocatedSize(GMPPlaneType aType) const = 0;
 
   // Get allocated stride per plane.
   virtual int32_t Stride(GMPPlaneType aType) const = 0;
 
   // Set frame width.
-  virtual GMPVideoErr SetWidth(int32_t aWidth) = 0;
+  virtual GMPErr SetWidth(int32_t aWidth) = 0;
 
   // Set frame height.
-  virtual GMPVideoErr SetHeight(int32_t aHeight) = 0;
+  virtual GMPErr SetHeight(int32_t aHeight) = 0;
 
   // Get frame width.
   virtual int32_t Width() const = 0;
 
   // Get frame height.
   virtual int32_t Height() const = 0;
 
-  // Set frame timestamp (90kHz).
-  virtual void SetTimestamp(uint32_t aTimestamp) = 0;
+  // Set frame timestamp (microseconds)
+  virtual void SetTimestamp(uint64_t aTimestamp) = 0;
 
-  // Get frame timestamp (90kHz).
-  virtual uint32_t Timestamp() const = 0;
+  // Get frame timestamp (microseconds)
+  virtual uint64_t Timestamp() const = 0;
 
-  // Set render time in miliseconds.
-  virtual void SetRenderTime_ms(int64_t aRenderTime_ms) = 0;
+  // Set frame duration (microseconds)
+  // NOTE: next-frame's Timestamp() != this-frame's TimeStamp()+Duration()
+  // depending on rounding to avoid having to track roundoff errors
+  // and dropped/missing frames(!) (which may leave a large gap)
+  virtual void SetDuration(uint64_t aDuration) = 0;
 
-  // Get render time in miliseconds.
-  virtual int64_t RenderTime_ms() const = 0;
+  // Get frame duration (microseconds)
+  virtual uint64_t Duration() const = 0;
 
   // Return true if underlying plane buffers are of zero size, false if not.
   virtual bool IsZeroSize() const = 0;
 
   // Reset underlying plane buffers sizes to 0. This function doesn't clear memory.
   virtual void ResetSize() = 0;
 };
 
--- a/content/media/gmp/gmp-api/gmp-video-frame.h
+++ b/content/media/gmp/gmp-api/gmp-video-frame.h
@@ -29,17 +29,16 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_FRAME_h_
 #define GMP_VIDEO_FRAME_h_
 
-#include "gmp-video-errors.h"
 #include "gmp-video-plane.h"
 
 enum GMPVideoFrameFormat {
   kGMPEncodedVideoFrame = 0,
   kGMPI420VideoFrame = 1
 };
 
 class GMPVideoFrame {
--- a/content/media/gmp/gmp-api/gmp-video-host.h
+++ b/content/media/gmp/gmp-api/gmp-video-host.h
@@ -29,23 +29,23 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_HOST_h_
 #define GMP_VIDEO_HOST_h_
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 #include "gmp-video-codec.h"
 
 class GMPVideoHost
 {
 public:
   // Construct various video API objects. Host does not retain reference,
   // caller is owner and responsible for deleting.
-  virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) = 0;
-  virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) = 0;
+  virtual GMPErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) = 0;
+  virtual GMPErr CreatePlane(GMPPlane** aPlane) = 0;
 };
 
 #endif // GMP_VIDEO_HOST_h_
--- a/content/media/gmp/gmp-api/gmp-video-plane.h
+++ b/content/media/gmp/gmp-api/gmp-video-plane.h
@@ -29,17 +29,17 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef GMP_VIDEO_PLANE_h_
 #define GMP_VIDEO_PLANE_h_
 
-#include "gmp-video-errors.h"
+#include "gmp-errors.h"
 #include <stdint.h>
 
 // The implementation backing this interface uses shared memory for the
 // buffer(s). This means it can only be used by the "owning" process.
 // At first the process which created the object owns it. When the object
 // is passed to an interface the creator loses ownership and must Destroy()
 // the object. Further attempts to use it may fail due to not being able to
 // access the underlying buffer(s).
@@ -47,28 +47,28 @@
 // Methods that create or destroy shared memory must be called on the main
 // thread. They are marked below.
 class GMPPlane {
 public:
   // MAIN THREAD ONLY
   // CreateEmptyPlane - set allocated size, actual plane size and stride:
   // If current size is smaller than current size, then a buffer of sufficient
   // size will be allocated.
-  virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
-                                       int32_t aStride,
-                                       int32_t aPlaneSize) = 0;
+  virtual GMPErr CreateEmptyPlane(int32_t aAllocatedSize,
+                                  int32_t aStride,
+                                  int32_t aPlaneSize) = 0;
 
   // MAIN THREAD ONLY
   // Copy the entire plane data.
-  virtual GMPVideoErr Copy(const GMPPlane& aPlane) = 0;
+  virtual GMPErr Copy(const GMPPlane& aPlane) = 0;
 
   // MAIN THREAD ONLY
   // Copy buffer: If current size is smaller
   // than current size, then a buffer of sufficient size will be allocated.
-  virtual GMPVideoErr Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer) = 0;
+  virtual GMPErr Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer) = 0;
 
   // Swap plane data.
   virtual void Swap(GMPPlane& aPlane) = 0;
 
   // Get allocated size.
   virtual int32_t AllocatedSize() const = 0;
 
   // Set actual size.
--- a/content/media/gmp/moz.build
+++ b/content/media/gmp/moz.build
@@ -6,41 +6,49 @@
 
 XPIDL_MODULE = 'content_geckomediaplugins'
 
 XPIDL_SOURCES += [
     'mozIGeckoMediaPluginService.idl',
 ]
 
 EXPORTS += [
+    'gmp-api/gmp-async-shutdown.h',
+    'gmp-api/gmp-audio-codec.h',
+    'gmp-api/gmp-audio-decode.h',
+    'gmp-api/gmp-audio-host.h',
+    'gmp-api/gmp-audio-samples.h',
+    'gmp-api/gmp-decryption.h',
     'gmp-api/gmp-entrypoints.h',
     'gmp-api/gmp-errors.h',
     'gmp-api/gmp-platform.h',
+    'gmp-api/gmp-storage.h',
     'gmp-api/gmp-video-codec.h',
     'gmp-api/gmp-video-decode.h',
     'gmp-api/gmp-video-encode.h',
-    'gmp-api/gmp-video-errors.h',
     'gmp-api/gmp-video-frame-encoded.h',
     'gmp-api/gmp-video-frame-i420.h',
     'gmp-api/gmp-video-frame.h',
     'gmp-api/gmp-video-host.h',
     'gmp-api/gmp-video-plane.h',
     'GMPChild.h',
     'GMPMessageUtils.h',
     'GMPParent.h',
     'GMPPlatform.h',
     'GMPProcessChild.h',
     'GMPProcessParent.h',
     'GMPService.h',
     'GMPSharedMemManager.h',
     'GMPVideoDecoderChild.h',
     'GMPVideoDecoderParent.h',
+    'GMPVideoDecoderProxy.h',
     'GMPVideoEncodedFrameImpl.h',
     'GMPVideoEncoderChild.h',
     'GMPVideoEncoderParent.h',
+    'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
 ]
 
 UNIFIED_SOURCES += [
     'GMPChild.cpp',
     'GMPParent.cpp',
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -5,56 +5,56 @@
 
 #include "nsISupports.idl"
 #include "nsIThread.idl"
 #include "nsIPrincipal.idl"
 
 %{C++
 #include "nsTArray.h"
 #include "nsStringGlue.h"
-class GMPVideoDecoder;
-class GMPVideoEncoder;
+class GMPVideoDecoderProxy;
+class GMPVideoEncoderProxy;
 class GMPVideoHost;
 %}
 
-[ptr] native GMPVideoDecoder(GMPVideoDecoder);
-[ptr] native GMPVideoEncoder(GMPVideoEncoder);
+[ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
+[ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 
-[scriptable, uuid(63fc797f-9d01-43f4-8b93-5b1fe713c2f8)]
+[scriptable, uuid(7cef50ca-7a0f-41f2-9560-47abf709f0d7)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
    * Get a video 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.
    */
   [noscript]
-  GMPVideoDecoder getGMPVideoDecoder(in TagArray tags,
-                                     [optional] in AString origin,
-                                     out GMPVideoHost outVideoHost);
+  GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
+                                          [optional] in AString origin,
+                                          out GMPVideoHost outVideoHost);
 
   /**
    * 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.
    */
   [noscript]
-  GMPVideoEncoder getGMPVideoEncoder(in TagArray tags,
-                                     [optional] in AString origin,
-                                     out GMPVideoHost outVideoHost);
+  GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
+		                                      [optional] in AString origin,
+		                                      out GMPVideoHost outVideoHost);
 
   /**
    * Add a directory to scan for gecko media plugins.
    * @note Main-thread API.
    */
   void addPluginDirectory(in AString directory);
 
   /**
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -9,25 +9,47 @@
 
 #include "mozilla/Scoped.h"
 #include "VideoConduit.h"
 #include "AudioConduit.h"
 #include "runnable_utils.h"
 
 #include "mozIGeckoMediaPluginService.h"
 #include "nsServiceManagerUtils.h"
+#include "GMPVideoDecoderProxy.h"
+#include "GMPVideoEncoderProxy.h"
 
 #include "gmp-video-host.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 
 #include "webrtc/video_engine/include/vie_external_codec.h"
 
 namespace mozilla {
 
+#ifdef LOG
+#undef LOG
+#endif
+
+#ifdef PR_LOGGING
+PRLogModuleInfo*
+GetGMPLog()
+{
+  static PRLogModuleInfo *sLog;
+  if (!sLog)
+    sLog = PR_NewLogModule("GMP");
+  return sLog;
+}
+#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
+#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
+#else
+#define LOGD(msg)
+#define LOG(leve, msg)
+#endif
+
 // Encoder.
 WebrtcGmpVideoEncoder::WebrtcGmpVideoEncoder()
   : mGMPThread(nullptr)
   , mGMP(nullptr)
   , mHost(nullptr)
   , mCallback(nullptr)
 {}
 
@@ -116,17 +138,17 @@ WebrtcGmpVideoEncoder::InitEncode(const 
 }
 
 int32_t
 WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores,
                                     uint32_t aMaxPayloadSize)
 {
   GMPVideoHost* host = nullptr;
-  GMPVideoEncoder* gmp = nullptr;
+  GMPVideoEncoderProxy* gmp = nullptr;
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
   nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
                                          NS_LITERAL_STRING(""),
                                          &host,
                                          &gmp);
   if (NS_FAILED(rv)) {
@@ -139,25 +161,30 @@ WebrtcGmpVideoEncoder::InitEncode_g(cons
   if (!gmp || !host) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   // Bug XXXXXX: transfer settings from codecSettings to codec.
   GMPVideoCodec codec;
   memset(&codec, 0, sizeof(codec));
 
+  codec.mGMPApiVersion = 33;
   codec.mWidth = aCodecSettings->width;
   codec.mHeight = aCodecSettings->height;
   codec.mStartBitrate = aCodecSettings->startBitrate;
   codec.mMinBitrate = aCodecSettings->minBitrate;
   codec.mMaxBitrate = aCodecSettings->maxBitrate;
   codec.mMaxFramerate = aCodecSettings->maxFramerate;
 
-  GMPVideoErr err = mGMP->InitEncode(codec, this, 1, aMaxPayloadSize);
-  if (err != GMPVideoNoErr) {
+  // Pass dummy codecSpecific data for now...
+  nsTArray<uint8_t> codecSpecific;
+ 
+  // H.264 mode 1 only supported so far
+  GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, 256000 /*aMaxPayloadSize*/);
+  if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 
 int32_t
@@ -183,57 +210,59 @@ int32_t
 WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
                                 const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
                                 const std::vector<webrtc::VideoFrameType>* aFrameTypes)
 {
   MOZ_ASSERT(mHost);
   MOZ_ASSERT(mGMP);
 
   GMPVideoFrame* ftmp = nullptr;
-  GMPVideoErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp);
+  if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
   GMPVideoi420Frame* frame = static_cast<GMPVideoi420Frame*>(ftmp);
 
   err = frame->CreateFrame(aInputImage->allocated_size(webrtc::kYPlane),
                            aInputImage->buffer(webrtc::kYPlane),
                            aInputImage->allocated_size(webrtc::kUPlane),
                            aInputImage->buffer(webrtc::kUPlane),
                            aInputImage->allocated_size(webrtc::kVPlane),
                            aInputImage->buffer(webrtc::kVPlane),
                            aInputImage->width(),
                            aInputImage->height(),
                            aInputImage->stride(webrtc::kYPlane),
                            aInputImage->stride(webrtc::kUPlane),
                            aInputImage->stride(webrtc::kVPlane));
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
-  frame->SetTimestamp(aInputImage->timestamp());
-  frame->SetRenderTime_ms(aInputImage->render_time_ms());
+  frame->SetTimestamp((aInputImage->timestamp() * 1000ll)/90); // note: rounds down!
+  //frame->SetDuration(1000000ll/30); // XXX base duration on measured current FPS - or don't bother
 
   // Bug XXXXXX: Set codecSpecific info
   GMPCodecSpecificInfo info;
   memset(&info, 0, sizeof(info));
+  info.mCodecType = kGMPVideoCodecH264;
 
-  std::vector<GMPVideoFrameType> gmp_frame_types;
+  nsTArray<GMPVideoFrameType> gmp_frame_types;
   for (auto it = aFrameTypes->begin(); it != aFrameTypes->end(); ++it) {
     GMPVideoFrameType ft;
 
     int32_t ret = WebrtcFrameTypeToGmpFrameType(*it, &ft);
     if (ret != WEBRTC_VIDEO_CODEC_OK) {
       return ret;
     }
 
-    gmp_frame_types.push_back(ft);
+    gmp_frame_types.AppendElement(ft);
   }
 
+  LOGD(("GMP Encode: %llu", (aInputImage->timestamp() * 1000ll)/90));
   err = mGMP->Encode(frame, info, gmp_frame_types);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return err;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 
 
@@ -270,114 +299,37 @@ WebrtcGmpVideoEncoder::SetRates(uint32_t
 
   return ret;
 }
 
 int32_t
 WebrtcGmpVideoEncoder::SetRates_g(uint32_t aNewBitRate, uint32_t aFrameRate)
 {
   MOZ_ASSERT(mGMP);
-  GMPVideoErr err = mGMP->SetRates(aNewBitRate, aFrameRate);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mGMP->SetRates(aNewBitRate, aFrameRate);
+  if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
-#define GMP_ENCODE_HAS_START_CODES 1
-#ifdef GMP_ENCODE_HAS_START_CODES
-// Temporary until inside-sandbox-code switches from start codes to the API here
-static int GetNextNALUnit(const uint8_t **aData,
-                          const uint8_t *aEnd, // at first byte past end
-                          size_t *aNalSize)
-{
-  const uint8_t *data = *aData;
-  uint8_t zeros = 0;
-
-  MOZ_ASSERT(data);
-  // Don't assume we start with a start code (paranoia)
-  while (data < aEnd) {
-    if (*data == 0) {
-      zeros++;
-      if (zeros > 3) {
-        // internal format error; keep going anyways
-        zeros = 3;
-      }
-    } else {
-      if (*data == 0x01) {
-        if (zeros >= 2) {
-          // Found start code 0x000001 or 0x00000001
-          MOZ_ASSERT(zeros == 3); // current temp code only handles 4-byte codes
-          // now find the length of the NAL
-          *aData = ++data; // start of actual data
-
-          while (data < aEnd) {
-            if (*data == 0) {
-              zeros++;
-              if (zeros > 3) {
-                // internal format error; keep going anyways
-                zeros = 3;
-              }
-            } else {
-              if (*data == 0x01) {
-                if (zeros >= 2) {
-                  // Found start code 0x000001 or 0x00000001
-                  *aNalSize = (data - *aData) - zeros;
-                  return 0;
-                }
-              }
-              zeros = 0;
-            }
-            data++;
-          }
-          // NAL ends at the end of the buffer
-          *aNalSize = (data - *aData);
-          return 0;
-        }
-      }
-      zeros = 0;
-    }
-    data++;
-  }
-  return -1; // no nals
-}
-
-#endif
-
-// GMPEncoderCallback virtual functions.
+// GMPVideoEncoderCallback virtual functions.
 void
 WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                                const GMPCodecSpecificInfo& aCodecSpecificInfo)
 {
   if (mCallback) { // paranoia
     webrtc::VideoFrameType ft;
     GmpFrameTypeToWebrtcFrameType(aEncodedFrame->FrameType(), &ft);
     GMPBufferType type = aCodecSpecificInfo.mBufferType;
+    uint32_t timestamp = (aEncodedFrame->TimeStamp() * 90ll + 999)/1000;
 
-#ifdef GMP_ENCODE_HAS_START_CODES
-    {
-      // This code will be removed when the code inside the plugin is updated
-      // Break input encoded data into NALUs and convert to length+data format
-      const uint8_t* data = aEncodedFrame->Buffer();
-      const uint8_t* end  = data + aEncodedFrame->Size(); // at first byte past end
-      size_t nalSize = 0;
-      while (GetNextNALUnit(&data, end, &nalSize) == 0) {
-        // Assumes 4-byte start codes (0x00000001)
-        MOZ_ASSERT(data >= aEncodedFrame->Buffer() + 4);
-        uint8_t *start_code = const_cast<uint8_t*>(data-sizeof(uint32_t));
-        if (*start_code == 0x00 && *(start_code+1) == 0x00 &&
-            *(start_code+2) == 0x00 && *(start_code+3) == 0x01) {
-          *(reinterpret_cast<uint32_t*>(start_code)) = nalSize;
-        }
-        data += nalSize;
-      }
-      type = GMP_BufferLength32;
-    }
-#endif
+    LOGD(("GMP Encoded: %llu, type %d, len %d", aEncodedFrame->TimeStamp(), type,
+         aEncodedFrame->Size()));
 
     // Right now makes one Encoded() callback per unit
     // XXX convert to FragmentationHeader format (array of offsets and sizes plus a buffer) in
     // combination with H264 packetization changes in webrtc/trunk code
     uint8_t *buffer = aEncodedFrame->Buffer();
     uint8_t *end = aEncodedFrame->Buffer() + aEncodedFrame->Size();
     uint32_t size;
     while (buffer < end) {
@@ -409,17 +361,17 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoE
         default:
           // really that it's not in the enum; gives more readable error
           MOZ_ASSERT(aCodecSpecificInfo.mBufferType != GMP_BufferSingle);
           aEncodedFrame->Destroy();
           return;
       }
       webrtc::EncodedImage unit(buffer, size, size);
       unit._frameType = ft;
-      unit._timeStamp = aEncodedFrame->TimeStamp();
+      unit._timeStamp = timestamp;
       unit._completeFrame = true;
 
       mCallback->Encoded(unit, nullptr, nullptr);
 
       buffer += size;
     }
   }
   aEncodedFrame->Destroy();
@@ -456,17 +408,17 @@ WebrtcGmpVideoDecoder::InitDecode(const 
   return ret;
 }
 
 int32_t
 WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores)
 {
   GMPVideoHost* host = nullptr;
-  GMPVideoDecoder* gmp = nullptr;
+  GMPVideoDecoderProxy* gmp = nullptr;
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
   if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
                                                     NS_LITERAL_STRING(""),
                                                     &host,
                                                     &gmp)))) {
     return WEBRTC_VIDEO_CODEC_ERROR;
@@ -476,19 +428,24 @@ WebrtcGmpVideoDecoder::InitDecode_g(cons
   mHost = host;
   if (!gmp || !host) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   // Bug XXXXXX: transfer settings from codecSettings to codec.
   GMPVideoCodec codec;
   memset(&codec, 0, sizeof(codec));
+  codec.mGMPApiVersion = 33;
 
-  GMPVideoErr err = mGMP->InitDecode(codec, this, 1);
-  if (err != GMPVideoNoErr) {
+  // XXX this is currently a hack
+  //GMPVideoCodecUnion codecSpecific;
+  //memset(&codecSpecific, 0, sizeof(codecSpecific));
+  nsTArray<uint8_t> codecSpecific;
+  nsresult rv = mGMP->InitDecode(codec, codecSpecific, this, 1);
+  if (NS_FAILED(rv)) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 int32_t
 WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
@@ -518,46 +475,55 @@ WebrtcGmpVideoDecoder::Decode_g(const we
                                 const webrtc::RTPFragmentationHeader* aFragmentation,
                                 const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
                                 int64_t aRenderTimeMs)
 {
   MOZ_ASSERT(mHost);
   MOZ_ASSERT(mGMP);
 
   GMPVideoFrame* ftmp = nullptr;
-  GMPVideoErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
-  if (err != GMPVideoNoErr) {
+  GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
+  if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   GMPVideoEncodedFrame* frame = static_cast<GMPVideoEncodedFrame*>(ftmp);
   err = frame->CreateEmptyFrame(aInputImage._length);
-  if (err != GMPVideoNoErr) {
+  if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
+
+  // XXX At this point, we only will get mode1 data (a single length and a buffer)
+  // Session_info.cc/etc code needs to change to support mode 0.
+  *(reinterpret_cast<uint32_t*>(frame->Buffer())) = frame->Size();
+
   // XXX It'd be wonderful not to have to memcpy the encoded data!
-  memcpy(frame->Buffer(), aInputImage._buffer, frame->Size());
+  memcpy(frame->Buffer()+4, aInputImage._buffer+4, frame->Size()-4);
 
   frame->SetEncodedWidth(aInputImage._encodedWidth);
   frame->SetEncodedHeight(aInputImage._encodedHeight);
-  frame->SetTimeStamp(aInputImage._timeStamp);
+  frame->SetTimeStamp((aInputImage._timeStamp * 1000ll)/90); // rounds down
   frame->SetCompleteFrame(aInputImage._completeFrame);
 
   GMPVideoFrameType ft;
   int32_t ret = WebrtcFrameTypeToGmpFrameType(aInputImage._frameType, &ft);
   if (ret != WEBRTC_VIDEO_CODEC_OK) {
     return ret;
   }
 
   // Bug XXXXXX: Set codecSpecific info
   GMPCodecSpecificInfo info;
   memset(&info, 0, sizeof(info));
+  info.mCodecType = kGMPVideoCodecH264;
+  info.mBufferType = GMP_BufferLength32;
+  info.mCodecSpecific.mH264.mSimulcastIdx = 0;
 
-  err = mGMP->Decode(frame, aMissingFrames, info, aRenderTimeMs);
-  if (err != GMPVideoNoErr) {
+  LOGD(("GMP Decode: %llu, len %d", frame->TimeStamp(), aInputImage._length));
+  nsresult rv = mGMP->Decode(frame, aMissingFrames, info, aRenderTimeMs);
+  if (NS_FAILED(rv)) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 int32_t
 WebrtcGmpVideoDecoder::RegisterDecodeCompleteCallback( webrtc::DecodedImageCallback* aCallback)
@@ -594,17 +560,18 @@ WebrtcGmpVideoDecoder::Decoded(GMPVideoi
                                 aDecodedFrame->Width(),
                                 aDecodedFrame->Height(),
                                 aDecodedFrame->Stride(kGMPYPlane),
                                 aDecodedFrame->Stride(kGMPUPlane),
                                 aDecodedFrame->Stride(kGMPVPlane));
     if (ret != 0) {
       return;
     }
-    image.set_timestamp(aDecodedFrame->Timestamp());
+    image.set_timestamp((aDecodedFrame->Timestamp() * 90ll + 999)/1000); // round up
     image.set_render_time_ms(0);
 
+    LOGD(("GMP Decoded: %llu", aDecodedFrame->Timestamp()));
     mCallback->Decoded(image);
   }
   aDecodedFrame->Destroy();
 }
 
 }
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
@@ -25,27 +25,25 @@
 
 #include "mozIGeckoMediaPluginService.h"
 #include "MediaConduitInterface.h"
 #include "AudioConduit.h"
 #include "VideoConduit.h"
 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
 
 #include "gmp-video-host.h"
-#include "gmp-video-encode.h"
-#include "gmp-video-decode.h"
-#include "gmp-video-frame-i420.h"
-#include "gmp-video-frame-encoded.h"
+#include "GMPVideoDecoderProxy.h"
+#include "GMPVideoEncoderProxy.h"
 
 #include "WebrtcGmpVideoCodec.h"
 
 namespace mozilla {
 
 class WebrtcGmpVideoEncoder : public WebrtcVideoEncoder,
-                              public GMPEncoderCallback
+                              public GMPVideoEncoderCallback
 {
 public:
   WebrtcGmpVideoEncoder();
   virtual ~WebrtcGmpVideoEncoder() {}
 
   // Implement VideoEncoder interface.
   virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
                              int32_t aNumberOfCores,
@@ -61,17 +59,17 @@ public:
   virtual int32_t Release();
 
   virtual int32_t SetChannelParameters(uint32_t aPacketLoss,
                                        int aRTT) MOZ_OVERRIDE;
 
   virtual int32_t SetRates(uint32_t aNewBitRate,
                            uint32_t aFrameRate) MOZ_OVERRIDE;
 
-  // GMPEncoderCallback virtual functions.
+  // GMPVideoEncoderCallback virtual functions.
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
 
 
 private:
   virtual int32_t InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
                                int32_t aNumberOfCores,
                                uint32_t aMaxPayloadSize);
@@ -80,24 +78,24 @@ private:
                            const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
                            const std::vector<webrtc::VideoFrameType>* aFrameTypes);
 
   virtual int32_t SetRates_g(uint32_t aNewBitRate,
                              uint32_t aFrameRate);
 
   nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
   nsIThread* mGMPThread;
-  GMPVideoEncoder* mGMP;
+  GMPVideoEncoderProxy* mGMP;
   GMPVideoHost* mHost;
   webrtc::EncodedImageCallback* mCallback;
 };
 
 
 class WebrtcGmpVideoDecoder : public WebrtcVideoDecoder,
-                              public GMPDecoderCallback
+                              public GMPVideoDecoderCallback
 {
 public:
   WebrtcGmpVideoDecoder();
   virtual ~WebrtcGmpVideoDecoder() {}
 
   // Implement VideoDecoder interface.
   virtual int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
                              int32_t aNumberOfCores);
@@ -121,28 +119,36 @@ public:
   virtual void ReceivedDecodedFrame(const uint64_t aPictureId) MOZ_OVERRIDE {
     MOZ_CRASH();
   }
 
   virtual void InputDataExhausted() MOZ_OVERRIDE {
     MOZ_CRASH();
   }
 
+  virtual void DrainComplete() MOZ_OVERRIDE {
+    MOZ_CRASH();
+  }
+
+  virtual void ResetComplete() MOZ_OVERRIDE {
+    MOZ_CRASH();
+  }
+
 private:
   virtual int32_t InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
                                int32_t aNumberOfCores);
 
   virtual int32_t Decode_g(const webrtc::EncodedImage& aInputImage,
                            bool aMissingFrames,
                            const webrtc::RTPFragmentationHeader* aFragmentation,
                            const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
                            int64_t aRenderTimeMs);
 
   nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
   nsIThread* mGMPThread;
-  GMPVideoDecoder* mGMP;
+  GMPVideoDecoderProxy*  mGMP;
   GMPVideoHost* mHost;
   webrtc::DecodedImageCallback* mCallback;
 };
 
 }
 
 #endif