Bug 1020760 - Update GMP APIs to support EME plugins. r=jesup

This commit is contained in:
Chris Pearce 2014-07-11 12:20:51 +12:00
parent 78fa27150c
commit a234e1b6cb
48 changed files with 1276 additions and 557 deletions

View File

@ -7,9 +7,24 @@
#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,
@ -39,57 +54,11 @@ struct ParamTraits<GMPVideoCodecMode>
{};
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>
@ -136,6 +105,7 @@ struct ParamTraits<GMPVideoCodec>
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);
@ -145,11 +115,8 @@ struct ParamTraits<GMPVideoCodec>
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++) {
@ -160,6 +127,11 @@ struct ParamTraits<GMPVideoCodec>
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;
}
@ -178,16 +150,9 @@ struct ParamTraits<GMPVideoCodec>
!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;
}
@ -281,6 +246,31 @@ struct ParamTraits<GMPCodecSpecificInfoVP8>
}
};
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>
{
@ -289,8 +279,11 @@ struct ParamTraits<GMPCodecSpecificInfo>
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!");
}
@ -301,11 +294,18 @@ struct ParamTraits<GMPCodecSpecificInfo>
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;
@ -320,6 +320,9 @@ struct ParamTraits<GMPCodecSpecificInfo>
if (aParam.mCodecType == kGMPVideoCodecVP8) {
codecName = "VP8";
}
else if (aParam.mCodecType == kGMPVideoCodecH264) {
codecName = "H264";
}
aLog->append(StringPrintf(L"[%s]", codecName));
}
};

View File

@ -27,6 +27,7 @@ public:
void Run()
{
mTask->Run();
mTask->Destroy();
mTask = nullptr;
}
@ -35,7 +36,7 @@ private:
{
}
nsAutoPtr<GMPTask> mTask;
GMPTask* mTask;
};
class SyncRunnable MOZ_FINAL
@ -71,6 +72,7 @@ public:
void Run()
{
mTask->Run();
mTask->Destroy();
mTask = nullptr;
MonitorAutoLock lock(mMonitor);
mDone = true;
@ -83,7 +85,7 @@ private:
}
bool mDone;
nsAutoPtr<GMPTask> mTask;
GMPTask* mTask;
MessageLoop* mMessageLoop;
Monitor mMonitor;
};
@ -108,7 +110,6 @@ RunOnMainThread(GMPTask* aTask)
}
nsRefPtr<Runnable> r = new Runnable(aTask);
sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
return GMPNoErr;
@ -152,6 +153,9 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
aPlatformAPI.runonmainthread = &RunOnMainThread;
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
aPlatformAPI.createmutex = &CreateMutex;
aPlatformAPI.createrecord = nullptr;
aPlatformAPI.settimer = nullptr;
aPlatformAPI.getcurrenttime = nullptr;
}
GMPThreadImpl::GMPThreadImpl()

View File

@ -13,6 +13,8 @@
namespace mozilla {
namespace gmp {
class GMPChild;
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
class GMPThreadImpl : public GMPThread

View File

@ -183,7 +183,7 @@ 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);
@ -217,7 +217,7 @@ 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);

View File

@ -6,6 +6,7 @@
#ifndef GMPService_h_
#define GMPService_h_
#include "nsString.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsIObserver.h"
#include "nsTArray.h"

View File

@ -8,10 +8,10 @@ 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;
@ -32,8 +32,8 @@ struct GMPVideoi420FrameData
GMPPlaneData mVPlane;
int32_t mWidth;
int32_t mHeight;
uint32_t mTimestamp;
int64_t mRenderTime_ms;
uint64_t mTimestamp; // microseconds
uint64_t mDuration; // microseconds
};
}

View File

