summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/omx/PureOmxPlatformLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/omx/PureOmxPlatformLayer.cpp')
-rw-r--r--dom/media/platforms/omx/PureOmxPlatformLayer.cpp405
1 files changed, 405 insertions, 0 deletions
diff --git a/dom/media/platforms/omx/PureOmxPlatformLayer.cpp b/dom/media/platforms/omx/PureOmxPlatformLayer.cpp
new file mode 100644
index 0000000000..dd6b259ac6
--- /dev/null
+++ b/dom/media/platforms/omx/PureOmxPlatformLayer.cpp
@@ -0,0 +1,405 @@
+/* -*- 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 "OmxDataDecoder.h"
+#include "OmxPromiseLayer.h"
+#include "PureOmxPlatformLayer.h"
+#include "OmxCoreLibLinker.h"
+
+#ifdef LOG
+# undef LOG
+#endif
+
+#define LOG(arg, ...) \
+ MOZ_LOG( \
+ sPDMLog, mozilla::LogLevel::Debug, \
+ ("PureOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+#define LOG_BUF(arg, ...) \
+ MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
+ ("PureOmxBufferData(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+
+namespace mozilla {
+
+#define OMX_FUNC(func) extern typeof(func)* func;
+#include "OmxFunctionList.h"
+#undef OMX_FUNC
+
+PureOmxBufferData::PureOmxBufferData(
+ const PureOmxPlatformLayer& aPlatformLayer,
+ const OMX_PARAM_PORTDEFINITIONTYPE& aPortDef)
+ : BufferData(nullptr), mPlatformLayer(aPlatformLayer), mPortDef(aPortDef) {
+ LOG_BUF("");
+
+ if (ShouldUseEGLImage()) {
+ // TODO
+ LOG_BUF(
+ "OMX_UseEGLImage() seems available but using it isn't implemented "
+ "yet.");
+ }
+
+ OMX_ERRORTYPE err;
+ err = OMX_AllocateBuffer(mPlatformLayer.GetComponent(), &mBuffer,
+ mPortDef.nPortIndex, this, mPortDef.nBufferSize);
+ if (err != OMX_ErrorNone) {
+ LOG_BUF("Failed to allocate the buffer!: 0x%08x", err);
+ }
+}
+
+PureOmxBufferData::~PureOmxBufferData() {
+ LOG_BUF("");
+ ReleaseBuffer();
+}
+
+void PureOmxBufferData::ReleaseBuffer() {
+ LOG_BUF("");
+
+ if (mBuffer) {
+ OMX_ERRORTYPE err;
+ err = OMX_FreeBuffer(mPlatformLayer.GetComponent(), mPortDef.nPortIndex,
+ mBuffer);
+ if (err != OMX_ErrorNone) {
+ LOG_BUF("Failed to free the buffer!: 0x%08x", err);
+ }
+ mBuffer = nullptr;
+ }
+}
+
+bool PureOmxBufferData::ShouldUseEGLImage() {
+ OMX_ERRORTYPE err;
+ err = OMX_UseEGLImage(mPlatformLayer.GetComponent(), nullptr,
+ mPortDef.nPortIndex, nullptr, nullptr);
+ return (err != OMX_ErrorNotImplemented);
+}
+
+/* static */
+bool PureOmxPlatformLayer::Init(void) {
+ if (!OmxCoreLibLinker::Link()) {
+ return false;
+ }
+
+ OMX_ERRORTYPE err = OMX_Init();
+ if (err != OMX_ErrorNone) {
+ MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
+ ("PureOmxPlatformLayer::%s: Failed to initialize OMXCore: 0x%08x",
+ __func__, err));
+ return false;
+ }
+
+ return true;
+}
+
+/* static */
+OMX_CALLBACKTYPE PureOmxPlatformLayer::sCallbacks = {
+ EventHandler, EmptyBufferDone, FillBufferDone};
+
+PureOmxPlatformLayer::PureOmxPlatformLayer(
+ OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer,
+ TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer)
+ : mComponent(nullptr),
+ mDataDecoder(aDataDecoder),
+ mPromiseLayer(aPromiseLayer),
+ mTaskQueue(aTaskQueue),
+ mImageContainer(aImageContainer) {
+ LOG("");
+}
+
+PureOmxPlatformLayer::~PureOmxPlatformLayer() { LOG(""); }
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo) {
+ LOG("");
+
+ if (!aInfo) {
+ return OMX_ErrorUndefined;
+ }
+ mInfo = aInfo;
+
+ return CreateComponent();
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EmptyThisBuffer(BufferData* aData) {
+ LOG("");
+ return OMX_EmptyThisBuffer(mComponent, aData->mBuffer);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::FillThisBuffer(BufferData* aData) {
+ LOG("");
+ return OMX_FillThisBuffer(mComponent, aData->mBuffer);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd, OMX_U32 aParam1,
+ OMX_PTR aCmdData) {
+ LOG("aCmd: 0x%08x", aCmd);
+ if (!mComponent) {
+ return OMX_ErrorUndefined;
+ }
+ return OMX_SendCommand(mComponent, aCmd, aParam1, aCmdData);
+}
+
+nsresult PureOmxPlatformLayer::FindPortDefinition(
+ OMX_DIRTYPE aType, OMX_PARAM_PORTDEFINITIONTYPE& portDef) {
+ nsTArray<uint32_t> portIndex;
+ GetPortIndices(portIndex);
+ for (auto idx : portIndex) {
+ InitOmxParameter(&portDef);
+ portDef.nPortIndex = idx;
+
+ OMX_ERRORTYPE err;
+ err = GetParameter(OMX_IndexParamPortDefinition, &portDef,
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ if (err != OMX_ErrorNone) {
+ return NS_ERROR_FAILURE;
+ } else if (portDef.eDir == aType) {
+ LOG("Found OMX_IndexParamPortDefinition: port: %d, type: %d",
+ portDef.nPortIndex, portDef.eDir);
+ return NS_OK;
+ }
+ }
+ return NS_ERROR_FAILURE;
+}
+
+nsresult PureOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
+ BUFFERLIST* aBufferList) {
+ LOG("aType: %d", aType);
+
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+ nsresult result = FindPortDefinition(aType, portDef);
+ if (result != NS_OK) {
+ return result;
+ }
+
+ LOG("nBufferCountActual: %d, nBufferSize: %d", portDef.nBufferCountActual,
+ portDef.nBufferSize);
+
+ for (OMX_U32 i = 0; i < portDef.nBufferCountActual; ++i) {
+ RefPtr<PureOmxBufferData> buffer = new PureOmxBufferData(*this, portDef);
+ aBufferList->AppendElement(buffer);
+ }
+
+ return NS_OK;
+}
+
+nsresult PureOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
+ BUFFERLIST* aBufferList) {
+ LOG("aType: 0x%08x", aType);
+
+ uint32_t len = aBufferList->Length();
+ for (uint32_t i = 0; i < len; i++) {
+ PureOmxBufferData* buffer =
+ static_cast<PureOmxBufferData*>(aBufferList->ElementAt(i).get());
+
+ // All raw OpenMAX buffers have to be released here to flush
+ // OMX_CommandStateSet for switching the state to OMX_StateLoaded.
+ // See OmxDataDecoder::DoAsyncShutdown() for more detail.
+ buffer->ReleaseBuffer();
+ }
+ aBufferList->Clear();
+
+ return NS_OK;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::GetState(OMX_STATETYPE* aType) {
+ LOG("");
+
+ if (mComponent) {
+ return OMX_GetState(mComponent, aType);
+ }
+
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
+ OMX_PTR aComponentParameterStructure,
+ OMX_U32 aComponentParameterSize) {
+ LOG("aParamIndex: 0x%08x", aParamIndex);
+
+ if (!mComponent) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_GetParameter(mComponent, aParamIndex,
+ aComponentParameterStructure);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
+ OMX_PTR aComponentParameterStructure,
+ OMX_U32 aComponentParameterSize) {
+ LOG("aParamIndex: 0x%08x", aParamIndex);
+
+ if (!mComponent) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_SetParameter(mComponent, aParamIndex,
+ aComponentParameterStructure);
+}
+
+nsresult PureOmxPlatformLayer::Shutdown() {
+ LOG("");
+ if (mComponent) {
+ OMX_FreeHandle(mComponent);
+ mComponent = nullptr;
+ }
+ mPromiseLayer = nullptr;
+ mDataDecoder = nullptr;
+ return NS_OK;
+}
+
+/* static */
+OMX_ERRORTYPE PureOmxPlatformLayer::EventHandler(OMX_HANDLETYPE hComponent,
+ OMX_PTR pAppData,
+ OMX_EVENTTYPE eEventType,
+ OMX_U32 nData1, OMX_U32 nData2,
+ OMX_PTR pEventData) {
+ PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "mozilla::PureOmxPlatformLayer::EventHandler",
+ [self, eEventType, nData1, nData2, pEventData]() {
+ self->EventHandler(eEventType, nData1, nData2, pEventData);
+ });
+ nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+ return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+/* static */
+OMX_ERRORTYPE PureOmxPlatformLayer::EmptyBufferDone(
+ OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "mozilla::PureOmxPlatformLayer::EmptyBufferDone",
+ [self, pBuffer]() { self->EmptyBufferDone(pBuffer); });
+ nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+ return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+/* static */
+OMX_ERRORTYPE PureOmxPlatformLayer::FillBufferDone(
+ OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData,
+ OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
+ PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "mozilla::PureOmxPlatformLayer::FillBufferDone",
+ [self, pBuffer]() { self->FillBufferDone(pBuffer); });
+ nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+ return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EventHandler(OMX_EVENTTYPE eEventType, OMX_U32 nData1,
+ OMX_U32 nData2, OMX_PTR pEventData) {
+ bool handled = mPromiseLayer->Event(eEventType, nData1, nData2);
+ LOG("eEventType: 0x%08x, handled: %d", eEventType, handled);
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ PureOmxBufferData* buffer =
+ static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
+ OMX_DIRTYPE portDirection = buffer->GetPortDirection();
+ LOG("PortDirection: %d", portDirection);
+ mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
+ PureOmxBufferData* buffer =
+ static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
+ OMX_DIRTYPE portDirection = buffer->GetPortDirection();
+ LOG("PortDirection: %d", portDirection);
+ mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
+ return OMX_ErrorNone;
+}
+
+bool PureOmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) {
+ return FindStandardComponent(aMimeType, nullptr);
+}
+
+static bool GetStandardComponentRole(const nsACString& aMimeType,
+ nsACString& aRole) {
+ if (aMimeType.EqualsLiteral("video/avc") ||
+ aMimeType.EqualsLiteral("video/mp4") ||
+ aMimeType.EqualsLiteral("video/mp4v-es")) {
+ aRole.Assign("video_decoder.avc");
+ return true;
+ } else if (aMimeType.EqualsLiteral("audio/mp4a-latm") ||
+ aMimeType.EqualsLiteral("audio/mp4") ||
+ aMimeType.EqualsLiteral("audio/aac")) {
+ aRole.Assign("audio_decoder.aac");
+ return true;
+ }
+ return false;
+}
+
+/* static */
+bool PureOmxPlatformLayer::FindStandardComponent(const nsACString& aMimeType,
+ nsACString* aComponentName) {
+ nsAutoCString role;
+ if (!GetStandardComponentRole(aMimeType, role)) return false;
+
+ OMX_U32 nComponents = 0;
+ OMX_ERRORTYPE err;
+ err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
+ &nComponents, nullptr);
+ if (err != OMX_ErrorNone || nComponents <= 0) {
+ return false;
+ }
+ if (!aComponentName) {
+ return true;
+ }
+
+ // TODO:
+ // Only the first component will be used.
+ // We should detect the most preferred component.
+ OMX_U8* componentNames[1];
+ UniquePtr<OMX_U8[]> componentName;
+ componentName = MakeUniqueFallible<OMX_U8[]>(OMX_MAX_STRINGNAME_SIZE);
+ componentNames[0] = componentName.get();
+ nComponents = 1;
+ err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
+ &nComponents, componentNames);
+ if (err == OMX_ErrorNone) {
+ MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
+ ("PureOmxPlatformLayer::%s: A component has been found for %s: %s",
+ __func__, aMimeType.Data(), componentNames[0]));
+ aComponentName->Assign(reinterpret_cast<char*>(componentNames[0]));
+ }
+
+ return err == OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::CreateComponent(const nsACString* aComponentName) {
+ nsAutoCString componentName;
+ if (aComponentName) {
+ componentName = *aComponentName;
+ } else if (!FindStandardComponent(mInfo->mMimeType, &componentName)) {
+ return OMX_ErrorComponentNotFound;
+ }
+
+ OMX_ERRORTYPE err;
+ err = OMX_GetHandle(&mComponent, const_cast<OMX_STRING>(componentName.Data()),
+ this, &sCallbacks);
+
+ const char* mime = mInfo->mMimeType.Data();
+ if (err == OMX_ErrorNone) {
+ LOG("Succeeded to create the component for %s", mime);
+ } else {
+ LOG("Failed to create the component for %s: 0x%08x", mime, err);
+ }
+
+ return err;
+}
+
+} // namespace mozilla