deleted file mode 100644
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
+++ /dev/null
@@ -1,1253 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "CSFLog.h"
-
-#include "WebrtcOMXH264VideoCodec.h"
-
-// Android/Stagefright
-#include <avc_utils.h>
-#include <binder/ProcessState.h>
-#include <foundation/ABuffer.h>
-#include <foundation/AMessage.h>
-#include <gui/Surface.h>
-#include <media/ICrypto.h>
-#include <media/stagefright/MediaCodec.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <OMX_Component.h>
-using namespace android;
-
-// WebRTC
-//#include "webrtc/common_video/interface/texture_video_frame.h"
-#include "webrtc/video_engine/include/vie_external_codec.h"
-#include "runnable_utils.h"
-
-// Gecko
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
-#include "GonkBufferQueueProducer.h"
-#endif
-#include "GonkNativeWindow.h"
-#include "GrallocImages.h"
-#include "mozilla/Atomics.h"
-#include "mozilla/Mutex.h"
-#include "nsThreadUtils.h"
-#include "OMXCodecWrapper.h"
-#include "TextureClient.h"
-#include "mozilla/IntegerPrintfMacros.h"
-
-#define DEQUEUE_BUFFER_TIMEOUT_US (100 * 1000ll) // 100ms.
-#define START_DEQUEUE_BUFFER_TIMEOUT_US (10 * DEQUEUE_BUFFER_TIMEOUT_US) // 1s.
-#define DRAIN_THREAD_TIMEOUT_US (1000 * 1000ll) // 1s.
-
-#define WOHVC_LOG_TAG "WebrtcOMXH264VideoCodec"
-#define CODEC_LOGV(...) CSFLogInfo(WOHVC_LOG_TAG, __VA_ARGS__)
-#define CODEC_LOGD(...) CSFLogDebug(WOHVC_LOG_TAG, __VA_ARGS__)
-#define CODEC_LOGI(...) CSFLogInfo(WOHVC_LOG_TAG, __VA_ARGS__)
-#define CODEC_LOGW(...) CSFLogWarn(WOHVC_LOG_TAG, __VA_ARGS__)
-#define CODEC_LOGE(...) CSFLogError(WOHVC_LOG_TAG, __VA_ARGS__)
-
-namespace mozilla {
-
-static const uint8_t kNALStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
-enum {
- kNALTypeIDR = 5,
- kNALTypeSPS = 7,
- kNALTypePPS = 8,
-};
-
-// NS_INLINE_DECL_THREADSAFE_REFCOUNTING() cannot be used directly in
-// ImageNativeHandle below because the return type of webrtc::NativeHandle
-// AddRef()/Release() conflicts with those defined in macro. To avoid another
-// copy/paste of ref-counting implementation here, this dummy base class
-// is created to proivde another level of indirection.
-class DummyRefCountBase {
-public:
- // Use the name of real class for logging.
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DummyRefCountBase)
-protected:
- // To make sure subclass will be deleted/destructed properly.
- virtual ~DummyRefCountBase() {}
-};
-
-// This function implements 2 interafces:
-// 1. webrtc::NativeHandle: to wrap layers::Image object so decoded frames can
-// be passed through WebRTC rendering pipeline using TextureVideoFrame.
-// 2. ImageHandle: for renderer to get the image object inside without knowledge
-// about webrtc::NativeHandle.
-class ImageNativeHandle final
- : public webrtc::NativeHandle
- , public DummyRefCountBase
-{
-public:
- ImageNativeHandle(layers::Image* aImage)
- : mImage(aImage)
- {}
-
- // Implement webrtc::NativeHandle.
- virtual void* GetHandle() override { return mImage.get(); }
-
- virtual int AddRef() override
- {
- return DummyRefCountBase::AddRef();
- }
-
- virtual int Release() override
- {
- return DummyRefCountBase::Release();
- }
-
-private:
- RefPtr<layers::Image> mImage;
-};
-
-struct EncodedFrame
-{
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mTimestamp;
- int64_t mRenderTimeMs;
-};
-
-static void
-ShutdownThread(nsCOMPtr<nsIThread>& aThread)
-{
- aThread->Shutdown();
-}
-
-// Base runnable class to repeatly pull OMX output buffers in seperate thread.
-// How to use:
-// - implementing DrainOutput() to get output. Remember to return false to tell
-// drain not to pop input queue.
-// - call QueueInput() to schedule a run to drain output. The input, aFrame,
-// should contains corresponding info such as image size and timestamps for
-// DrainOutput() implementation to construct data needed by encoded/decoded
-// callbacks.
-// TODO: Bug 997110 - Revisit queue/drain logic. Current design assumes that
-// encoder only generate one output buffer per input frame and won't work
-// if encoder drops frames or generates multiple output per input.
-class OMXOutputDrain : public Runnable
-{
-public:
- void Start() {
- CODEC_LOGD("OMXOutputDrain starting");
- MonitorAutoLock lock(mMonitor);
- if (mThread == nullptr) {
- NS_NewNamedThread("OMXOutputDrain", getter_AddRefs(mThread));
- }
- CODEC_LOGD("OMXOutputDrain started");
- mEnding = false;
- mThread->Dispatch(this, NS_DISPATCH_NORMAL);
- }
-
- void Stop() {
- CODEC_LOGD("OMXOutputDrain stopping");
- MonitorAutoLock lock(mMonitor);
- mEnding = true;
- lock.NotifyAll(); // In case Run() is waiting.
-
- if (mThread != nullptr) {
- MonitorAutoUnlock unlock(mMonitor);
- CODEC_LOGD("OMXOutputDrain thread shutdown");
- NS_DispatchToMainThread(
- WrapRunnableNM<decltype(&ShutdownThread),
- nsCOMPtr<nsIThread> >(&ShutdownThread, mThread));
- mThread = nullptr;
- }
- CODEC_LOGD("OMXOutputDrain stopped");
- }
-
- void QueueInput(const EncodedFrame& aFrame)
- {
- MonitorAutoLock lock(mMonitor);
-
- MOZ_ASSERT(mThread);
-
- mInputFrames.push(aFrame);
- // Notify Run() about queued input and it can start working.
- lock.NotifyAll();
- }
-
- NS_IMETHOD Run() override
- {
- MonitorAutoLock lock(mMonitor);
- if (mEnding) {
- return NS_OK;
- }
- MOZ_ASSERT(mThread);
-
- while (true) {
- if (mInputFrames.empty()) {
- // Wait for new input.
- lock.Wait();
- }
-
- if (mEnding) {
- CODEC_LOGD("OMXOutputDrain Run() ending");
- // Stop draining.
- break;
- }
-
- MOZ_ASSERT(!mInputFrames.empty());
- {
- // Release monitor while draining because it's blocking.
- MonitorAutoUnlock unlock(mMonitor);
- DrainOutput();
- }
- }
-
- CODEC_LOGD("OMXOutputDrain Ended");
- return NS_OK;
- }
-
-protected:
- OMXOutputDrain()
- : mMonitor("OMXOutputDrain monitor")
- , mEnding(false)
- {}
-
- // Drain output buffer for input frame queue mInputFrames.
- // mInputFrames contains info such as size and time of the input frames.
- // We have to give a queue to handle encoder frame skips - we can input 10
- // frames and get one back. NOTE: any access of aInputFrames MUST be preceded
- // locking mMonitor!
-
- // Blocks waiting for decoded buffers, but for a limited period because
- // we need to check for shutdown.
- virtual bool DrainOutput() = 0;
-
-protected:
- // This monitor protects all things below it, and is also used to
- // wait/notify queued input.
- Monitor mMonitor;
- std::queue<EncodedFrame> mInputFrames;
-
-private:
- // also protected by mMonitor
- nsCOMPtr<nsIThread> mThread;
- bool mEnding;
-};
-
-// Assumption: SPS is first paramset or is not present
-static bool IsParamSets(uint8_t* aData, size_t aSize)
-{
- MOZ_ASSERT(aData && aSize > sizeof(kNALStartCode));
- return (aData[sizeof(kNALStartCode)] & 0x1f) == kNALTypeSPS;
-}
-
-// get the length of any pre-pended SPS/PPS's
-static size_t ParamSetLength(uint8_t* aData, size_t aSize)
-{
- const uint8_t* data = aData;
- size_t size = aSize;
- const uint8_t* nalStart = nullptr;
- size_t nalSize = 0;
- while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
- if ((*nalStart & 0x1f) != kNALTypeSPS &&
- (*nalStart & 0x1f) != kNALTypePPS) {
- MOZ_ASSERT(nalStart - sizeof(kNALStartCode) >= aData);
- return (nalStart - sizeof(kNALStartCode)) - aData; // SPS/PPS/iframe
- }
- }
- return aSize; // it's only SPS/PPS
-}
-
-// H.264 decoder using stagefright.
-// It implements gonk native window callback to receive buffers from
-// MediaCodec::RenderOutputBufferAndRelease().
-class WebrtcOMXDecoder final : public GonkNativeWindowNewFrameCallback
-{
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcOMXDecoder)
-
-private:
- virtual ~WebrtcOMXDecoder()
- {
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p OMX destructor", this);
- if (mStarted) {
- Stop();
- }
- if (mCodec != nullptr) {
- mCodec->release();
- mCodec.clear();
- }
- mLooper.clear();
- }
-
-public:
- WebrtcOMXDecoder(const char* aMimeType,
- webrtc::DecodedImageCallback* aCallback)
- : mWidth(0)
- , mHeight(0)
- , mStarted(false)
- , mCallback(aCallback)
- , mDecodedFrameLock("WebRTC decoded frame lock")
- , mEnding(false)
- {
- // Create binder thread pool required by stagefright.
- android::ProcessState::self()->startThreadPool();
-
- mLooper = new ALooper;
- mLooper->start();
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p creating decoder", this);
- mCodec = MediaCodec::CreateByType(mLooper, aMimeType, false /* encoder */);
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p OMX created", this);
- }
-
- // Find SPS in input data and extract picture width and height if found.
- static status_t ExtractPicDimensions(uint8_t* aData, size_t aSize,
- int32_t* aWidth, int32_t* aHeight)
- {
- MOZ_ASSERT(aData && aSize > sizeof(kNALStartCode));
- if ((aData[sizeof(kNALStartCode)] & 0x1f) != kNALTypeSPS) {
- return ERROR_MALFORMED;
- }
- sp<ABuffer> sps = new ABuffer(&aData[sizeof(kNALStartCode)], aSize - sizeof(kNALStartCode));
- FindAVCDimensions(sps, aWidth, aHeight);
- return OK;
- }
-
- // Configure decoder using image width/height.
- status_t ConfigureWithPicDimensions(int32_t aWidth, int32_t aHeight)
- {
- MOZ_ASSERT(mCodec != nullptr);
- if (mCodec == nullptr) {
- return INVALID_OPERATION;
- }
-
- CODEC_LOGD("OMX:%p decoder width:%d height:%d", this, aWidth, aHeight);
-
- sp<AMessage> config = new AMessage();
- config->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
- config->setInt32("width", aWidth);
- config->setInt32("height", aHeight);
- mWidth = aWidth;
- mHeight = aHeight;
-
- sp<Surface> surface = nullptr;
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
- sp<IGraphicBufferProducer> producer;
- sp<IGonkGraphicBufferConsumer> consumer;
- GonkBufferQueue::createBufferQueue(&producer, &consumer);
- mNativeWindow = new GonkNativeWindow(consumer);
-#else
- mNativeWindow = new GonkNativeWindow();
-#endif
- if (mNativeWindow.get()) {
- // listen to buffers queued by MediaCodec::RenderOutputBufferAndRelease().
- mNativeWindow->setNewFrameCallback(this);
- // XXX remove buffer changes after a better solution lands - bug 1009420
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
- static_cast<GonkBufferQueueProducer*>(producer.get())->setSynchronousMode(false);
- // More spare buffers to avoid OMX decoder waiting for native window
- consumer->setMaxAcquiredBufferCount(WEBRTC_OMX_H264_MIN_DECODE_BUFFERS);
- surface = new Surface(producer);
-#else
- sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
- bq->setSynchronousMode(false);
- // More spare buffers to avoid OMX decoder waiting for native window
- bq->setMaxAcquiredBufferCount(WEBRTC_OMX_H264_MIN_DECODE_BUFFERS);
- surface = new Surface(bq);
-#endif
- }
- status_t result = mCodec->configure(config, surface, nullptr, 0);
- if (result == OK) {
- CODEC_LOGD("OMX:%p decoder configured", this);
- result = Start();
- }
- return result;
- }
-
- status_t
- FillInput(const webrtc::EncodedImage& aEncoded, bool aIsFirstFrame,
- int64_t& aRenderTimeMs)
- {
- MOZ_ASSERT(mCodec != nullptr && aEncoded._buffer && aEncoded._length > 0);
- if (mCodec == nullptr || !aEncoded._buffer || aEncoded._length == 0) {
- return INVALID_OPERATION;
- }
-
- // Break input encoded data into NALUs and send each one to decode.
- // 8x10 decoder doesn't allow picture coding NALs to be in the same buffer
- // with SPS/PPS (BUFFER_FLAG_CODECCONFIG) per QC
- const uint8_t* data = aEncoded._buffer;
- size_t size = aEncoded._length;
- const uint8_t* nalStart = nullptr;
- size_t nalSize = 0;
- status_t err = OK;
-
- // this returns a pointer to the NAL byte (after the StartCode)
- while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
- // Individual NALU inherits metadata from input encoded data.
- webrtc::EncodedImage nalu(aEncoded);
-
- nalu._buffer = const_cast<uint8_t*>(nalStart) - sizeof(kNALStartCode);
- MOZ_ASSERT(nalu._buffer >= aEncoded._buffer);
- nalu._length = nalSize + sizeof(kNALStartCode);
- MOZ_ASSERT(nalu._buffer + nalu._length <= aEncoded._buffer + aEncoded._length);
-
- size_t index;
- err = mCodec->dequeueInputBuffer(&index,
- aIsFirstFrame ? START_DEQUEUE_BUFFER_TIMEOUT_US : DEQUEUE_BUFFER_TIMEOUT_US);
- if (err != OK) {
- if (err != -EAGAIN) {
- CODEC_LOGE("decode dequeue input buffer error:%d", err);
- } else {
- CODEC_LOGE("decode dequeue 100ms without a buffer (EAGAIN)");
- }
- return err;
- }
-
- // Prepend start code to buffer.
- MOZ_ASSERT(memcmp(nalu._buffer, kNALStartCode, sizeof(kNALStartCode)) == 0);
- const sp<ABuffer>& omxIn = mInputBuffers.itemAt(index);
- MOZ_ASSERT(omxIn->capacity() >= nalu._length);
- omxIn->setRange(0, nalu._length);
- // Copying is needed because MediaCodec API doesn't support externally
- // allocated buffer as input.
- uint8_t* dst = omxIn->data();
- memcpy(dst, nalu._buffer, nalu._length);
- int64_t inputTimeUs = (nalu._timeStamp * 1000ll) / 90; // 90kHz -> us.
- // Assign input flags according to input buffer NALU and frame types.
- uint32_t flags;
- int nalType = dst[sizeof(kNALStartCode)] & 0x1f;
- switch (nalType) {
- case kNALTypeSPS:
- case kNALTypePPS:
- flags = MediaCodec::BUFFER_FLAG_CODECCONFIG;
- break;
- case kNALTypeIDR:
- flags = MediaCodec::BUFFER_FLAG_SYNCFRAME;
- break;
- default:
- flags = 0;
- break;
- }
- CODEC_LOGD("Decoder input: %d bytes (NAL 0x%02x), time %lld (%u), flags 0x%x",
- nalu._length, dst[sizeof(kNALStartCode)], inputTimeUs, nalu._timeStamp, flags);
- err = mCodec->queueInputBuffer(index, 0, nalu._length, inputTimeUs, flags);
- if (err == OK && !(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
- if (mOutputDrain == nullptr) {
- mOutputDrain = new OutputDrain(this);
- mOutputDrain->Start();
- }
- EncodedFrame frame;
- frame.mWidth = mWidth;
- frame.mHeight = mHeight;
- frame.mTimestamp = nalu._timeStamp;
- frame.mRenderTimeMs = aRenderTimeMs;
- mOutputDrain->QueueInput(frame);
- }
- }
-
- return err;
- }
-
- status_t
- DrainOutput(std::queue<EncodedFrame>& aInputFrames, Monitor& aMonitor)
- {
- MOZ_ASSERT(mCodec != nullptr);
- if (mCodec == nullptr) {
- return INVALID_OPERATION;
- }
-
- size_t index = 0;
- size_t outOffset = 0;
- size_t outSize = 0;
- int64_t outTime = -1ll;
- uint32_t outFlags = 0;
- status_t err = mCodec->dequeueOutputBuffer(&index, &outOffset, &outSize,
- &outTime, &outFlags,
- DRAIN_THREAD_TIMEOUT_US);
- switch (err) {
- case OK:
- break;
- case -EAGAIN:
- // Not an error: output not available yet. Try later.
- CODEC_LOGI("decode dequeue OMX output buffer timed out. Try later.");
- return err;
- case INFO_FORMAT_CHANGED:
- // Not an error: will get this value when OMX output buffer is enabled,
- // or when input size changed.
- CODEC_LOGD("decode dequeue OMX output buffer format change");
- return err;
- case INFO_OUTPUT_BUFFERS_CHANGED:
- // Not an error: will get this value when OMX output buffer changed
- // (probably because of input size change).
- CODEC_LOGD("decode dequeue OMX output buffer change");
- err = mCodec->getOutputBuffers(&mOutputBuffers);
- MOZ_ASSERT(err == OK);
- return INFO_OUTPUT_BUFFERS_CHANGED;
- default:
- CODEC_LOGE("decode dequeue OMX output buffer error:%d", err);
- // Return OK to instruct OutputDrain to drop input from queue.
- MonitorAutoLock lock(aMonitor);
- aInputFrames.pop();
- return OK;
- }
-
- CODEC_LOGD("Decoder output: %d bytes, offset %u, time %lld, flags 0x%x",
- outSize, outOffset, outTime, outFlags);
- if (mCallback) {
- EncodedFrame frame;
- {
- MonitorAutoLock lock(aMonitor);
- frame = aInputFrames.front();
- aInputFrames.pop();
- }
- {
- // Store info of this frame. OnNewFrame() will need the timestamp later.
- MutexAutoLock lock(mDecodedFrameLock);
- if (mEnding) {
- mCodec->releaseOutputBuffer(index);
- return err;
- }
- mDecodedFrames.push(frame);
- }
- // Ask codec to queue buffer back to native window. OnNewFrame() will be
- // called.
- mCodec->renderOutputBufferAndRelease(index);
- // Once consumed, buffer will be queued back to GonkNativeWindow for codec
- // to dequeue/use.
- } else {
- mCodec->releaseOutputBuffer(index);
- }
-
- return err;
- }
-
- // Will be called when MediaCodec::RenderOutputBufferAndRelease() returns
- // buffers back to native window for rendering.
- void OnNewFrame() override
- {
- RefPtr<layers::TextureClient> buffer = mNativeWindow->getCurrentBuffer();
- if (!buffer) {
- CODEC_LOGE("Decoder NewFrame: Get null buffer");
- return;
- }
-
- gfx::IntSize picSize(buffer->GetSize());
- nsAutoPtr<layers::GrallocImage> grallocImage(new layers::GrallocImage());
- grallocImage->AdoptData(buffer, picSize);
-
- // Get timestamp of the frame about to render.
- int64_t timestamp = -1;
- int64_t renderTimeMs = -1;
- {
- MutexAutoLock lock(mDecodedFrameLock);
- if (mDecodedFrames.empty()) {
- return;
- }
- EncodedFrame decoded = mDecodedFrames.front();
- timestamp = decoded.mTimestamp;
- renderTimeMs = decoded.mRenderTimeMs;
- mDecodedFrames.pop();
- }
- MOZ_ASSERT(timestamp >= 0 && renderTimeMs >= 0);
-
- CODEC_LOGD("Decoder NewFrame: %dx%d, timestamp %lld, renderTimeMs %lld",
- picSize.width, picSize.height, timestamp, renderTimeMs);
-
- nsAutoPtr<webrtc::VideoFrame> videoFrame(new webrtc::VideoFrame(
- new ImageNativeHandle(grallocImage.forget()),
- picSize.width,
- picSize.height,
- timestamp,
- renderTimeMs));
- if (videoFrame != nullptr) {
- mCallback->Decoded(*videoFrame);
- }
- }
-
-private:
- class OutputDrain : public OMXOutputDrain
- {
- public:
- OutputDrain(WebrtcOMXDecoder* aOMX)
- : OMXOutputDrain()
- , mOMX(aOMX)
- {}
-
- protected:
- virtual bool DrainOutput() override
- {
- return (mOMX->DrainOutput(mInputFrames, mMonitor) == OK);
- }
-
- private:
- WebrtcOMXDecoder* mOMX;
- };
-
- status_t Start()
- {
- MOZ_ASSERT(!mStarted);
- if (mStarted) {
- return OK;
- }
-
- {
- MutexAutoLock lock(mDecodedFrameLock);
- mEnding = false;
- }
- status_t err = mCodec->start();
- if (err == OK) {
- mStarted = true;
- mCodec->getInputBuffers(&mInputBuffers);
- mCodec->getOutputBuffers(&mOutputBuffers);
- }
-
- return err;
- }
-
- status_t Stop()
- {
- MOZ_ASSERT(mStarted);
- if (!mStarted) {
- return OK;
- }
-
- CODEC_LOGD("OMXOutputDrain decoder stopping");
- // Drop all 'pending to render' frames.
- {
- MutexAutoLock lock(mDecodedFrameLock);
- mEnding = true;
- while (!mDecodedFrames.empty()) {
- mDecodedFrames.pop();
- }
- }
-
- if (mOutputDrain != nullptr) {
- CODEC_LOGD("decoder's OutputDrain stopping");
- mOutputDrain->Stop();
- mOutputDrain = nullptr;
- }
-
- status_t err = mCodec->stop();
- if (err == OK) {
- mInputBuffers.clear();
- mOutputBuffers.clear();
- mStarted = false;
- } else {
- MOZ_ASSERT(false);
- }
- CODEC_LOGD("OMXOutputDrain decoder stopped");
- return err;
- }
-
- sp<ALooper> mLooper;
- sp<MediaCodec> mCodec; // OMXCodec
- int mWidth;
- int mHeight;
- android::Vector<sp<ABuffer> > mInputBuffers;
- android::Vector<sp<ABuffer> > mOutputBuffers;
- bool mStarted;
-
- sp<GonkNativeWindow> mNativeWindow;
-
- RefPtr<OutputDrain> mOutputDrain;
- webrtc::DecodedImageCallback* mCallback;
-
- Mutex mDecodedFrameLock; // To protect mDecodedFrames and mEnding
- std::queue<EncodedFrame> mDecodedFrames;
- bool mEnding;
-};
-
-class EncOutputDrain : public OMXOutputDrain
-{
-public:
- EncOutputDrain(OMXVideoEncoder* aOMX, webrtc::EncodedImageCallback* aCallback)
- : OMXOutputDrain()
- , mOMX(aOMX)
- , mCallback(aCallback)
- , mIsPrevFrameParamSets(false)
- {}
-
-protected:
- virtual bool DrainOutput() override
- {
- nsTArray<uint8_t> output;
- int64_t timeUs = -1ll;
- int flags = 0;
- nsresult rv = mOMX->GetNextEncodedFrame(&output, &timeUs, &flags,
- DRAIN_THREAD_TIMEOUT_US);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- // Fail to get encoded frame. The corresponding input frame should be
- // removed.
- // We'll treat this like a skipped frame
- return true;
- }
-
- if (output.Length() == 0) {
- // No encoded data yet. Try later.
- CODEC_LOGD("OMX: (encode no output available this time)");
- return false;
- }
-
- // Conversion to us rounds down, so we need to round up for us->90KHz
- uint32_t target_timestamp = (timeUs * 90ll + 999) / 1000; // us -> 90KHz
- // 8x10 v2.0 encoder doesn't set this reliably:
- //bool isParamSets = (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG);
- // Assume that SPS/PPS will be at the start of any buffer
- // Assume PPS will not be in a separate buffer - SPS/PPS or SPS/PPS/iframe
- bool isParamSets = IsParamSets(output.Elements(), output.Length());
- bool isIFrame = (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME);
- CODEC_LOGD("OMX: encoded frame (%d): time %lld (%u), flags x%x",
- output.Length(), timeUs, target_timestamp, flags);
- // Should not be parameter sets and I-frame at the same time.
- // Except that it is possible, apparently, after an encoder re-config (bug 1063883)
- // MOZ_ASSERT(!(isParamSets && isIFrame));
-
- if (mCallback) {
- // Implementation here assumes encoder output to be a buffer containing
- // parameter sets(SPS + PPS) followed by a series of buffers, each for
- // one input frame.
- // TODO: handle output violating this assumpton in bug 997110.
- webrtc::EncodedImage encoded(output.Elements(), output.Length(),
- output.Capacity());
- encoded._frameType = (isParamSets || isIFrame) ?
- webrtc::kKeyFrame : webrtc::kDeltaFrame;
- EncodedFrame input_frame;
- {
- MonitorAutoLock lock(mMonitor);
- // will sps/pps have the same timestamp as their iframe? Initial one on 8x10 has
- // 0 timestamp.
- if (isParamSets) {
- // Let's assume it was the first item in the queue, but leave it there since an
- // IDR will follow
- input_frame = mInputFrames.front();
- } else {
- do {
- if (mInputFrames.empty()) {
- // Let's assume it was the last item in the queue, but leave it there
- mInputFrames.push(input_frame);
- CODEC_LOGE("OMX: encoded timestamp %u which doesn't match input queue!! (head %u)",
- target_timestamp, input_frame.mTimestamp);
- break;
- }
-
- input_frame = mInputFrames.front();
- mInputFrames.pop();
- if (input_frame.mTimestamp != target_timestamp) {
- CODEC_LOGD("OMX: encoder skipped frame timestamp %u", input_frame.mTimestamp);
- }
- } while (input_frame.mTimestamp != target_timestamp);
- }
- }
-
- encoded._encodedWidth = input_frame.mWidth;
- encoded._encodedHeight = input_frame.mHeight;
- encoded._timeStamp = input_frame.mTimestamp;
- encoded.capture_time_ms_ = input_frame.mRenderTimeMs;
- encoded._completeFrame = true;
-
- CODEC_LOGD("Encoded frame: %d bytes, %dx%d, is_param %d, is_iframe %d, timestamp %u, captureTimeMs %" PRIu64,
- encoded._length, encoded._encodedWidth, encoded._encodedHeight,
- isParamSets, isIFrame, encoded._timeStamp, encoded.capture_time_ms_);
- // Prepend SPS/PPS to I-frames unless they were sent last time.
- SendEncodedDataToCallback(encoded, isIFrame && !mIsPrevFrameParamSets && !isParamSets);
- // This will be true only for the frame following a paramset block! So if we're
- // working with a correct encoder that generates SPS/PPS then iframe always, we
- // won't try to insert. (also, don't set if we get SPS/PPS/iframe in one buffer)
- mIsPrevFrameParamSets = isParamSets && !isIFrame;
- if (isParamSets) {
- // copy off the param sets for inserting later
- mParamSets.Clear();
- // since we may have SPS/PPS or SPS/PPS/iframe
- size_t length = ParamSetLength(encoded._buffer, encoded._length);
- MOZ_ASSERT(length > 0);
- mParamSets.AppendElements(encoded._buffer, length);
- }
- }
-
- return !isParamSets; // not really needed anymore
- }
-
-private:
- // Send encoded data to callback.The data will be broken into individual NALUs
- // if necessary and sent to callback one by one. This function can also insert
- // SPS/PPS NALUs in front of input data if requested.
- void SendEncodedDataToCallback(webrtc::EncodedImage& aEncodedImage,
- bool aPrependParamSets)
- {
- if (aPrependParamSets) {
- webrtc::EncodedImage prepend(aEncodedImage);
- // Insert current parameter sets in front of the input encoded data.
- MOZ_ASSERT(mParamSets.Length() > sizeof(kNALStartCode)); // Start code + ...
- prepend._length = mParamSets.Length();
- prepend._buffer = mParamSets.Elements();
- // Break into NALUs and send.
- CODEC_LOGD("Prepending SPS/PPS: %d bytes, timestamp %u, captureTimeMs %" PRIu64,
- prepend._length, prepend._timeStamp, prepend.capture_time_ms_);
- SendEncodedDataToCallback(prepend, false);
- }
-
- struct nal_entry {
- uint32_t offset;
- uint32_t size;
- };
- AutoTArray<nal_entry, 1> nals;
-
- // Break input encoded data into NALUs and send each one to callback.
- const uint8_t* data = aEncodedImage._buffer;
- size_t size = aEncodedImage._length;
- const uint8_t* nalStart = nullptr;
- size_t nalSize = 0;
- while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
- // XXX optimize by making buffer an offset
- nal_entry nal = {((uint32_t) (nalStart - aEncodedImage._buffer)), (uint32_t) nalSize};
- nals.AppendElement(nal);
- }
-
- size_t num_nals = nals.Length();
- if (num_nals > 0) {
- webrtc::RTPFragmentationHeader fragmentation;
- fragmentation.VerifyAndAllocateFragmentationHeader(num_nals);
- for (size_t i = 0; i < num_nals; i++) {
- fragmentation.fragmentationOffset[i] = nals[i].offset;
- fragmentation.fragmentationLength[i] = nals[i].size;
- }
- webrtc::EncodedImage unit(aEncodedImage);
- unit._completeFrame = true;
-
- mCallback->Encoded(unit, nullptr, &fragmentation);
- }
- }
-
- OMXVideoEncoder* mOMX;
- webrtc::EncodedImageCallback* mCallback;
- bool mIsPrevFrameParamSets;
- nsTArray<uint8_t> mParamSets;
-};
-
-// Encoder.
-WebrtcOMXH264VideoEncoder::WebrtcOMXH264VideoEncoder()
- : mOMX(nullptr)
- , mCallback(nullptr)
- , mWidth(0)
- , mHeight(0)
- , mFrameRate(0)
- , mBitRateKbps(0)
-#ifdef OMX_IDR_NEEDED_FOR_BITRATE
- , mBitRateAtLastIDR(0)
-#endif
- , mOMXConfigured(false)
- , mOMXReconfigure(false)
-{
- mReservation = new OMXCodecReservation(true);
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p constructed", this);
-}
-
-int32_t
-WebrtcOMXH264VideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
- int32_t aNumOfCores,
- size_t aMaxPayloadSize)
-{
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p init", this);
-
- if (mOMX == nullptr) {
- nsAutoPtr<OMXVideoEncoder> omx(OMXCodecWrapper::CreateAVCEncoder());
- if (NS_WARN_IF(omx == nullptr)) {
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- mOMX = omx.forget();
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p OMX created", this);
- }
-
- if (!mReservation->ReserveOMXCodec()) {
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p Encoder in use", this);
- mOMX = nullptr;
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- // Defer configuration until 1st frame is received because this function will
- // be called more than once, and unfortunately with incorrect setting values
- // at first.
- mWidth = aCodecSettings->width;
- mHeight = aCodecSettings->height;
- mFrameRate = aCodecSettings->maxFramerate;
- mBitRateKbps = aCodecSettings->startBitrate;
- // XXX handle maxpayloadsize (aka mode 0/1)
-
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p OMX Encoder reserved", this);
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t
-WebrtcOMXH264VideoEncoder::Encode(const webrtc::VideoFrame& aInputImage,
- const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
- const std::vector<webrtc::FrameType>* aFrameTypes)
-{
- MOZ_ASSERT(mOMX != nullptr);
- if (mOMX == nullptr) {
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- // Have to reconfigure for resolution or framerate changes :-(
- // ~220ms initial configure on 8x10, 50-100ms for re-configure it appears
- // XXX drop frames while this is happening?
- if (aInputImage.width() < 0 || (uint32_t)aInputImage.width() != mWidth ||
- aInputImage.height() < 0 || (uint32_t)aInputImage.height() != mHeight) {
- mWidth = aInputImage.width();
- mHeight = aInputImage.height();
- mOMXReconfigure = true;
- }
-
- if (!mOMXConfigured || mOMXReconfigure) {
- if (mOMXConfigured) {
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p reconfiguring encoder %dx%d @ %u fps",
- this, mWidth, mHeight, mFrameRate);
- mOMXConfigured = false;
- }
- mOMXReconfigure = false;
- // XXX This can take time. Encode() likely assumes encodes are queued "quickly" and
- // don't block the input too long. Frames may build up.
-
- // XXX take from negotiated SDP in codecSpecific data
- OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3;
- // OMX_Video_ControlRateConstant is not supported on QC 8x10
- OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstantSkipFrames;
-
- // Set up configuration parameters for AVC/H.264 encoder.
- sp<AMessage> format = new AMessage;
- // Fixed values
- format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
- // XXX We should only set to < infinity if we're not using any recovery RTCP options
- // However, we MUST set it to a lower value because the 8x10 rate controller
- // only changes rate at GOP boundaries.... but it also changes rate on requested GOPs
-
- // Too long and we have very low bitrates for the first second or two... plus
- // bug 1014921 means we have to force them every ~3 seconds or less.
- format->setInt32("i-frame-interval", 4 /* seconds */);
- // See mozilla::layers::GrallocImage, supports YUV 4:2:0, CbCr width and
- // height is half that of Y
- format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar);
- format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline);
- format->setInt32("level", level);
- format->setInt32("bitrate-mode", bitrateMode);
- format->setInt32("store-metadata-in-buffers", 0);
- // XXX Unfortunately, 8x10 doesn't support this, but ask anyways
- format->setInt32("prepend-sps-pps-to-idr-frames", 1);
- // Input values.
- format->setInt32("width", mWidth);
- format->setInt32("height", mHeight);
- format->setInt32("stride", mWidth);
- format->setInt32("slice-height", mHeight);
- format->setInt32("frame-rate", mFrameRate);
- format->setInt32("bitrate", mBitRateKbps*1000);
-
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p configuring encoder %dx%d @ %d fps, rate %d kbps",
- this, mWidth, mHeight, mFrameRate, mBitRateKbps);
- nsresult rv = mOMX->ConfigureDirect(format,
- OMXVideoEncoder::BlobFormat::AVC_NAL);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- CODEC_LOGE("WebrtcOMXH264VideoEncoder:%p FAILED configuring encoder %d", this, int(rv));
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
- mOMXConfigured = true;
-#ifdef OMX_IDR_NEEDED_FOR_BITRATE
- mLastIDRTime = TimeStamp::Now();
- mBitRateAtLastIDR = mBitRateKbps;
-#endif
- }
-
- if (aFrameTypes && aFrameTypes->size() &&
- ((*aFrameTypes)[0] == webrtc::kKeyFrame)) {
- mOMX->RequestIDRFrame();
-#ifdef OMX_IDR_NEEDED_FOR_BITRATE
- mLastIDRTime = TimeStamp::Now();
- mBitRateAtLastIDR = mBitRateKbps;
- } else if (mBitRateKbps != mBitRateAtLastIDR) {
- // 8x10 OMX codec requires a keyframe to shift bitrates!
- TimeStamp now = TimeStamp::Now();
- if (mLastIDRTime.IsNull()) {
- // paranoia
- mLastIDRTime = now;
- }
- int32_t timeSinceLastIDR = (now - mLastIDRTime).ToMilliseconds();
-
- // Balance asking for IDRs too often against direction and amount of bitrate change.
-
- // HACK for bug 1014921: 8x10 has encode/decode mismatches that build up errors
- // if you go too long without an IDR. In normal use, bitrate will change often
- // enough to never hit this time limit.
- if ((timeSinceLastIDR > 3000) ||
- (mBitRateKbps < (mBitRateAtLastIDR * 8)/10) ||
- (timeSinceLastIDR < 300 && mBitRateKbps < (mBitRateAtLastIDR * 9)/10) ||
- (timeSinceLastIDR < 1000 && mBitRateKbps < (mBitRateAtLastIDR * 97)/100) ||
- (timeSinceLastIDR >= 1000 && mBitRateKbps < mBitRateAtLastIDR) ||
- (mBitRateKbps > (mBitRateAtLastIDR * 15)/10) ||
- (timeSinceLastIDR < 500 && mBitRateKbps > (mBitRateAtLastIDR * 13)/10) ||
- (timeSinceLastIDR < 1000 && mBitRateKbps > (mBitRateAtLastIDR * 11)/10) ||
- (timeSinceLastIDR >= 1000 && mBitRateKbps > mBitRateAtLastIDR)) {
- CODEC_LOGD("Requesting IDR for bitrate change from %u to %u (time since last idr %dms)",
- mBitRateAtLastIDR, mBitRateKbps, timeSinceLastIDR);
-
- mOMX->RequestIDRFrame();
- mLastIDRTime = now;
- mBitRateAtLastIDR = mBitRateKbps;
- }
-#endif
- }
-
- // Wrap VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder.
- layers::PlanarYCbCrData yuvData;
- yuvData.mYChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kYPlane));
- yuvData.mYSize = gfx::IntSize(aInputImage.width(), aInputImage.height());
- yuvData.mYStride = aInputImage.stride(webrtc::kYPlane);
- MOZ_ASSERT(aInputImage.stride(webrtc::kUPlane) == aInputImage.stride(webrtc::kVPlane));
- yuvData.mCbCrStride = aInputImage.stride(webrtc::kUPlane);
- yuvData.mCbChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kUPlane));
- yuvData.mCrChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kVPlane));
- yuvData.mCbCrSize = gfx::IntSize((yuvData.mYSize.width + 1) / 2,
- (yuvData.mYSize.height + 1) / 2);
- yuvData.mPicSize = yuvData.mYSize;
- yuvData.mStereoMode = StereoMode::MONO;
- layers::RecyclingPlanarYCbCrImage img(nullptr);
- // AdoptData() doesn't need AllocateAndGetNewBuffer(); OMXVideoEncoder is ok with this
- img.AdoptData(yuvData);
-
- CODEC_LOGD("Encode frame: %dx%d, timestamp %u (%lld), renderTimeMs %" PRIu64,
- aInputImage.width(), aInputImage.height(),
- aInputImage.timestamp(), aInputImage.timestamp() * 1000ll / 90,
- aInputImage.render_time_ms());
-
- nsresult rv = mOMX->Encode(&img,
- yuvData.mYSize.width,
- yuvData.mYSize.height,
- aInputImage.timestamp() * 1000ll / 90, // 90kHz -> us.
- 0);
- if (rv == NS_OK) {
- if (mOutputDrain == nullptr) {
- mOutputDrain = new EncOutputDrain(mOMX, mCallback);
- mOutputDrain->Start();
- }
- EncodedFrame frame;
- frame.mWidth = mWidth;
- frame.mHeight = mHeight;
- frame.mTimestamp = aInputImage.timestamp();
- frame.mRenderTimeMs = aInputImage.render_time_ms();
- mOutputDrain->QueueInput(frame);
- }
-
- return (rv == NS_OK) ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR;
-}
-
-int32_t
-WebrtcOMXH264VideoEncoder::RegisterEncodeCompleteCallback(
- webrtc::EncodedImageCallback* aCallback)
-{
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p set callback:%p", this, aCallback);
- MOZ_ASSERT(aCallback);
- mCallback = aCallback;
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t
-WebrtcOMXH264VideoEncoder::Release()
-{
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p will be released", this);
-
- if (mOutputDrain != nullptr) {
- mOutputDrain->Stop();
- mOutputDrain = nullptr;
- }
- mOMXConfigured = false;
- bool hadOMX = !!mOMX;
- mOMX = nullptr;
- if (hadOMX) {
- mReservation->ReleaseOMXCodec();
- }
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p released", this);
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-WebrtcOMXH264VideoEncoder::~WebrtcOMXH264VideoEncoder()
-{
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p will be destructed", this);
-
- Release();
-}
-
-// Inform the encoder of the new packet loss rate and the round-trip time of
-// the network. aPacketLossRate is fraction lost and can be 0~255
-// (255 means 100% lost).
-// Note: stagefright doesn't handle these parameters.
-int32_t
-WebrtcOMXH264VideoEncoder::SetChannelParameters(uint32_t aPacketLossRate,
- int64_t aRoundTripTimeMs)
-{
- CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p set channel packet loss:%u, rtt:%" PRIi64,
- this, aPacketLossRate, aRoundTripTimeMs);
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-// TODO: Bug 997567. Find the way to support frame rate change.
-int32_t
-WebrtcOMXH264VideoEncoder::SetRates(uint32_t aBitRateKbps, uint32_t aFrameRate)
-{
- CODEC_LOGE("WebrtcOMXH264VideoEncoder:%p set bitrate:%u, frame rate:%u (%u))",
- this, aBitRateKbps, aFrameRate, mFrameRate);
- MOZ_ASSERT(mOMX != nullptr);
- if (mOMX == nullptr) {
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
-
- // XXX Should use StageFright framerate change, perhaps only on major changes of framerate.
-
- // Without Stagefright support, Algorithm should be:
- // if (frameRate < 50% of configured) {
- // drop framerate to next step down that includes current framerate within 50%
- // } else if (frameRate > configured) {
- // change config to next step up that includes current framerate
- // }
-#if !defined(TEST_OMX_FRAMERATE_CHANGES)
- if (aFrameRate > mFrameRate ||
- aFrameRate < mFrameRate/2) {
- uint32_t old_rate = mFrameRate;
- if (aFrameRate >= 15) {
- mFrameRate = 30;
- } else if (aFrameRate >= 10) {
- mFrameRate = 20;
- } else if (aFrameRate >= 8) {
- mFrameRate = 15;
- } else /* if (aFrameRate >= 5)*/ {
- // don't go lower; encoder may not be stable
- mFrameRate = 10;
- }
- if (mFrameRate < aFrameRate) { // safety
- mFrameRate = aFrameRate;
- }
- if (old_rate != mFrameRate) {
- mOMXReconfigure = true; // force re-configure on next frame
- }
- }
-#else
- // XXX for testing, be wild!
- if (aFrameRate != mFrameRate) {
- mFrameRate = aFrameRate;
- mOMXReconfigure = true; // force re-configure on next frame
- }
-#endif
-
- // XXX Limit bitrate for 8x10 devices to a specific level depending on fps and resolution
- // mBitRateKbps = LimitBitrate8x10(mWidth, mHeight, mFrameRate, aBitRateKbps);
- // Rely on global single setting (~720 kbps for HVGA@30fps) for now
- if (aBitRateKbps > 700) {
- aBitRateKbps = 700;
- }
- mBitRateKbps = aBitRateKbps;
- nsresult rv = mOMX->SetBitrate(mBitRateKbps);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetBitrate failed");
- return NS_FAILED(rv) ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR;
-}
-
-// Decoder.
-WebrtcOMXH264VideoDecoder::WebrtcOMXH264VideoDecoder()
- : mCallback(nullptr)
- , mOMX(nullptr)
-{
- mReservation = new OMXCodecReservation(false);
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be constructed", this);
-}
-
-int32_t
-WebrtcOMXH264VideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings,
- int32_t aNumOfCores)
-{
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p init OMX:%p", this, mOMX.get());
-
- if (!mReservation->ReserveOMXCodec()) {
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p Decoder in use", this);
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- // Defer configuration until SPS/PPS NALUs (where actual decoder config
- // values can be extracted) are received.
-
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p OMX Decoder reserved", this);
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t
-WebrtcOMXH264VideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
- bool aMissingFrames,
- const webrtc::RTPFragmentationHeader* aFragmentation,
- const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
- int64_t aRenderTimeMs)
-{
- if (aInputImage._length== 0 || !aInputImage._buffer) {
- return WEBRTC_VIDEO_CODEC_ERROR;
- }
-
- bool configured = !!mOMX;
- if (!configured) {
- // Search for SPS NALU in input to get width/height config.
- int32_t width;
- int32_t height;
- status_t result = WebrtcOMXDecoder::ExtractPicDimensions(aInputImage._buffer,
- aInputImage._length,
- &width, &height);
- if (result != OK) {
- // Cannot config decoder because SPS haven't been seen.
- CODEC_LOGI("WebrtcOMXH264VideoDecoder:%p missing SPS in input (nal 0x%02x, len %d)",
- this, aInputImage._buffer[sizeof(kNALStartCode)] & 0x1f, aInputImage._length);
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
- RefPtr<WebrtcOMXDecoder> omx = new WebrtcOMXDecoder(MEDIA_MIMETYPE_VIDEO_AVC,
- mCallback);
- result = omx->ConfigureWithPicDimensions(width, height);
- if (NS_WARN_IF(result != OK)) {
- return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
- }
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p start OMX", this);
- mOMX = omx;
- }
-
- bool feedFrame = true;
- while (feedFrame) {
- status_t err = mOMX->FillInput(aInputImage, !configured, aRenderTimeMs);
- feedFrame = (err == -EAGAIN); // No input buffer available. Try again.
- }
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t
-WebrtcOMXH264VideoDecoder::RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback)
-{
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p set callback:%p", this, aCallback);
- MOZ_ASSERT(aCallback);
- mCallback = aCallback;
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t
-WebrtcOMXH264VideoDecoder::Release()
-{
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be released", this);
-
- mOMX = nullptr; // calls Stop()
- mReservation->ReleaseOMXCodec();
-
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-WebrtcOMXH264VideoDecoder::~WebrtcOMXH264VideoDecoder()
-{
- CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be destructed", this);
- Release();
-}
-
-int32_t
-WebrtcOMXH264VideoDecoder::Reset()
-{
- CODEC_LOGW("WebrtcOMXH264VideoDecoder::Reset() will NOT reset decoder");
- return WEBRTC_VIDEO_CODEC_OK;
-}
-
-}