@ -80,6 +80,22 @@ GMPVideoDecoderChild::InputDataExhausted()
SendInputDataExhausted();
}
void
GMPVideoDecoderChild::DrainComplete()
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
SendDrainComplete();
}
void
GMPVideoDecoderChild::ResetComplete()
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
SendResetComplete();
}
void
GMPVideoDecoderChild::CheckThread()
{
@ -88,6 +104,7 @@ GMPVideoDecoderChild::CheckThread()
bool
GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
const nsTArray<uint8_t>& aCodecSpecific,
const int32_t& aCoreCount)
{
if (!mVideoDecoder) {
@ -95,8 +112,11 @@ GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
}
// 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;
}
@ -115,8 +135,6 @@ GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
// 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;
}

View File

@ -11,6 +11,7 @@
#include "gmp-video-decode.h"
#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
#include "mozilla/gmp/GMPTypes.h"
namespace mozilla {
namespace gmp {
@ -18,7 +19,7 @@ namespace gmp {
class GMPChild;
class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
public GMPDecoderCallback,
public GMPVideoDecoderCallback,
public GMPSharedMemManager
{
public:
@ -28,11 +29,13 @@ public:
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();
@ -60,6 +63,7 @@ public:
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,

View File

@ -12,6 +12,7 @@
#include "GMPMessageUtils.h"
#include "nsAutoRef.h"
#include "nsThreadUtils.h"
#include "mozilla/gmp/GMPTypes.h"
template <>
class nsAutoRefTraits<GMPVideoEncodedFrame> : public nsPointerRefTraits<GMPVideoEncodedFrame>
@ -42,32 +43,33 @@ 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,
@ -77,7 +79,7 @@ GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* 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());
@ -92,63 +94,63 @@ GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
// 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());
@ -160,6 +162,8 @@ GMPVideoDecoderParent::DecodingComplete()
mVideoHost.DoneWithAPI();
unused << SendDecodingComplete();
return NS_OK;
}
// Note: Keep this sync'd up with DecodingComplete
@ -236,6 +240,32 @@ GMPVideoDecoderParent::RecvInputDataExhausted()
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)
{

View File

@ -12,15 +12,16 @@
#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)
@ -30,16 +31,17 @@ public:
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();
@ -65,6 +67,8 @@ private:
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;
@ -72,7 +76,7 @@ private:
bool mCanSendMessages;
GMPParent* mPlugin;
GMPDecoderCallback* mCallback;
GMPVideoDecoderCallback* mCallback;
GMPVideoHostImpl mVideoHost;
};

View File

@ -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

View File

@ -14,8 +14,8 @@ 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),
@ -29,8 +29,8 @@ GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameDat
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()),
@ -49,6 +49,12 @@ GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
}
}
const GMPEncryptedBufferData*
GMPVideoEncodedFrameImpl::GetDecryptionData() const
{
return nullptr;
}
GMPVideoFrameFormat
GMPVideoEncodedFrameImpl::GetFrameFormat()
{
@ -80,8 +86,8 @@ GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameDa
{
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;
@ -104,7 +110,7 @@ GMPVideoEncodedFrameImpl::DestroyBuffer()
mBuffer = ipc::Shmem();
}
GMPVideoErr
GMPErr
GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
{
if (aSize == 0) {
@ -114,22 +120,22 @@ GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
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);
@ -137,13 +143,13 @@ GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
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
@ -171,27 +177,27 @@ GMPVideoEncodedFrameImpl::EncodedHeight()
}
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

View File

@ -31,9 +31,10 @@
#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 {
@ -63,16 +64,21 @@ public:
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;
@ -83,14 +89,15 @@ public:
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;

View File

@ -10,8 +10,6 @@
#include "GMPVideoEncodedFrameImpl.h"
#include "GMPVideoi420FrameImpl.h"
using mozilla::ipc::ProcessChild;
namespace mozilla {
namespace gmp {
@ -64,6 +62,7 @@ GMPVideoEncoderChild::CheckThread()
bool
GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
const nsTArray<uint8_t>& aCodecSpecific,
const int32_t& aNumberOfCores,
const uint32_t& aMaxPayloadSize)
{
@ -72,7 +71,12 @@ GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
}
// 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;
}
@ -80,7 +84,7 @@ GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
bool
GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const InfallibleTArray<int>& aFrameTypes)
const nsTArray<GMPVideoFrameType>& aFrameTypes)
{
if (!mVideoEncoder) {
return false;
@ -88,12 +92,8 @@ GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
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;
}

View File

@ -18,7 +18,7 @@ namespace gmp {
class GMPChild;
class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
public GMPEncoderCallback,
public GMPVideoEncoderCallback,
public GMPSharedMemManager
{
public:
@ -28,7 +28,7 @@ public:
void Init(GMPVideoEncoder* aEncoder);
GMPVideoHostImpl& Host();
// GMPEncoderCallback
// GMPVideoEncoderCallback
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
@ -58,11 +58,12 @@ public:
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;

View File

@ -43,42 +43,43 @@ 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());
@ -93,77 +94,71 @@ GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
// 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.

View File

@ -12,13 +12,14 @@
#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
{
@ -29,17 +30,18 @@ public:
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
@ -71,7 +73,7 @@ private:
bool mCanSendMessages;
GMPParent* mPlugin;
GMPEncoderCallback* mCallback;
GMPVideoEncoderCallback* mCallback;
GMPVideoHostImpl mVideoHost;
};

View File

@ -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_

View File

@ -20,41 +20,41 @@ 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;
@ -62,7 +62,7 @@ GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
*aPlane = p;
return GMPVideoNoErr;
return GMPNoErr;
}
GMPSharedMemManager*

View File

@ -35,8 +35,8 @@ public:
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.

View File

@ -73,21 +73,21 @@ GMPPlaneImpl::InitPlaneData(GMPPlaneData& aPlaneData)
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()) {
@ -98,7 +98,7 @@ GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
mBuffer = new_mem;
return GMPVideoNoErr;
return GMPNoErr;
}
void
@ -110,31 +110,31 @@ GMPPlaneImpl::DestroyBuffer()
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;
}
@ -145,14 +145,14 @@ GMPPlaneImpl::Copy(const GMPPlane& aPlane)
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;
}
@ -163,7 +163,7 @@ GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
mSize = aSize;
mStride = aStride;
return GMPVideoNoErr;
return GMPNoErr;
}
void

