summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/omx/OmxPromiseLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/omx/OmxPromiseLayer.cpp')
-rw-r--r--dom/media/platforms/omx/OmxPromiseLayer.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/dom/media/platforms/omx/OmxPromiseLayer.cpp b/dom/media/platforms/omx/OmxPromiseLayer.cpp
new file mode 100644
index 0000000000..74d1fe15f8
--- /dev/null
+++ b/dom/media/platforms/omx/OmxPromiseLayer.cpp
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "OmxPromiseLayer.h"
+
+#include "ImageContainer.h"
+
+#include "OmxDataDecoder.h"
+#include "OmxPlatformLayer.h"
+
+#ifdef LOG
+# undef LOG
+#endif
+
+#define LOG(arg, ...) \
+ MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
+ ("OmxPromiseLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+
+namespace mozilla {
+
+OmxPromiseLayer::OmxPromiseLayer(TaskQueue* aTaskQueue,
+ OmxDataDecoder* aDataDecoder,
+ layers::ImageContainer* aImageContainer)
+ : mTaskQueue(aTaskQueue) {
+ mPlatformLayer.reset(OmxPlatformLayer::Create(aDataDecoder, this, aTaskQueue,
+ aImageContainer));
+ MOZ_ASSERT(!!mPlatformLayer);
+}
+
+RefPtr<OmxPromiseLayer::OmxCommandPromise> OmxPromiseLayer::Init(
+ const TrackInfo* aInfo) {
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+ OMX_ERRORTYPE err = mPlatformLayer->InitOmxToStateLoaded(aInfo);
+ if (err != OMX_ErrorNone) {
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet);
+ return OmxCommandPromise::CreateAndReject(failure, __func__);
+ }
+
+ OMX_STATETYPE state = GetState();
+ if (state == OMX_StateLoaded) {
+ return OmxCommandPromise::CreateAndResolve(OMX_CommandStateSet, __func__);
+ }
+ if (state == OMX_StateIdle) {
+ return SendCommand(OMX_CommandStateSet, OMX_StateIdle, nullptr);
+ }
+
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandStateSet);
+ return OmxCommandPromise::CreateAndReject(failure, __func__);
+}
+
+OMX_ERRORTYPE
+OmxPromiseLayer::Config() {
+ MOZ_ASSERT(GetState() == OMX_StateLoaded);
+
+ return mPlatformLayer->Config();
+}
+
+RefPtr<OmxPromiseLayer::OmxBufferPromise> OmxPromiseLayer::FillBuffer(
+ BufferData* aData) {
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+ LOG("buffer %p", aData->mBuffer);
+
+ RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__);
+
+ OMX_ERRORTYPE err = mPlatformLayer->FillThisBuffer(aData);
+
+ if (err != OMX_ErrorNone) {
+ OmxBufferFailureHolder failure(err, aData);
+ aData->mPromise.Reject(std::move(failure), __func__);
+ } else {
+ aData->mStatus = BufferData::BufferStatus::OMX_COMPONENT;
+ GetBufferHolders(OMX_DirOutput)->AppendElement(aData);
+ }
+
+ return p;
+}
+
+RefPtr<OmxPromiseLayer::OmxBufferPromise> OmxPromiseLayer::EmptyBuffer(
+ BufferData* aData) {
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+ LOG("buffer %p, size %lu", aData->mBuffer, aData->mBuffer->nFilledLen);
+
+ RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__);
+
+ OMX_ERRORTYPE err = mPlatformLayer->EmptyThisBuffer(aData);
+
+ if (err != OMX_ErrorNone) {
+ OmxBufferFailureHolder failure(err, aData);
+ aData->mPromise.Reject(std::move(failure), __func__);
+ } else {
+ if (aData->mRawData) {
+ mRawDatas.AppendElement(std::move(aData->mRawData));
+ }
+ aData->mStatus = BufferData::BufferStatus::OMX_COMPONENT;
+ GetBufferHolders(OMX_DirInput)->AppendElement(aData);
+ }
+
+ return p;
+}
+
+OmxPromiseLayer::BUFFERLIST* OmxPromiseLayer::GetBufferHolders(
+ OMX_DIRTYPE aType) {
+ MOZ_ASSERT(aType == OMX_DirInput || aType == OMX_DirOutput);
+
+ if (aType == OMX_DirInput) {
+ return &mInbufferHolders;
+ }
+
+ return &mOutbufferHolders;
+}
+
+already_AddRefed<MediaRawData> OmxPromiseLayer::FindAndRemoveRawData(
+ OMX_TICKS aTimecode) {
+ for (auto raw : mRawDatas) {
+ if (raw->mTime.ToMicroseconds() == aTimecode) {
+ mRawDatas.RemoveElement(raw);
+ return raw.forget();
+ }
+ }
+ return nullptr;
+}
+
+already_AddRefed<BufferData> OmxPromiseLayer::FindAndRemoveBufferHolder(
+ OMX_DIRTYPE aType, BufferData::BufferID aId) {
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+ RefPtr<BufferData> holder;
+ BUFFERLIST* holders = GetBufferHolders(aType);
+
+ for (uint32_t i = 0; i < holders->Length(); i++) {
+ if (holders->ElementAt(i)->ID() == aId) {
+ holder = holders->ElementAt(i);
+ holders->RemoveElementAt(i);
+ return holder.forget();
+ }
+ }
+
+ return nullptr;
+}
+
+already_AddRefed<BufferData> OmxPromiseLayer::FindBufferById(
+ OMX_DIRTYPE aType, BufferData::BufferID aId) {
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+
+ RefPtr<BufferData> holder;
+ BUFFERLIST* holders = GetBufferHolders(aType);
+
+ for (uint32_t i = 0; i < holders->Length(); i++) {
+ if (holders->ElementAt(i)->ID() == aId) {
+ holder = holders->ElementAt(i);
+ return holder.forget();
+ }
+ }
+
+ return nullptr;
+}
+
+void OmxPromiseLayer::EmptyFillBufferDone(OMX_DIRTYPE aType,
+ BufferData* aData) {
+ if (aData) {
+ LOG("type %d, buffer %p", aType, aData->mBuffer);
+ if (aType == OMX_DirOutput) {
+ aData->mRawData = nullptr;
+ aData->mRawData = FindAndRemoveRawData(aData->mBuffer->nTimeStamp);
+ }
+ aData->mStatus = BufferData::BufferStatus::OMX_CLIENT;
+ aData->mPromise.Resolve(aData, __func__);
+ } else {
+ LOG("type %d, no buffer", aType);
+ }
+}
+
+void OmxPromiseLayer::EmptyFillBufferDone(OMX_DIRTYPE aType,
+ BufferData::BufferID aID) {
+ RefPtr<BufferData> holder = FindAndRemoveBufferHolder(aType, aID);
+ EmptyFillBufferDone(aType, holder);
+}
+
+RefPtr<OmxPromiseLayer::OmxCommandPromise> OmxPromiseLayer::SendCommand(
+ OMX_COMMANDTYPE aCmd, OMX_U32 aParam1, OMX_PTR aCmdData) {
+ if (aCmd == OMX_CommandFlush) {
+ // It doesn't support another flush commands before previous one is
+ // completed.
+ MOZ_RELEASE_ASSERT(!mFlushCommands.Length());
+
+ // Some coomponents don't send event with OMX_ALL, they send flush complete
+ // event with input port and another event for output port.
+ // In prupose of better compatibility, we interpret the OMX_ALL to
+ // OMX_DirInput and OMX_DirOutput flush separately.
+ OMX_DIRTYPE types[] = {OMX_DIRTYPE::OMX_DirInput,
+ OMX_DIRTYPE::OMX_DirOutput};
+ for (const auto type : types) {
+ if ((aParam1 == type) || (aParam1 == OMX_ALL)) {
+ mFlushCommands.AppendElement(FlushCommand({type, aCmdData}));
+ }
+
+ if (type == OMX_DirInput) {
+ // Clear all buffered raw data.
+ mRawDatas.Clear();
+ }
+ }
+
+ // Don't overlay more than one flush command, some components can't overlay
+ // flush commands. So here we send another flush after receiving the
+ // previous flush completed event.
+ if (mFlushCommands.Length()) {
+ OMX_ERRORTYPE err = mPlatformLayer->SendCommand(
+ OMX_CommandFlush, mFlushCommands.ElementAt(0).type,
+ mFlushCommands.ElementAt(0).cmd);
+ if (err != OMX_ErrorNone) {
+ OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
+ return OmxCommandPromise::CreateAndReject(failure, __func__);
+ }
+ } else {
+ LOG("OMX_CommandFlush parameter error");
+ OmxCommandFailureHolder failure(OMX_ErrorNotReady, OMX_CommandFlush);
+ return OmxCommandPromise::CreateAndReject(failure, __func__);
+ }
+ } else {
+ OMX_ERRORTYPE err = mPlatformLayer->SendCommand(aCmd, aParam1, aCmdData);
+ if (err != OMX_ErrorNone) {
+ OmxCommandFailureHolder failure(OMX_ErrorNotReady, aCmd);
+ return OmxCommandPromise::CreateAndReject(failure, __func__);
+ }
+ }
+
+ RefPtr<OmxCommandPromise> p;
+ if (aCmd == OMX_CommandStateSet) {
+ p = mCommandStatePromise.Ensure(__func__);
+ } else if (aCmd == OMX_CommandFlush) {
+ p = mFlushPromise.Ensure(__func__);
+ } else if (aCmd == OMX_CommandPortEnable) {
+ p = mPortEnablePromise.Ensure(__func__);
+ } else if (aCmd == OMX_CommandPortDisable) {
+ p = mPortDisablePromise.Ensure(__func__);
+ } else {
+ LOG("error unsupport command");
+ MOZ_ASSERT(0);
+ }
+
+ return p;
+}
+
+bool OmxPromiseLayer::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1,
+ OMX_U32 aData2) {
+ OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE)aData1;
+ switch (aEvent) {
+ case OMX_EventCmdComplete: {
+ if (cmd == OMX_CommandStateSet) {
+ mCommandStatePromise.Resolve(OMX_CommandStateSet, __func__);
+ } else if (cmd == OMX_CommandFlush) {
+ MOZ_RELEASE_ASSERT(mFlushCommands.ElementAt(0).type == aData2);
+ LOG("OMX_CommandFlush completed port type %lu", aData2);
+ mFlushCommands.RemoveElementAt(0);
+
+ // Sending next flush command.
+ if (mFlushCommands.Length()) {
+ OMX_ERRORTYPE err = mPlatformLayer->SendCommand(
+ OMX_CommandFlush, mFlushCommands.ElementAt(0).type,
+ mFlushCommands.ElementAt(0).cmd);
+ if (err != OMX_ErrorNone) {
+ OmxCommandFailureHolder failure(OMX_ErrorNotReady,
+ OMX_CommandFlush);
+ mFlushPromise.Reject(failure, __func__);
+ }
+ } else {
+ mFlushPromise.Resolve(OMX_CommandFlush, __func__);
+ }
+ } else if (cmd == OMX_CommandPortDisable) {
+ mPortDisablePromise.Resolve(OMX_CommandPortDisable, __func__);
+ } else if (cmd == OMX_CommandPortEnable) {
+ mPortEnablePromise.Resolve(OMX_CommandPortEnable, __func__);
+ }
+ break;
+ }
+ case OMX_EventError: {
+ if (cmd == OMX_CommandStateSet) {
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined,
+ OMX_CommandStateSet);
+ mCommandStatePromise.Reject(failure, __func__);
+ } else if (cmd == OMX_CommandFlush) {
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined, OMX_CommandFlush);
+ mFlushPromise.Reject(failure, __func__);
+ } else if (cmd == OMX_CommandPortDisable) {
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined,
+ OMX_CommandPortDisable);
+ mPortDisablePromise.Reject(failure, __func__);
+ } else if (cmd == OMX_CommandPortEnable) {
+ OmxCommandFailureHolder failure(OMX_ErrorUndefined,
+ OMX_CommandPortEnable);
+ mPortEnablePromise.Reject(failure, __func__);
+ } else {
+ return false;
+ }
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+ return true;
+}
+
+nsresult OmxPromiseLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
+ BUFFERLIST* aBuffers) {
+ return mPlatformLayer->AllocateOmxBuffer(aType, aBuffers);
+}
+
+nsresult OmxPromiseLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
+ BUFFERLIST* aBuffers) {
+ return mPlatformLayer->ReleaseOmxBuffer(aType, aBuffers);
+}
+
+OMX_STATETYPE
+OmxPromiseLayer::GetState() {
+ OMX_STATETYPE state;
+ OMX_ERRORTYPE err = mPlatformLayer->GetState(&state);
+ return err == OMX_ErrorNone ? state : OMX_StateInvalid;
+}
+
+OMX_ERRORTYPE
+OmxPromiseLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
+ OMX_PTR aComponentParameterStructure,
+ OMX_U32 aComponentParameterSize) {
+ return mPlatformLayer->GetParameter(aParamIndex, aComponentParameterStructure,
+ aComponentParameterSize);
+}
+
+OMX_ERRORTYPE
+OmxPromiseLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
+ OMX_PTR aComponentParameterStructure,
+ OMX_U32 aComponentParameterSize) {
+ return mPlatformLayer->SetParameter(aParamIndex, aComponentParameterStructure,
+ aComponentParameterSize);
+}
+
+OMX_U32
+OmxPromiseLayer::InputPortIndex() { return mPlatformLayer->InputPortIndex(); }
+
+OMX_U32
+OmxPromiseLayer::OutputPortIndex() { return mPlatformLayer->OutputPortIndex(); }
+
+nsresult OmxPromiseLayer::Shutdown() {
+ LOG("");
+ MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+ MOZ_ASSERT(!GetBufferHolders(OMX_DirInput)->Length());
+ MOZ_ASSERT(!GetBufferHolders(OMX_DirOutput)->Length());
+ return mPlatformLayer->Shutdown();
+}
+
+} // namespace mozilla