mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1182289: Clean up dispatches in WebrtcGmpVideoEncoder/Decoder. r=jesup, a=abillings
This commit is contained in:
parent
a024b5aa03
commit
eeda62f97a
@ -8,11 +8,11 @@
|
||||
namespace mozilla {
|
||||
|
||||
VideoEncoder* GmpVideoCodec::CreateEncoder() {
|
||||
return static_cast<VideoEncoder*>(new WebrtcGmpVideoEncoder());
|
||||
return static_cast<VideoEncoder*>(new WebrtcVideoEncoderProxy());
|
||||
}
|
||||
|
||||
VideoDecoder* GmpVideoCodec::CreateDecoder() {
|
||||
return static_cast<VideoDecoder*>(new WebrtcGmpVideoDecoder());
|
||||
return static_cast<VideoDecoder*>(new WebrtcVideoDecoderProxy());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "GMPVideoDecoderProxy.h"
|
||||
#include "GMPVideoEncoderProxy.h"
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
#include "gmp-video-host.h"
|
||||
#include "gmp-video-frame-i420.h"
|
||||
@ -47,31 +48,61 @@ GetGMPLog()
|
||||
#define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg)
|
||||
#define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg)
|
||||
|
||||
WebrtcGmpPCHandleSetter::WebrtcGmpPCHandleSetter(const std::string& aPCHandle)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(false, "WebrtcGmpPCHandleSetter can only be used on main");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(sCurrentHandle.empty());
|
||||
sCurrentHandle = aPCHandle;
|
||||
}
|
||||
|
||||
WebrtcGmpPCHandleSetter::~WebrtcGmpPCHandleSetter()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(false, "WebrtcGmpPCHandleSetter can only be used on main");
|
||||
return;
|
||||
}
|
||||
|
||||
sCurrentHandle.clear();
|
||||
}
|
||||
|
||||
/* static */ std::string
|
||||
WebrtcGmpPCHandleSetter::GetCurrentHandle()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(false, "WebrtcGmpPCHandleSetter can only be used on main");
|
||||
return "";
|
||||
}
|
||||
|
||||
return sCurrentHandle;
|
||||
}
|
||||
|
||||
std::string WebrtcGmpPCHandleSetter::sCurrentHandle = "";
|
||||
|
||||
// Encoder.
|
||||
WebrtcGmpVideoEncoder::WebrtcGmpVideoEncoder()
|
||||
: mGMP(nullptr)
|
||||
, mInitting(false)
|
||||
, mHost(nullptr)
|
||||
, mMaxPayloadSize(0)
|
||||
, mCallbackMutex("WebrtcGmpVideoEncoder encoded callback mutex")
|
||||
, mCallback(nullptr)
|
||||
, mCachedPluginId(0)
|
||||
{}
|
||||
|
||||
static void
|
||||
Encoder_Close_g(GMPVideoEncoderProxy* aGMP)
|
||||
{
|
||||
aGMP->Close();
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (mPCHandle.empty()) {
|
||||
mPCHandle = WebrtcGmpPCHandleSetter::GetCurrentHandle();
|
||||
}
|
||||
MOZ_ASSERT(!mPCHandle.empty());
|
||||
#endif
|
||||
}
|
||||
|
||||
WebrtcGmpVideoEncoder::~WebrtcGmpVideoEncoder()
|
||||
{
|
||||
// Note: we only use SyncRunnables to access mGMP
|
||||
// Callbacks may occur at any time until we call Close (or receive
|
||||
// Terminated()), so call Close here synchronously.
|
||||
// Do NOT touch the refcount of 'this'!
|
||||
if (mGMPThread && mGMP) {
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableNM(&Encoder_Close_g, mGMP));
|
||||
mGMP = nullptr;
|
||||
}
|
||||
// We should not have been destroyed if we never closed our GMP
|
||||
MOZ_ASSERT(!mGMP);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -146,85 +177,135 @@ WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
MOZ_ASSERT(currentThread != mGMPThread);
|
||||
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
mGMPThread->Dispatch(WrapRunnable(this,
|
||||
&WebrtcGmpVideoEncoder::InitEncode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
return initDone->Result();
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize,
|
||||
InitDoneRunnable* aInitDone)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
UniquePtr<GetGMPVideoEncoderCallback> callback(
|
||||
new InitDoneCallback(this, aInitDone, aCodecSettings, aMaxPayloadSize));
|
||||
nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mGMPThread = nullptr;
|
||||
mHost = nullptr;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::GmpInitDone(GMPVideoEncoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
uint32_t aMaxPayloadSize)
|
||||
{
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
if (!mGMP || !mHost) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
// Bug XXXXXX: transfer settings from codecSettings to codec.
|
||||
memset(&mCodecParams, 0, sizeof(mCodecParams));
|
||||
GMPVideoCodec codecParams;
|
||||
memset(&codecParams, 0, sizeof(codecParams));
|
||||
|
||||
mCodecParams.mGMPApiVersion = 33;
|
||||
mCodecParams.mStartBitrate = aCodecSettings->startBitrate;
|
||||
mCodecParams.mMinBitrate = aCodecSettings->minBitrate;
|
||||
mCodecParams.mMaxBitrate = aCodecSettings->maxBitrate;
|
||||
mCodecParams.mMaxFramerate = aCodecSettings->maxFramerate;
|
||||
codecParams.mGMPApiVersion = 33;
|
||||
codecParams.mStartBitrate = aCodecSettings->startBitrate;
|
||||
codecParams.mMinBitrate = aCodecSettings->minBitrate;
|
||||
codecParams.mMaxBitrate = aCodecSettings->maxBitrate;
|
||||
codecParams.mMaxFramerate = aCodecSettings->maxFramerate;
|
||||
mMaxPayloadSize = aMaxPayloadSize;
|
||||
if (aCodecSettings->codecSpecific.H264.packetizationMode == 1) {
|
||||
mMaxPayloadSize = 0; // No limit.
|
||||
}
|
||||
|
||||
if (aCodecSettings->mode == webrtc::kScreensharing) {
|
||||
mCodecParams.mMode = kGMPScreensharing;
|
||||
codecParams.mMode = kGMPScreensharing;
|
||||
} else {
|
||||
mCodecParams.mMode = kGMPRealtimeVideo;
|
||||
codecParams.mMode = kGMPRealtimeVideo;
|
||||
}
|
||||
|
||||
return InitEncoderForSize(aCodecSettings->width, aCodecSettings->height);
|
||||
codecParams.mWidth = aCodecSettings->width;
|
||||
codecParams.mHeight = aCodecSettings->height;
|
||||
|
||||
nsRefPtr<GmpInitDoneRunnable> initDone(new GmpInitDoneRunnable(mPCHandle));
|
||||
mGMPThread->Dispatch(WrapRunnableNM(WebrtcGmpVideoEncoder::InitEncode_g,
|
||||
nsRefPtr<WebrtcGmpVideoEncoder>(this),
|
||||
codecParams,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
// Since init of the GMP encoder is a multi-step async dispatch (including
|
||||
// dispatches to main), and since this function is invoked on main, there's
|
||||
// no safe way to block until this init is done. If an error occurs, we'll
|
||||
// handle it later.
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
WebrtcGmpVideoEncoder::InitEncode_g(
|
||||
const nsRefPtr<WebrtcGmpVideoEncoder>& aThis,
|
||||
const GMPVideoCodec& aCodecParams,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
UniquePtr<GetGMPVideoEncoderCallback> callback(
|
||||
new InitDoneCallback(aThis, aInitDone, aCodecParams, aMaxPayloadSize));
|
||||
aThis->mInitting = true;
|
||||
nsresult rv = aThis->mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOGD(("GMP Encode: GetGMPVideoEncoder failed"));
|
||||
aThis->Close_g();
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
|
||||
"GMP Encode: GetGMPVideoEncoder failed");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::InitEncoderForSize(unsigned short aWidth, unsigned short aHeight)
|
||||
WebrtcGmpVideoEncoder::GmpInitDone(GMPVideoEncoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
std::string* aErrorOut)
|
||||
{
|
||||
if (!mInitting || !aGMP || !aHost) {
|
||||
*aErrorOut = "GMP Encode: Either init was aborted, "
|
||||
"or init failed to supply either a GMP Encoder or GMP host.";
|
||||
if (aGMP) {
|
||||
// This could destroy us, since aGMP may be the last thing holding a ref
|
||||
// Return immediately.
|
||||
aGMP->Close();
|
||||
}
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
mInitting = false;
|
||||
|
||||
if (mGMP && mGMP != aGMP) {
|
||||
Close_g();
|
||||
}
|
||||
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
mCachedPluginId = mGMP->GetPluginId();
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::GmpInitDone(GMPVideoEncoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
const GMPVideoCodec& aCodecParams,
|
||||
uint32_t aMaxPayloadSize,
|
||||
std::string* aErrorOut)
|
||||
{
|
||||
int32_t r = GmpInitDone(aGMP, aHost, aErrorOut);
|
||||
if (r != WEBRTC_VIDEO_CODEC_OK) {
|
||||
// We might have been destroyed if GmpInitDone failed.
|
||||
// Return immediately.
|
||||
return r;
|
||||
}
|
||||
mCodecParams = aCodecParams;
|
||||
return InitEncoderForSize(aCodecParams.mWidth,
|
||||
aCodecParams.mHeight,
|
||||
aErrorOut);
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoEncoder::Close_g()
|
||||
{
|
||||
GMPVideoEncoderProxy* gmp(mGMP);
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
mInitting = false;
|
||||
|
||||
if (gmp) {
|
||||
// Do this last, since this could cause us to be destroyed
|
||||
gmp->Close();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::InitEncoderForSize(unsigned short aWidth,
|
||||
unsigned short aHeight,
|
||||
std::string* aErrorOut)
|
||||
{
|
||||
mCodecParams.mWidth = aWidth;
|
||||
mCodecParams.mHeight = aHeight;
|
||||
@ -233,6 +314,7 @@ WebrtcGmpVideoEncoder::InitEncoderForSize(unsigned short aWidth, unsigned short
|
||||
|
||||
GMPErr err = mGMP->InitEncode(mCodecParams, codecSpecific, this, 1, mMaxPayloadSize);
|
||||
if (err != GMPNoErr) {
|
||||
*aErrorOut = "GMP Encode: InitEncode failed";
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
@ -245,69 +327,45 @@ WebrtcGmpVideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
if (!mGMP) {
|
||||
// destroyed via Terminate()
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aInputImage.width() >= 0 && aInputImage.height() >= 0);
|
||||
if (static_cast<uint32_t>(aInputImage.width()) != mCodecParams.mWidth ||
|
||||
static_cast<uint32_t>(aInputImage.height()) != mCodecParams.mHeight) {
|
||||
LOGD(("GMP Encode: resolution change from %ux%u to %dx%d",
|
||||
mCodecParams.mWidth, mCodecParams.mHeight, aInputImage.width(), aInputImage.height()));
|
||||
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
// Would be really nice to avoid this sync dispatch, but it would require a
|
||||
// copy of the frame, since it doesn't appear to actually have a refcount.
|
||||
mGMPThread->Dispatch(
|
||||
WrapRunnable(this,
|
||||
&WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange,
|
||||
&WebrtcGmpVideoEncoder::Encode_g,
|
||||
&aInputImage,
|
||||
initDone));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
aCodecSpecificInfo,
|
||||
aFrameTypes),
|
||||
NS_DISPATCH_SYNC);
|
||||
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
if (initDone->Result() != WEBRTC_VIDEO_CODEC_OK) {
|
||||
return initDone->Result();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableRet(&ret, this,
|
||||
&WebrtcGmpVideoEncoder::Encode_g,
|
||||
&aInputImage,
|
||||
aCodecSpecificInfo,
|
||||
aFrameTypes));
|
||||
|
||||
return ret;
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange(const webrtc::I420VideoFrame* aInputImage,
|
||||
InitDoneRunnable* aInitDone)
|
||||
WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange(
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone)
|
||||
{
|
||||
mGMP->Close();
|
||||
Close_g();
|
||||
|
||||
UniquePtr<GetGMPVideoEncoderCallback> callback(
|
||||
new InitDoneForResolutionChangeCallback(this, aInitDone,
|
||||
aInputImage->width(),
|
||||
aInputImage->height()));
|
||||
new InitDoneForResolutionChangeCallback(this,
|
||||
aInitDone,
|
||||
aWidth,
|
||||
aHeight));
|
||||
|
||||
// OpenH264 codec (at least) can't handle dynamic input resolution changes
|
||||
// re-init the plugin when the resolution changes
|
||||
// XXX allow codec to indicate it doesn't need re-init!
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
mInitting = true;
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback))))) {
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
|
||||
"GMP Encode: GetGMPVideoEncoder failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,8 +374,27 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
|
||||
{
|
||||
if (!mGMP) {
|
||||
// destroyed via Terminate(), failed to init, or just not initted yet
|
||||
LOGD(("GMP Encode: not initted yet"));
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
MOZ_ASSERT(mHost);
|
||||
MOZ_ASSERT(mGMP);
|
||||
|
||||
if (static_cast<uint32_t>(aInputImage->width()) != mCodecParams.mWidth ||
|
||||
static_cast<uint32_t>(aInputImage->height()) != mCodecParams.mHeight) {
|
||||
LOGD(("GMP Encode: resolution change from %ux%u to %dx%d",
|
||||
mCodecParams.mWidth, mCodecParams.mHeight, aInputImage->width(), aInputImage->height()));
|
||||
|
||||
nsRefPtr<GmpInitDoneRunnable> initDone(new GmpInitDoneRunnable(mPCHandle));
|
||||
RegetEncoderForResolutionChange(aInputImage->width(),
|
||||
aInputImage->height(),
|
||||
initDone);
|
||||
if (!mGMP) {
|
||||
// We needed to go async to re-get the encoder. Bail.
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
GMPVideoFrame* ftmp = nullptr;
|
||||
GMPErr err = mHost->CreateFrame(kGMPI420VideoFrame, &ftmp);
|
||||
@ -374,26 +451,28 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* aCallback)
|
||||
{
|
||||
MutexAutoLock lock(mCallbackMutex);
|
||||
mCallback = aCallback;
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
WebrtcGmpVideoEncoder::ReleaseGmp_g(nsRefPtr<WebrtcGmpVideoEncoder>& aEncoder)
|
||||
{
|
||||
aEncoder->Close_g();
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::Release()
|
||||
WebrtcGmpVideoEncoder::ReleaseGmp()
|
||||
{
|
||||
LOGD(("GMP Released:"));
|
||||
// Note: we only use SyncRunnables to access mGMP
|
||||
// Callbacks may occur at any time until we call Close (or receive
|
||||
// Terminated()), so call Close here synchronously.
|
||||
if (mGMPThread && mGMP) {
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableNM(&Encoder_Close_g, mGMP));
|
||||
if (mGMPThread) {
|
||||
mGMPThread->Dispatch(
|
||||
WrapRunnableNM(&WebrtcGmpVideoEncoder::ReleaseGmp_g,
|
||||
nsRefPtr<WebrtcGmpVideoEncoder>(this)),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
// Now safe to forget things
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
@ -406,25 +485,28 @@ WebrtcGmpVideoEncoder::SetChannelParameters(uint32_t aPacketLoss, int aRTT)
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate)
|
||||
{
|
||||
int32_t ret;
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableRet(&ret, this,
|
||||
&WebrtcGmpVideoEncoder::SetRates_g,
|
||||
aNewBitRate, aFrameRate));
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoEncoder::SetRates_g,
|
||||
nsRefPtr<WebrtcGmpVideoEncoder>(this),
|
||||
aNewBitRate,
|
||||
aFrameRate),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoEncoder::SetRates_g(uint32_t aNewBitRate, uint32_t aFrameRate)
|
||||
/* static */ int32_t
|
||||
WebrtcGmpVideoEncoder::SetRates_g(nsRefPtr<WebrtcGmpVideoEncoder> aThis,
|
||||
uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate)
|
||||
{
|
||||
if (!mGMP) {
|
||||
if (!aThis->mGMP) {
|
||||
// destroyed via Terminate()
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
GMPErr err = mGMP->SetRates(aNewBitRate, aFrameRate);
|
||||
GMPErr err = aThis->mGMP->SetRates(aNewBitRate, aFrameRate);
|
||||
if (err != GMPNoErr) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
@ -437,11 +519,11 @@ void
|
||||
WebrtcGmpVideoEncoder::Terminated()
|
||||
{
|
||||
LOGD(("GMP Encoder Terminated: %p", (void *)this));
|
||||
mCachedPluginId = PluginID();
|
||||
|
||||
// We need to drop our reference to this
|
||||
mGMP->Close();
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
mInitting = false;
|
||||
// Could now notify that it's dead
|
||||
}
|
||||
|
||||
@ -449,7 +531,8 @@ void
|
||||
WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo)
|
||||
{
|
||||
if (mCallback) { // paranoia
|
||||
MutexAutoLock lock(mCallbackMutex);
|
||||
if (mCallback) {
|
||||
webrtc::VideoFrameType ft;
|
||||
GmpFrameTypeToWebrtcFrameType(aEncodedFrame->FrameType(), &ft);
|
||||
uint32_t timestamp = (aEncodedFrame->TimeStamp() * 90ll + 999)/1000;
|
||||
@ -559,7 +642,6 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
unit._completeFrame = true;
|
||||
|
||||
mCallback->Encoded(unit, nullptr, &fragmentation);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,35 +649,34 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
// Decoder.
|
||||
WebrtcGmpVideoDecoder::WebrtcGmpVideoDecoder() :
|
||||
mGMP(nullptr),
|
||||
mInitting(false),
|
||||
mHost(nullptr),
|
||||
mCallbackMutex("WebrtcGmpVideoDecoder decoded callback mutex"),
|
||||
mCallback(nullptr),
|
||||
mCachedPluginId(0),
|
||||
mDecoderStatus(GMPNoErr){}
|
||||
|
||||
static void
|
||||
Decoder_Close_g(GMPVideoDecoderProxy* aGMP)
|
||||
mDecoderStatus(GMPNoErr)
|
||||
{
|
||||
aGMP->Close();
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (mPCHandle.empty()) {
|
||||
mPCHandle = WebrtcGmpPCHandleSetter::GetCurrentHandle();
|
||||
}
|
||||
MOZ_ASSERT(!mPCHandle.empty());
|
||||
#endif
|
||||
}
|
||||
|
||||
WebrtcGmpVideoDecoder::~WebrtcGmpVideoDecoder()
|
||||
{
|
||||
// Note: we only use SyncRunnables to access mGMP
|
||||
// Callbacks may occur at any time until we call Close (or receive
|
||||
// Terminated()), so call Close here synchronously.
|
||||
// Do NOT touch the refcount of 'this'!
|
||||
if (mGMPThread && mGMP) {
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableNM(&Decoder_Close_g, mGMP));
|
||||
mGMP = nullptr;
|
||||
}
|
||||
// We should not have been destroyed if we never closed our GMP
|
||||
MOZ_ASSERT(!mGMP);
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores)
|
||||
{
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (!mMPS) {
|
||||
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
}
|
||||
MOZ_ASSERT(mMPS);
|
||||
|
||||
if (!mGMPThread) {
|
||||
@ -604,54 +685,65 @@ WebrtcGmpVideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings,
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<InitDoneRunnable> initDone(new InitDoneRunnable());
|
||||
mGMPThread->Dispatch(WrapRunnable(this,
|
||||
&WebrtcGmpVideoDecoder::InitDecode_g,
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
initDone.get()),
|
||||
nsRefPtr<GmpInitDoneRunnable> initDone(new GmpInitDoneRunnable(mPCHandle));
|
||||
mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoDecoder::InitDecode_g,
|
||||
nsRefPtr<WebrtcGmpVideoDecoder>(this),
|
||||
aCodecSettings,
|
||||
aNumberOfCores,
|
||||
initDone),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
while (!initDone->IsDone()) {
|
||||
NS_ProcessNextEvent(currentThread, true);
|
||||
}
|
||||
|
||||
return initDone->Result();
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
InitDoneRunnable* aInitDone)
|
||||
/* static */ void
|
||||
WebrtcGmpVideoDecoder::InitDecode_g(
|
||||
const nsRefPtr<WebrtcGmpVideoDecoder>& aThis,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone)
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
UniquePtr<GetGMPVideoDecoderCallback> callback(
|
||||
new InitDoneCallback(this, aInitDone));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback))))) {
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mGMPThread = nullptr;
|
||||
mHost = nullptr;
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR);
|
||||
new InitDoneCallback(aThis, aInitDone));
|
||||
aThis->mInitting = true;
|
||||
nsresult rv = aThis->mMPS->GetGMPVideoDecoder(&tags,
|
||||
NS_LITERAL_CSTRING(""),
|
||||
Move(callback));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOGD(("GMP Decode: GetGMPVideoDecoder failed"));
|
||||
aThis->Close_g();
|
||||
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
|
||||
"GMP Decode: GetGMPVideoDecoder failed.");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::GmpInitDone(GMPVideoDecoderProxy* aGMP,
|
||||
GMPVideoHost* aHost)
|
||||
GMPVideoHost* aHost,
|
||||
std::string* aErrorOut)
|
||||
{
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
mMPS = nullptr;
|
||||
|
||||
if (!mGMP || !mHost) {
|
||||
if (!mInitting || !aGMP || !aHost) {
|
||||
*aErrorOut = "GMP Decode: Either init was aborted, "
|
||||
"or init failed to supply either a GMP decoder or GMP host.";
|
||||
if (aGMP) {
|
||||
// This could destroy us, since aGMP may be the last thing holding a ref
|
||||
// Return immediately.
|
||||
aGMP->Close();
|
||||
}
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
mInitting = false;
|
||||
|
||||
if (mGMP && mGMP != aGMP) {
|
||||
Close_g();
|
||||
}
|
||||
|
||||
mGMP = aGMP;
|
||||
mHost = aHost;
|
||||
mCachedPluginId = mGMP->GetPluginId();
|
||||
// Bug XXXXXX: transfer settings from codecSettings to codec.
|
||||
GMPVideoCodec codec;
|
||||
memset(&codec, 0, sizeof(codec));
|
||||
@ -663,12 +755,27 @@ WebrtcGmpVideoDecoder::GmpInitDone(GMPVideoDecoderProxy* aGMP,
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
nsresult rv = mGMP->InitDecode(codec, codecSpecific, this, 1);
|
||||
if (NS_FAILED(rv)) {
|
||||
*aErrorOut = "GMP Decode: InitDecode failed";
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoDecoder::Close_g()
|
||||
{
|
||||
GMPVideoDecoderProxy* gmp(mGMP);
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
mInitting = false;
|
||||
|
||||
if (gmp) {
|
||||
// Do this last, since this could cause us to be destroyed
|
||||
gmp->Close();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
|
||||
bool aMissingFrames,
|
||||
@ -678,6 +785,9 @@ WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
|
||||
{
|
||||
int32_t ret;
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
// Would be really nice to avoid this sync dispatch, but it would require a
|
||||
// copy of the frame, since it doesn't appear to actually have a refcount.
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableRet(&ret, this,
|
||||
&WebrtcGmpVideoDecoder::Decode_g,
|
||||
@ -697,11 +807,12 @@ WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs)
|
||||
{
|
||||
MOZ_ASSERT(mHost);
|
||||
if (!mGMP) {
|
||||
// destroyed via Terminate()
|
||||
// destroyed via Terminate(), failed to init, or just not initted yet
|
||||
LOGD(("GMP Decode: not initted yet"));
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
MOZ_ASSERT(mHost);
|
||||
|
||||
if (!aInputImage._length) {
|
||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||
@ -764,27 +875,29 @@ WebrtcGmpVideoDecoder::Decode_g(const webrtc::EncodedImage& aInputImage,
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::RegisterDecodeCompleteCallback( webrtc::DecodedImageCallback* aCallback)
|
||||
{
|
||||
MutexAutoLock lock(mCallbackMutex);
|
||||
mCallback = aCallback;
|
||||
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::Release()
|
||||
/* static */ void
|
||||
WebrtcGmpVideoDecoder::ReleaseGmp_g(nsRefPtr<WebrtcGmpVideoDecoder>& aDecoder)
|
||||
{
|
||||
// Note: we only use SyncRunnables to access mGMP
|
||||
// Callbacks may occur at any time until we call Close (or receive
|
||||
// Terminated()), so call Close here synchronously.
|
||||
if (mGMPThread && mGMP) {
|
||||
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
|
||||
WrapRunnableNM(&Decoder_Close_g, mGMP));
|
||||
aDecoder->Close_g();
|
||||
}
|
||||
|
||||
int32_t
|
||||
WebrtcGmpVideoDecoder::ReleaseGmp()
|
||||
{
|
||||
LOGD(("GMP Released:"));
|
||||
if (mGMPThread) {
|
||||
mGMPThread->Dispatch(
|
||||
WrapRunnableNM(&WebrtcGmpVideoDecoder::ReleaseGmp_g,
|
||||
nsRefPtr<WebrtcGmpVideoDecoder>(this)),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
// Now safe to forget things
|
||||
mMPS = nullptr;
|
||||
mGMP = nullptr;
|
||||
mGMPThread = nullptr;
|
||||
mHost = nullptr;
|
||||
return WEBRTC_VIDEO_CODEC_OK;
|
||||
}
|
||||
|
||||
@ -799,17 +912,19 @@ void
|
||||
WebrtcGmpVideoDecoder::Terminated()
|
||||
{
|
||||
LOGD(("GMP Decoder Terminated: %p", (void *)this));
|
||||
mCachedPluginId = PluginID();
|
||||
|
||||
mGMP->Close();
|
||||
mGMP = nullptr;
|
||||
mHost = nullptr;
|
||||
mInitting = false;
|
||||
// Could now notify that it's dead
|
||||
}
|
||||
|
||||
void
|
||||
WebrtcGmpVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
|
||||
{
|
||||
if (mCallback) { // paranioa
|
||||
MutexAutoLock lock(mCallbackMutex);
|
||||
if (mCallback) {
|
||||
webrtc::I420VideoFrame image;
|
||||
int ret = image.CreateFrame(aDecodedFrame->AllocatedSize(kGMPYPlane),
|
||||
aDecodedFrame->Buffer(kGMPYPlane),
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
@ -50,77 +51,67 @@
|
||||
#include "GMPVideoDecoderProxy.h"
|
||||
#include "GMPVideoEncoderProxy.h"
|
||||
|
||||
#include "PeerConnectionImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebrtcGmpVideoEncoder : public WebrtcVideoEncoder,
|
||||
public GMPVideoEncoderCallbackProxy
|
||||
// Class that allows code on the other side of webrtc.org to tell
|
||||
// WebrtcGmpVideoEncoder/Decoder what PC they should send errors to.
|
||||
// This is necessary because webrtc.org gives us no way to plumb the handle
|
||||
// through, nor does it give us any way to inform it of an error that will
|
||||
// make it back to the PC that cares (except for errors encountered
|
||||
// synchronously in functions like InitEncode/Decode, which will not happen
|
||||
// because GMP init is async).
|
||||
// Right now, this is used in MediaPipelineFactory.
|
||||
class WebrtcGmpPCHandleSetter
|
||||
{
|
||||
public:
|
||||
WebrtcGmpVideoEncoder();
|
||||
virtual ~WebrtcGmpVideoEncoder();
|
||||
|
||||
// Implement VideoEncoder interface.
|
||||
virtual const uint64_t PluginID() override
|
||||
{
|
||||
return mGMP ? mGMP->GetPluginId() : mCachedPluginId;
|
||||
}
|
||||
|
||||
virtual void Terminated() override;
|
||||
|
||||
virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) override;
|
||||
|
||||
virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes) override;
|
||||
|
||||
virtual int32_t RegisterEncodeCompleteCallback(
|
||||
webrtc::EncodedImageCallback* aCallback) override;
|
||||
|
||||
virtual int32_t Release() override;
|
||||
|
||||
virtual int32_t SetChannelParameters(uint32_t aPacketLoss,
|
||||
int aRTT) override;
|
||||
|
||||
virtual int32_t SetRates(uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate) override;
|
||||
|
||||
// GMPVideoEncoderCallback virtual functions.
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo) override;
|
||||
|
||||
virtual void Error(GMPErr aError) override {
|
||||
}
|
||||
|
||||
private:
|
||||
class InitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
InitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mResult(WEBRTC_VIDEO_CODEC_OK),
|
||||
mThread(do_GetCurrentThread())
|
||||
explicit WebrtcGmpPCHandleSetter(const std::string& aPCHandle);
|
||||
|
||||
~WebrtcGmpPCHandleSetter();
|
||||
|
||||
static std::string GetCurrentHandle();
|
||||
|
||||
private:
|
||||
static std::string sCurrentHandle;
|
||||
};
|
||||
|
||||
class GmpInitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit GmpInitDoneRunnable(const std::string& aPCHandle) :
|
||||
mResult(WEBRTC_VIDEO_CODEC_OK),
|
||||
mPCHandle(aPCHandle)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(mThread == nsCOMPtr<nsIThread>(do_GetCurrentThread()));
|
||||
mInitDone = true;
|
||||
if (mResult == WEBRTC_VIDEO_CODEC_OK) {
|
||||
// Might be useful to notify the PeerConnection about successful init
|
||||
// someday.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PeerConnectionWrapper wrapper(mPCHandle);
|
||||
if (wrapper.impl()) {
|
||||
wrapper.impl()->OnMediaError(mError);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch(int32_t aResult)
|
||||
void Dispatch(int32_t aResult, const std::string& aError = "")
|
||||
{
|
||||
mResult = aResult;
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
mError = aError;
|
||||
nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
|
||||
if (mainThread) {
|
||||
// For some reason, the compiler on CI is treating |this| as a const
|
||||
// pointer, despite the fact that we're in a non-const function. And,
|
||||
// interestingly enough, correcting this doesn't require a const_cast.
|
||||
mainThread->Dispatch(do_AddRef(static_cast<nsIRunnable*>(this)),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Result()
|
||||
@ -129,69 +120,122 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
int32_t mResult;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
std::string mPCHandle;
|
||||
std::string mError;
|
||||
};
|
||||
|
||||
void InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize,
|
||||
InitDoneRunnable* aInitDone);
|
||||
class WebrtcGmpVideoEncoder : public GMPVideoEncoderCallbackProxy
|
||||
{
|
||||
public:
|
||||
WebrtcGmpVideoEncoder();
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoEncoder);
|
||||
|
||||
// Implement VideoEncoder interface, sort of.
|
||||
// (We cannot use |Release|, since that's needed for nsRefPtr)
|
||||
virtual const uint64_t PluginID()
|
||||
{
|
||||
return mCachedPluginId;
|
||||
}
|
||||
|
||||
virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize);
|
||||
|
||||
virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
|
||||
|
||||
virtual int32_t RegisterEncodeCompleteCallback(
|
||||
webrtc::EncodedImageCallback* aCallback);
|
||||
|
||||
virtual int32_t ReleaseGmp();
|
||||
|
||||
virtual int32_t SetChannelParameters(uint32_t aPacketLoss,
|
||||
int aRTT);
|
||||
|
||||
virtual int32_t SetRates(uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate);
|
||||
|
||||
// GMPVideoEncoderCallback virtual functions.
|
||||
virtual void Terminated() override;
|
||||
|
||||
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
|
||||
const nsTArray<uint8_t>& aCodecSpecificInfo) override;
|
||||
|
||||
virtual void Error(GMPErr aError) override {
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~WebrtcGmpVideoEncoder();
|
||||
|
||||
static void InitEncode_g(const nsRefPtr<WebrtcGmpVideoEncoder>& aThis,
|
||||
const GMPVideoCodec& aCodecParams,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone);
|
||||
int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
uint32_t aMaxPayloadSize);
|
||||
int32_t InitEncoderForSize(unsigned short aWidth, unsigned short aHeight);
|
||||
const GMPVideoCodec& aCodecParams,
|
||||
uint32_t aMaxPayloadSize,
|
||||
std::string* aErrorOut);
|
||||
int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
std::string* aErrorOut);
|
||||
int32_t InitEncoderForSize(unsigned short aWidth,
|
||||
unsigned short aHeight,
|
||||
std::string* aErrorOut);
|
||||
static void ReleaseGmp_g(nsRefPtr<WebrtcGmpVideoEncoder>& aEncoder);
|
||||
void Close_g();
|
||||
|
||||
class InitDoneCallback : public GetGMPVideoEncoderCallback
|
||||
{
|
||||
public:
|
||||
InitDoneCallback(WebrtcGmpVideoEncoder* aEncoder,
|
||||
InitDoneRunnable* aInitDone,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
InitDoneCallback(const nsRefPtr<WebrtcGmpVideoEncoder>& aEncoder,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone,
|
||||
const GMPVideoCodec& aCodecParams,
|
||||
uint32_t aMaxPayloadSize)
|
||||
: mEncoder(aEncoder),
|
||||
mInitDone(aInitDone),
|
||||
mCodecSettings(aCodecSettings),
|
||||
mCodecParams(aCodecParams),
|
||||
mMaxPayloadSize(aMaxPayloadSize)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
|
||||
{
|
||||
mEncoder->mGMP = aGMP;
|
||||
mEncoder->mHost = aHost;
|
||||
int32_t result;
|
||||
if (aGMP || aHost) {
|
||||
result = mEncoder->GmpInitDone(aGMP, aHost, mCodecSettings,
|
||||
mMaxPayloadSize);
|
||||
} else {
|
||||
result = WEBRTC_VIDEO_CODEC_ERROR;
|
||||
}
|
||||
std::string errorOut;
|
||||
int32_t result = mEncoder->GmpInitDone(aGMP,
|
||||
aHost,
|
||||
mCodecParams,
|
||||
mMaxPayloadSize,
|
||||
&errorOut);
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
mInitDone->Dispatch(result, errorOut);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoEncoder* mEncoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
const webrtc::VideoCodec* mCodecSettings;
|
||||
nsRefPtr<WebrtcGmpVideoEncoder> mEncoder;
|
||||
nsRefPtr<GmpInitDoneRunnable> mInitDone;
|
||||
GMPVideoCodec mCodecParams;
|
||||
uint32_t mMaxPayloadSize;
|
||||
};
|
||||
|
||||
int32_t Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
|
||||
void RegetEncoderForResolutionChange(const webrtc::I420VideoFrame* aInputImage,
|
||||
InitDoneRunnable* aInitDone);
|
||||
void RegetEncoderForResolutionChange(
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone);
|
||||
|
||||
class InitDoneForResolutionChangeCallback : public GetGMPVideoEncoderCallback
|
||||
{
|
||||
public:
|
||||
InitDoneForResolutionChangeCallback(WebrtcGmpVideoEncoder* aEncoder,
|
||||
InitDoneRunnable* aInitDone,
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight)
|
||||
InitDoneForResolutionChangeCallback(
|
||||
const nsRefPtr<WebrtcGmpVideoEncoder>& aEncoder,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone,
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight)
|
||||
: mEncoder(aEncoder),
|
||||
mInitDone(aInitDone),
|
||||
mWidth(aWidth),
|
||||
@ -201,66 +245,140 @@ private:
|
||||
|
||||
virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
|
||||
{
|
||||
mEncoder->mGMP = aGMP;
|
||||
mEncoder->mHost = aHost;
|
||||
int32_t result;
|
||||
if (aGMP && aHost) {
|
||||
result = mEncoder->InitEncoderForSize(mWidth, mHeight);
|
||||
} else {
|
||||
result = WEBRTC_VIDEO_CODEC_ERROR;
|
||||
std::string errorOut;
|
||||
int32_t result = mEncoder->GmpInitDone(aGMP, aHost, &errorOut);
|
||||
if (result != WEBRTC_VIDEO_CODEC_OK) {
|
||||
mInitDone->Dispatch(result, errorOut);
|
||||
return;
|
||||
}
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
result = mEncoder->InitEncoderForSize(mWidth, mHeight, &errorOut);
|
||||
mInitDone->Dispatch(result, errorOut);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoEncoder* mEncoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
nsRefPtr<WebrtcGmpVideoEncoder> mEncoder;
|
||||
nsRefPtr<GmpInitDoneRunnable> mInitDone;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
virtual int32_t SetRates_g(uint32_t aNewBitRate,
|
||||
static int32_t SetRates_g(nsRefPtr<WebrtcGmpVideoEncoder> aThis,
|
||||
uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate);
|
||||
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
GMPVideoEncoderProxy* mGMP;
|
||||
// Used to handle a race where Release() is called while init is in progress
|
||||
bool mInitting;
|
||||
GMPVideoHost* mHost;
|
||||
GMPVideoCodec mCodecParams;
|
||||
uint32_t mMaxPayloadSize;
|
||||
// Protects mCallback
|
||||
Mutex mCallbackMutex;
|
||||
webrtc::EncodedImageCallback* mCallback;
|
||||
uint64_t mCachedPluginId;
|
||||
std::string mPCHandle;
|
||||
};
|
||||
|
||||
|
||||
class WebrtcGmpVideoDecoder : public WebrtcVideoDecoder,
|
||||
public GMPVideoDecoderCallbackProxy
|
||||
// Basically a strong ref to a WebrtcGmpVideoEncoder, that also translates
|
||||
// from Release() to WebrtcGmpVideoEncoder::ReleaseGmp(), since we need
|
||||
// WebrtcGmpVideoEncoder::Release() for managing the refcount.
|
||||
// The webrtc.org code gets one of these, so it doesn't unilaterally delete
|
||||
// the "real" encoder.
|
||||
class WebrtcVideoEncoderProxy : public WebrtcVideoEncoder
|
||||
{
|
||||
public:
|
||||
WebrtcVideoEncoderProxy() :
|
||||
mEncoderImpl(new WebrtcGmpVideoEncoder)
|
||||
{}
|
||||
|
||||
virtual ~WebrtcVideoEncoderProxy()
|
||||
{
|
||||
RegisterEncodeCompleteCallback(nullptr);
|
||||
}
|
||||
|
||||
const uint64_t PluginID() override
|
||||
{
|
||||
return mEncoderImpl->PluginID();
|
||||
}
|
||||
|
||||
int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
uint32_t aMaxPayloadSize) override
|
||||
{
|
||||
return mEncoderImpl->InitEncode(aCodecSettings,
|
||||
aNumberOfCores,
|
||||
aMaxPayloadSize);
|
||||
}
|
||||
|
||||
int32_t Encode(
|
||||
const webrtc::I420VideoFrame& aInputImage,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
const std::vector<webrtc::VideoFrameType>* aFrameTypes) override
|
||||
{
|
||||
return mEncoderImpl->Encode(aInputImage,
|
||||
aCodecSpecificInfo,
|
||||
aFrameTypes);
|
||||
}
|
||||
|
||||
int32_t RegisterEncodeCompleteCallback(
|
||||
webrtc::EncodedImageCallback* aCallback) override
|
||||
{
|
||||
return mEncoderImpl->RegisterEncodeCompleteCallback(aCallback);
|
||||
}
|
||||
|
||||
int32_t Release() override
|
||||
{
|
||||
return mEncoderImpl->ReleaseGmp();
|
||||
}
|
||||
|
||||
int32_t SetChannelParameters(uint32_t aPacketLoss,
|
||||
int aRTT) override
|
||||
{
|
||||
return mEncoderImpl->SetChannelParameters(aPacketLoss, aRTT);
|
||||
}
|
||||
|
||||
int32_t SetRates(uint32_t aNewBitRate,
|
||||
uint32_t aFrameRate) override
|
||||
{
|
||||
return mEncoderImpl->SetRates(aNewBitRate, aFrameRate);
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<WebrtcGmpVideoEncoder> mEncoderImpl;
|
||||
};
|
||||
|
||||
class WebrtcGmpVideoDecoder : public GMPVideoDecoderCallbackProxy
|
||||
{
|
||||
public:
|
||||
WebrtcGmpVideoDecoder();
|
||||
virtual ~WebrtcGmpVideoDecoder();
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoDecoder);
|
||||
|
||||
// Implement VideoDecoder interface.
|
||||
virtual const uint64_t PluginID() override
|
||||
// Implement VideoEncoder interface, sort of.
|
||||
// (We cannot use |Release|, since that's needed for nsRefPtr)
|
||||
virtual const uint64_t PluginID()
|
||||
{
|
||||
return mGMP ? mGMP->GetPluginId() : mCachedPluginId;
|
||||
return mCachedPluginId;
|
||||
}
|
||||
|
||||
virtual void Terminated() override;
|
||||
|
||||
virtual int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores) override;
|
||||
int32_t aNumberOfCores);
|
||||
virtual int32_t Decode(const webrtc::EncodedImage& aInputImage,
|
||||
bool aMissingFrames,
|
||||
const webrtc::RTPFragmentationHeader* aFragmentation,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo = nullptr,
|
||||
int64_t aRenderTimeMs = -1) override;
|
||||
virtual int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback) override;
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs);
|
||||
virtual int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback);
|
||||
|
||||
virtual int32_t Release() override;
|
||||
virtual int32_t ReleaseGmp();
|
||||
|
||||
virtual int32_t Reset() override;
|
||||
virtual int32_t Reset();
|
||||
|
||||
// GMPVideoDecoderCallbackProxy
|
||||
virtual void Terminated() override;
|
||||
|
||||
virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override;
|
||||
|
||||
@ -286,56 +404,24 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
class InitDoneRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
InitDoneRunnable()
|
||||
: mInitDone(false),
|
||||
mResult(WEBRTC_VIDEO_CODEC_OK),
|
||||
mThread(do_GetCurrentThread())
|
||||
{
|
||||
}
|
||||
virtual ~WebrtcGmpVideoDecoder();
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(mThread == nsCOMPtr<nsIThread>(do_GetCurrentThread()));
|
||||
mInitDone = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch(int32_t aResult)
|
||||
{
|
||||
mResult = aResult;
|
||||
mThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
bool IsDone()
|
||||
{
|
||||
MOZ_ASSERT(nsCOMPtr<nsIThread>(do_GetCurrentThread()) == mThread);
|
||||
return mInitDone;
|
||||
}
|
||||
|
||||
int32_t Result()
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mInitDone;
|
||||
int32_t mResult;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
void InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
InitDoneRunnable* aInitDone);
|
||||
int32_t GmpInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost);
|
||||
static void InitDecode_g(
|
||||
const nsRefPtr<WebrtcGmpVideoDecoder>& aThis,
|
||||
const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores,
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone);
|
||||
int32_t GmpInitDone(GMPVideoDecoderProxy* aGMP,
|
||||
GMPVideoHost* aHost,
|
||||
std::string* aErrorOut);
|
||||
static void ReleaseGmp_g(nsRefPtr<WebrtcGmpVideoDecoder>& aDecoder);
|
||||
void Close_g();
|
||||
|
||||
class InitDoneCallback : public GetGMPVideoDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit InitDoneCallback(WebrtcGmpVideoDecoder* aDecoder,
|
||||
InitDoneRunnable* aInitDone)
|
||||
const nsRefPtr<GmpInitDoneRunnable>& aInitDone)
|
||||
: mDecoder(aDecoder),
|
||||
mInitDone(aInitDone)
|
||||
{
|
||||
@ -343,15 +429,16 @@ private:
|
||||
|
||||
virtual void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
|
||||
{
|
||||
int32_t result = mDecoder->GmpInitDone(aGMP, aHost);
|
||||
std::string errorOut;
|
||||
int32_t result = mDecoder->GmpInitDone(aGMP, aHost, &errorOut);
|
||||
|
||||
mInitDone->Dispatch(result);
|
||||
mInitDone->Dispatch(result, errorOut);
|
||||
}
|
||||
|
||||
private:
|
||||
WebrtcGmpVideoDecoder* mDecoder;
|
||||
nsRefPtr<InitDoneRunnable> mInitDone;
|
||||
};
|
||||
nsRefPtr<GmpInitDoneRunnable> mInitDone;
|
||||
};
|
||||
|
||||
virtual int32_t Decode_g(const webrtc::EncodedImage& aInputImage,
|
||||
bool aMissingFrames,
|
||||
@ -362,10 +449,77 @@ private:
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
GMPVideoDecoderProxy* mGMP; // Addref is held for us
|
||||
// Used to handle a race where Release() is called while init is in progress
|
||||
bool mInitting;
|
||||
GMPVideoHost* mHost;
|
||||
// Protects mCallback
|
||||
Mutex mCallbackMutex;
|
||||
webrtc::DecodedImageCallback* mCallback;
|
||||
uint64_t mCachedPluginId;
|
||||
Atomic<uint64_t> mCachedPluginId;
|
||||
GMPErr mDecoderStatus;
|
||||
std::string mPCHandle;
|
||||
};
|
||||
|
||||
// Basically a strong ref to a WebrtcGmpVideoDecoder, that also translates
|
||||
// from Release() to WebrtcGmpVideoDecoder::ReleaseGmp(), since we need
|
||||
// WebrtcGmpVideoDecoder::Release() for managing the refcount.
|
||||
// The webrtc.org code gets one of these, so it doesn't unilaterally delete
|
||||
// the "real" encoder.
|
||||
class WebrtcVideoDecoderProxy : public WebrtcVideoDecoder
|
||||
{
|
||||
public:
|
||||
WebrtcVideoDecoderProxy() :
|
||||
mDecoderImpl(new WebrtcGmpVideoDecoder)
|
||||
{}
|
||||
|
||||
virtual ~WebrtcVideoDecoderProxy()
|
||||
{
|
||||
RegisterDecodeCompleteCallback(nullptr);
|
||||
}
|
||||
|
||||
const uint64_t PluginID() override
|
||||
{
|
||||
return mDecoderImpl->PluginID();
|
||||
}
|
||||
|
||||
int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
|
||||
int32_t aNumberOfCores) override
|
||||
{
|
||||
return mDecoderImpl->InitDecode(aCodecSettings, aNumberOfCores);
|
||||
}
|
||||
|
||||
int32_t Decode(
|
||||
const webrtc::EncodedImage& aInputImage,
|
||||
bool aMissingFrames,
|
||||
const webrtc::RTPFragmentationHeader* aFragmentation,
|
||||
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
|
||||
int64_t aRenderTimeMs) override
|
||||
{
|
||||
return mDecoderImpl->Decode(aInputImage,
|
||||
aMissingFrames,
|
||||
aFragmentation,
|
||||
aCodecSpecificInfo,
|
||||
aRenderTimeMs);
|
||||
}
|
||||
|
||||
int32_t RegisterDecodeCompleteCallback(
|
||||
webrtc::DecodedImageCallback* aCallback) override
|
||||
{
|
||||
return mDecoderImpl->RegisterDecodeCompleteCallback(aCallback);
|
||||
}
|
||||
|
||||
int32_t Release() override
|
||||
{
|
||||
return mDecoderImpl->ReleaseGmp();
|
||||
}
|
||||
|
||||
int32_t Reset() override
|
||||
{
|
||||
return mDecoderImpl->Reset();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<WebrtcGmpVideoDecoder> mDecoderImpl;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,10 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#endif
|
||||
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
#include "WebrtcGmpVideoCodec.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace mozilla {
|
||||
@ -315,6 +319,14 @@ MediaPipelineFactory::CreateOrUpdateMediaPipeline(
|
||||
const JsepTrackPair& aTrackPair,
|
||||
const JsepTrack& aTrack)
|
||||
{
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
// The GMP code is all the way on the other side of webrtc.org, and it is not
|
||||
// feasible to plumb this information all the way through. So, we set it (for
|
||||
// the duration of this call) in a global variable. This allows the GMP code
|
||||
// to report errors to the PC.
|
||||
WebrtcGmpPCHandleSetter setter(mPC->GetHandle());
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(aTrackPair.mRtpTransport);
|
||||
|
||||
bool receiving =
|
||||
|
@ -2030,6 +2030,13 @@ PeerConnectionImpl::GetStreamId(const DOMMediaStream& aStream)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
PeerConnectionImpl::OnMediaError(const std::string& aError)
|
||||
{
|
||||
CSFLogError(logTag, "Encountered media error! %s", aError.c_str());
|
||||
// TODO: Let content know about this somehow.
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
|
||||
const Sequence<OwningNonNull<DOMMediaStream>>& aStreams)
|
||||
|
@ -618,6 +618,8 @@ public:
|
||||
static std::string GetStreamId(const DOMMediaStream& aStream);
|
||||
static std::string GetTrackId(const dom::MediaStreamTrack& track);
|
||||
|
||||
void OnMediaError(const std::string& aError);
|
||||
|
||||
private:
|
||||
virtual ~PeerConnectionImpl();
|
||||
PeerConnectionImpl(const PeerConnectionImpl&rhs);
|
||||
|
Loading…
Reference in New Issue
Block a user