View File

@ -34,13 +34,13 @@ public:
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;
@ -51,7 +51,7 @@ public:
virtual void Destroy() MOZ_OVERRIDE;
private:
GMPVideoErr MaybeResize(int32_t aNewSize);
GMPErr MaybeResize(int32_t aNewSize);
void DestroyBuffer();
ipc::Shmem mBuffer;

View File

@ -15,8 +15,8 @@ GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost)
mVPlane(aHost),
mWidth(0),
mHeight(0),
mTimestamp(0),
mRenderTime_ms(0)
mTimestamp(0ll),
mDuration(0ll)
{
MOZ_ASSERT(aHost);
}
@ -29,7 +29,7 @@ GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrame
mWidth(aFrameData.mWidth()),
mHeight(aFrameData.mHeight()),
mTimestamp(aFrameData.mTimestamp()),
mRenderTime_ms(aFrameData.mRenderTime_ms())
mDuration(aFrameData.mDuration())
{
MOZ_ASSERT(aHost);
}
@ -47,7 +47,7 @@ GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData)
aFrameData.mWidth() = mWidth;
aFrameData.mHeight() = mHeight;
aFrameData.mTimestamp() = mTimestamp;
aFrameData.mRenderTime_ms() = mRenderTime_ms;
aFrameData.mDuration() = mDuration;
return true;
}
@ -106,12 +106,12 @@ GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) {
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;
@ -119,28 +119,28 @@ GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
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,
@ -152,58 +152,58 @@ GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
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
@ -216,7 +216,7 @@ GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame)
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*
@ -259,28 +259,28 @@ GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const
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
@ -296,27 +296,27 @@ GMPVideoi420FrameImpl::Height() const
}
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

