/* -*- 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 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 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(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(pAppData); nsCOMPtr 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(pAppData); nsCOMPtr 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(pAppData); nsCOMPtr 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(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(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(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 componentName; componentName = MakeUniqueFallible(OMX_MAX_STRINGNAME_SIZE); componentNames[0] = componentName.get(); nComponents = 1; err = OMX_GetComponentsOfRole(const_cast(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(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(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