summaryrefslogtreecommitdiffstats
path: root/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h')
-rw-r--r--media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h528
1 files changed, 528 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
new file mode 100644
index 000000000..0c01bf53c
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.h
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2012, The WebRTC project authors. All rights reserved.
+ *
+ * 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 WEBRTCGMPVIDEOCODEC_H_
+#define WEBRTCGMPVIDEOCODEC_H_
+
+#include <iostream>
+#include <queue>
+#include <string>
+
+#include "nsThreadUtils.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/Mutex.h"
+
+#include "mozIGeckoMediaPluginService.h"
+#include "MediaConduitInterface.h"
+#include "AudioConduit.h"
+#include "VideoConduit.h"
+#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
+
+#include "gmp-video-host.h"
+#include "GMPVideoDecoderProxy.h"
+#include "GMPVideoEncoderProxy.h"
+
+#include "PeerConnectionImpl.h"
+
+namespace mozilla {
+
+// 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:
+ explicit WebrtcGmpPCHandleSetter(const std::string& aPCHandle);
+
+ ~WebrtcGmpPCHandleSetter();
+
+ static std::string GetCurrentHandle();
+
+ private:
+ static std::string sCurrentHandle;
+};
+
+class GmpInitDoneRunnable : public Runnable
+{
+ public:
+ explicit GmpInitDoneRunnable(const std::string& aPCHandle) :
+ mResult(WEBRTC_VIDEO_CODEC_OK),
+ mPCHandle(aPCHandle)
+ {
+ }
+
+ NS_IMETHOD Run() override
+ {
+ 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, const std::string& aError = "")
+ {
+ mResult = aResult;
+ 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()
+ {
+ return mResult;
+ }
+
+ private:
+ int32_t mResult;
+ std::string mPCHandle;
+ std::string mError;
+};
+
+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 uint64_t PluginID() const
+ {
+ 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 RefPtr<WebrtcGmpVideoEncoder>& aThis,
+ const GMPVideoCodec& aCodecParams,
+ int32_t aNumberOfCores,
+ uint32_t aMaxPayloadSize,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone);
+ int32_t GmpInitDone(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost,
+ 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(RefPtr<WebrtcGmpVideoEncoder>& aEncoder);
+ void Close_g();
+
+ class InitDoneCallback : public GetGMPVideoEncoderCallback
+ {
+ public:
+ InitDoneCallback(const RefPtr<WebrtcGmpVideoEncoder>& aEncoder,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone,
+ const GMPVideoCodec& aCodecParams,
+ uint32_t aMaxPayloadSize)
+ : mEncoder(aEncoder),
+ mInitDone(aInitDone),
+ mCodecParams(aCodecParams),
+ mMaxPayloadSize(aMaxPayloadSize)
+ {
+ }
+
+ virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
+ {
+ std::string errorOut;
+ int32_t result = mEncoder->GmpInitDone(aGMP,
+ aHost,
+ mCodecParams,
+ mMaxPayloadSize,
+ &errorOut);
+
+ mInitDone->Dispatch(result, errorOut);
+ }
+
+ private:
+ RefPtr<WebrtcGmpVideoEncoder> mEncoder;
+ RefPtr<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(
+ uint32_t aWidth,
+ uint32_t aHeight,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone);
+
+ class InitDoneForResolutionChangeCallback : public GetGMPVideoEncoderCallback
+ {
+ public:
+ InitDoneForResolutionChangeCallback(
+ const RefPtr<WebrtcGmpVideoEncoder>& aEncoder,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone,
+ uint32_t aWidth,
+ uint32_t aHeight)
+ : mEncoder(aEncoder),
+ mInitDone(aInitDone),
+ mWidth(aWidth),
+ mHeight(aHeight)
+ {
+ }
+
+ virtual void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override
+ {
+ std::string errorOut;
+ int32_t result = mEncoder->GmpInitDone(aGMP, aHost, &errorOut);
+ if (result != WEBRTC_VIDEO_CODEC_OK) {
+ mInitDone->Dispatch(result, errorOut);
+ return;
+ }
+
+ result = mEncoder->InitEncoderForSize(mWidth, mHeight, &errorOut);
+ mInitDone->Dispatch(result, errorOut);
+ }
+
+ private:
+ RefPtr<WebrtcGmpVideoEncoder> mEncoder;
+ RefPtr<GmpInitDoneRunnable> mInitDone;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ };
+
+ static int32_t SetRates_g(RefPtr<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;
+ webrtc::CodecSpecificInfo mCodecSpecificInfo;
+ // Protects mCallback
+ Mutex mCallbackMutex;
+ webrtc::EncodedImageCallback* mCallback;
+ uint64_t mCachedPluginId;
+ std::string mPCHandle;
+};
+
+
+// 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);
+ }
+
+ uint64_t PluginID() const override
+ {
+ return mEncoderImpl->PluginID();
+ }
+
+ int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
+ int32_t aNumberOfCores,
+ size_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,
+ int64_t aRTT) override
+ {
+ return mEncoderImpl->SetChannelParameters(aPacketLoss, aRTT);
+ }
+
+ int32_t SetRates(uint32_t aNewBitRate,
+ uint32_t aFrameRate) override
+ {
+ return mEncoderImpl->SetRates(aNewBitRate, aFrameRate);
+ }
+
+ private:
+ RefPtr<WebrtcGmpVideoEncoder> mEncoderImpl;
+};
+
+class WebrtcGmpVideoDecoder : public GMPVideoDecoderCallbackProxy
+{
+public:
+ WebrtcGmpVideoDecoder();
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoDecoder);
+
+ // Implement VideoEncoder interface, sort of.
+ // (We cannot use |Release|, since that's needed for nsRefPtr)
+ virtual uint64_t PluginID() const
+ {
+ return mCachedPluginId;
+ }
+
+ virtual int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
+ int32_t aNumberOfCores);
+ virtual int32_t Decode(const webrtc::EncodedImage& aInputImage,
+ bool aMissingFrames,
+ const webrtc::RTPFragmentationHeader* aFragmentation,
+ const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
+ int64_t aRenderTimeMs);
+ virtual int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback);
+
+ virtual int32_t ReleaseGmp();
+
+ virtual int32_t Reset();
+
+ // GMPVideoDecoderCallbackProxy
+ virtual void Terminated() override;
+
+ virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) override;
+
+ virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override {
+ MOZ_CRASH();
+ }
+
+ virtual void ReceivedDecodedFrame(const uint64_t aPictureId) override {
+ MOZ_CRASH();
+ }
+
+ virtual void InputDataExhausted() override {
+ }
+
+ virtual void DrainComplete() override {
+ }
+
+ virtual void ResetComplete() override {
+ }
+
+ virtual void Error(GMPErr aError) override {
+ mDecoderStatus = aError;
+ }
+
+private:
+ virtual ~WebrtcGmpVideoDecoder();
+
+ static void InitDecode_g(
+ const RefPtr<WebrtcGmpVideoDecoder>& aThis,
+ const webrtc::VideoCodec* aCodecSettings,
+ int32_t aNumberOfCores,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone);
+ int32_t GmpInitDone(GMPVideoDecoderProxy* aGMP,
+ GMPVideoHost* aHost,
+ std::string* aErrorOut);
+ static void ReleaseGmp_g(RefPtr<WebrtcGmpVideoDecoder>& aDecoder);
+ void Close_g();
+
+ class InitDoneCallback : public GetGMPVideoDecoderCallback
+ {
+ public:
+ explicit InitDoneCallback(const RefPtr<WebrtcGmpVideoDecoder>& aDecoder,
+ const RefPtr<GmpInitDoneRunnable>& aInitDone)
+ : mDecoder(aDecoder),
+ mInitDone(aInitDone)
+ {
+ }
+
+ virtual void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost)
+ {
+ std::string errorOut;
+ int32_t result = mDecoder->GmpInitDone(aGMP, aHost, &errorOut);
+
+ mInitDone->Dispatch(result, errorOut);
+ }
+
+ private:
+ RefPtr<WebrtcGmpVideoDecoder> mDecoder;
+ RefPtr<GmpInitDoneRunnable> mInitDone;
+ };
+
+ virtual int32_t Decode_g(const webrtc::EncodedImage& aInputImage,
+ bool aMissingFrames,
+ const webrtc::RTPFragmentationHeader* aFragmentation,
+ const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
+ int64_t aRenderTimeMs);
+
+ nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
+ 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;
+ 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);
+ }
+
+ uint64_t PluginID() const 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:
+ RefPtr<WebrtcGmpVideoDecoder> mDecoderImpl;
+};
+
+}
+
+#endif