View File

@ -32,33 +32,33 @@ public:
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;
@ -71,8 +71,8 @@ private:
GMPPlaneImpl mVPlane;
int32_t mWidth;
int32_t mHeight;
uint32_t mTimestamp;
int64_t mRenderTime_ms;
uint64_t mTimestamp;
uint64_t mDuration;
};
} // namespace gmp

View File

@ -19,6 +19,7 @@ intr protocol PGMPVideoDecoder
manager PGMP;
child:
async InitDecode(GMPVideoCodec aCodecSettings,
uint8_t[] aCodecSpecific,
int32_t aCoreCount);
async Decode(GMPVideoEncodedFrameData aInputFrame,
bool aMissingFrames,
@ -35,6 +36,8 @@ parent:
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

View File

@ -8,6 +8,7 @@ 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";
@ -19,11 +20,12 @@ 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);

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -35,7 +35,16 @@
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_

View File

@ -34,12 +34,14 @@
#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;
};
@ -58,10 +60,20 @@ public:
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,
@ -74,6 +86,9 @@ struct GMPPlatformAPI {
GMPRunOnMainThreadPtr runonmainthread;
GMPSyncRunOnMainThreadPtr syncrunonmainthread;
GMPCreateMutexPtr createmutex;
GMPCreateRecordPtr createrecord;
GMPSetTimerOnMainThreadPtr settimer;
GMPGetCurrentTimePtr getcurrenttime;
};
#endif // GMP_PLATFORM_h_

View File

@ -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_

View File

@ -72,39 +72,50 @@ struct GMPVideoCodecVP8
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
@ -121,11 +132,19 @@ struct GMPSimulcastStream
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;
@ -138,7 +157,8 @@ struct GMPVideoCodec
uint32_t mMinBitrate; // kilobits/sec.
uint32_t mMaxFramerate;
GMPVideoCodecUnion mCodecSpecific;
bool mFrameDroppingOn;
int32_t mKeyFrameInterval;
uint32_t mQPMax;
uint32_t mNumberOfSimulcastStreams;
@ -157,6 +177,7 @@ enum GMPBufferType {
GMP_BufferLength16,
GMP_BufferLength24,
GMP_BufferLength32,
GMP_BufferInvalid,
};
struct GMPCodecSpecificInfoGeneric {
@ -188,6 +209,7 @@ union GMPCodecSpecificInfoUnion
{
GMPCodecSpecificInfoGeneric mGeneric;
GMPCodecSpecificInfoVP8 mVP8;
GMPCodecSpecificInfoH264 mH264;
};
// Note: if any pointers are added to this struct or its sub-structs, it

View File

@ -34,17 +34,17 @@
#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;
@ -53,6 +53,10 @@ public:
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
@ -63,9 +67,11 @@ public:
// 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.
@ -82,16 +88,22 @@ public:
//
// 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;

View File

@ -37,16 +37,16 @@
#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;
@ -62,26 +62,32 @@ public:
//
// 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.
@ -89,19 +95,19 @@ public:
// - 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;

View File

@ -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_

View File

@ -35,6 +35,8 @@
#define GMP_VIDEO_FRAME_ENCODED_h_
#include <stdint.h>
#include "gmp-decryption.h"
#include "gmp-video-frame.h"
enum GMPVideoFrameType
{
@ -58,17 +60,22 @@ 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;
@ -79,6 +86,9 @@ public:
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_

View File

@ -34,7 +34,7 @@
#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"
@ -63,22 +63,22 @@ public:
// 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;
@ -96,10 +96,10 @@ public:
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;
@ -107,17 +107,20 @@ public:
// 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;

View File

@ -34,7 +34,6 @@
#ifndef GMP_VIDEO_FRAME_h_
#define GMP_VIDEO_FRAME_h_
#include "gmp-video-errors.h"
#include "gmp-video-plane.h"
enum GMPVideoFrameFormat {

View File

@ -34,7 +34,7 @@
#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"
@ -44,8 +44,8 @@ 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_

View File

@ -34,7 +34,7 @@
#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
@ -52,18 +52,18 @@ public:
// 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;

View File

@ -11,13 +11,19 @@ XPIDL_SOURCES += [
]
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',
@ -33,9 +39,11 @@ EXPORTS += [
'GMPSharedMemManager.h',
'GMPVideoDecoderChild.h',
'GMPVideoDecoderParent.h',
'GMPVideoDecoderProxy.h',
'GMPVideoEncodedFrameImpl.h',
'GMPVideoEncoderChild.h',
'GMPVideoEncoderParent.h',
'GMPVideoEncoderProxy.h',
'GMPVideoHost.h',
'GMPVideoi420FrameImpl.h',
'GMPVideoPlaneImpl.h',

View File

@ -10,18 +10,18 @@
%{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
{
/**
@ -36,9 +36,9 @@ interface mozIGeckoMediaPluginService : nsISupports
* 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.
@ -47,9 +47,9 @@ interface mozIGeckoMediaPluginService : nsISupports
* 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.

View File

@ -14,6 +14,8 @@
#include "mozIGeckoMediaPluginService.h"
#include "nsServiceManagerUtils.h"
#include "GMPVideoDecoderProxy.h"
#include "GMPVideoEncoderProxy.h"
#include "gmp-video-host.h"
#include "gmp-video-frame-i420.h"
@ -23,6 +25,26 @@
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)
@ -121,7 +143,7 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
uint32_t aMaxPayloadSize)
{
GMPVideoHost* host = nullptr;
GMPVideoEncoder* gmp = nullptr;
GMPVideoEncoderProxy* gmp = nullptr;
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
@ -144,6 +166,7 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
GMPVideoCodec codec;
memset(&codec, 0, sizeof(codec));
codec.mGMPApiVersion = 33;
codec.mWidth = aCodecSettings->width;
codec.mHeight = aCodecSettings->height;
codec.mStartBitrate = aCodecSettings->startBitrate;
@ -151,8 +174,12 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
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;
}
@ -188,8 +215,8 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
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);
@ -205,17 +232,18 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
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;
@ -224,11 +252,12 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
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;
}
@ -275,75 +304,15 @@ 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)
@ -352,27 +321,10 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
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
@ -414,7 +366,7 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
}
webrtc::EncodedImage unit(buffer, size, size);
unit._frameType = ft;
unit._timeStamp = aEncodedFrame->TimeStamp();
unit._timeStamp = timestamp;
unit._completeFrame = true;
mCallback->Encoded(unit, nullptr, nullptr);
@ -461,7 +413,7 @@ 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"));
@ -481,9 +433,14 @@ WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
// 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;
}
@ -523,22 +480,29 @@ WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
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.
MOZ_ASSERT(ntohl(*(reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(aInputImage._buffer)))) ==
0x00000001);
*(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;
@ -550,9 +514,13 @@ WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
// 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;
}
@ -599,9 +567,10 @@ WebrtcGmpVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
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();

View File

@ -30,17 +30,15 @@
#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();
@ -66,7 +64,7 @@ public:
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;
@ -85,14 +83,14 @@ private:
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
nsIThread* mGMPThread;
GMPVideoEncoder* mGMP;
GMPVideoEncoderProxy* mGMP;
GMPVideoHost* mHost;
webrtc::EncodedImageCallback* mCallback;
};
class WebrtcGmpVideoDecoder : public WebrtcVideoDecoder,
public GMPDecoderCallback
public GMPVideoDecoderCallback
{
public:
WebrtcGmpVideoDecoder();
@ -126,6 +124,14 @@ public:
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);
@ -138,7 +144,7 @@ private:
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
nsIThread* mGMPThread;
GMPVideoDecoder* mGMP;
GMPVideoDecoderProxy* mGMP;
GMPVideoHost* mHost;
webrtc::DecodedImageCallback* mCallback;
};