diff --git a/Makefile b/Makefile index 9fc45de..921b449 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,21 @@ INCLUDES+=-I./ -Ilinux -Iffmpeg_compiled/usr/local/include/ -I /usr/include/dbus DIST ?= omxplayer-dist -SRC=linux/XMemUtils.cpp \ +INCLUDES+=-Ialsa +LDFLAGS+=-lasound +SRC += \ + alsa/omx_semaphore.cpp \ + alsa/omx_alsasink_component.cpp \ + alsa/omx_base_audio_port.cpp \ + alsa/omx_base_clock_port.cpp \ + alsa/omx_base_component.cpp \ + alsa/omx_base_port.cpp \ + alsa/omx_base_sink.cpp \ + alsa/omx_queue.cpp \ + alsa/omx_loader_XBMC.cpp + +SRC += \ + linux/XMemUtils.cpp \ utils/log.cpp \ DynamicDll.cpp \ utils/PCMRemap.cpp \ @@ -34,8 +48,9 @@ SRC=linux/XMemUtils.cpp \ Srt.cpp \ KeyConfig.cpp \ OMXControl.cpp \ - Keyboard.cpp \ - omxplayer.cpp \ + Keyboard.cpp + +SRC += omxplayer.cpp OBJS+=$(filter %.o,$(SRC:.cpp=.o)) diff --git a/Makefile.include b/Makefile.include index 58e9560..3b99d3b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,40 +1,5 @@ -USE_BUILDROOT=0 -FLOAT=hard - -ifeq ($(USE_BUILDROOT), 1) -BUILDROOT :=/opt/xbmc-bcm/buildroot -SDKSTAGE :=$(BUILDROOT)/output/staging -TARGETFS :=$(BUILDROOT)/output/target -TOOLCHAIN :=$(BUILDROOT)/output/host/usr/ -HOST :=arm-unknown-linux-gnueabi -SYSROOT :=$(BUILDROOT)/output/host/usr/arm-unknown-linux-gnueabi/sysroot -else -BUILDROOT :=/opt/bcm-rootfs -SDKSTAGE :=/opt/bcm-rootfs -TARGETFS :=/opt/bcm-rootfs -TOOLCHAIN :=/home/dc4/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/ -HOST :=arm-linux-gnueabihf -#SYSROOT :=$(TOOLCHAIN)/arm-bcm2708hardfp-linux-gnueabi/sysroot -SYSROOT :=/opt/bcm-rootfs -endif - -JOBS=7 - -CFLAGS := -isystem$(PREFIX)/include -CXXFLAGS := $(CFLAGS) -CPPFLAGS := $(CFLAGS) -LDFLAGS := -L$(BUILDROOT)/lib -LD := $(TOOLCHAIN)/bin/$(HOST)-ld --sysroot=$(SYSROOT) -CC := $(TOOLCHAIN)/bin/$(HOST)-gcc --sysroot=$(SYSROOT) -CXX := $(TOOLCHAIN)/bin/$(HOST)-g++ --sysroot=$(SYSROOT) -OBJDUMP := $(TOOLCHAIN)/bin/$(HOST)-objdump -RANLIB := $(TOOLCHAIN)/bin/$(HOST)-ranlib -STRIP := $(TOOLCHAIN)/bin/$(HOST)-strip -AR := $(TOOLCHAIN)/bin/$(HOST)-ar -CXXCP := $(CXX) -E -PATH := $(PREFIX)/bin:$(BUILDROOT)/output/host/usr/bin:$(PATH) - -CFLAGS += -pipe -mfloat-abi=$(FLOAT) -mcpu=arm1176jzf-s -fomit-frame-pointer -mabi=aapcs-linux -mtune=arm1176jzf-s -mfpu=vfp -Wno-psabi -mno-apcs-stack-check -g -mstructure-size-boundary=32 -mno-sched-prolog -LDFLAGS += -L$(SDKSTAGE)/lib -L$(SDKSTAGE)/usr/lib -L$(SDKSTAGE)/opt/vc/lib/ -Lpcre/build -#INCLUDES += -isystem$(SDKSTAGE)/usr/include -isystem$(SDKSTAGE)/opt/vc/include -isystem$(SYSROOT)/usr/include -isystem$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -isystem$(SDKSTAGE)/usr/include/freetype2 -INCLUDES += -isystem$(SDKSTAGE)/opt/vc/include -isystem$(SYSROOT)/usr/include -isystem$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -Ipcre/build -Iboost-trunk -Ifreetype2/include +INCLUDES:=-I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux +INCLUDES+=-I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include +LDFLAGS:=-L/opt/vc/lib -Wl,-rpath,/opt/vc/lib +LDFLAGS+=-lfreetype -ldbus-1 +STRIP:=echo diff --git a/OMXAudio.cpp b/OMXAudio.cpp index 41f282d..e1e82c4 100644 --- a/OMXAudio.cpp +++ b/OMXAudio.cpp @@ -112,6 +112,11 @@ bool COMXAudio::PortSettingsChanged() if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit)) return false; } + if (m_config.device == "omx:alsa") + { + if(!m_omx_render_analog.Initialize("OMX.XBMC.alsa.alsasink", OMX_IndexParamAudioInit)) + return false; + } UpdateAttenuation(); diff --git a/OMXCore.cpp b/OMXCore.cpp index 9d5fe61..389c41e 100644 --- a/OMXCore.cpp +++ b/OMXCore.cpp @@ -35,6 +35,7 @@ #ifdef TARGET_LINUX #include "XMemUtils.h" +#include "alsa/omx_loader_XBMC.h" #endif //#define OMX_DEBUG_EVENTS @@ -1430,6 +1431,12 @@ bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEX if(!m_handle) { omx_err = m_DllOMX->OMX_GetHandle(&m_handle, (char*)component_name.c_str(), this, &m_callbacks); +#ifdef TARGET_LINUX + if (strncmp("OMX.XBMC.", component_name.c_str(), 9) == 0) + omx_err = OMX_GetHandle_XBMC(&m_handle, (char*) component_name.c_str(), this, &m_callbacks); + else +#endif + omx_err = m_DllOMX->OMX_GetHandle(&m_handle, (char*)component_name.c_str(), this, &m_callbacks); if (!m_handle || omx_err != OMX_ErrorNone) { CLog::Log(LOGERROR, "COMXCoreComponent::Initialize - could not get component handle for %s omx_err(0x%08x)\n", @@ -1505,6 +1512,11 @@ bool COMXCoreComponent::Deinitialize() CLog::Log(LOGDEBUG, "COMXCoreComponent::Deinitialize : %s handle %p\n", m_componentName.c_str(), m_handle); +#ifdef TARGET_LINUX + if (strncmp("OMX.XBMC.", m_componentName.c_str(), 9) == 0) + omx_err = OMX_FreeHandle_XBMC(m_handle); + else +#endif omx_err = m_DllOMX->OMX_FreeHandle(m_handle); if (omx_err != OMX_ErrorNone) { diff --git a/README.md b/README.md index 2eb78f3..f70d73c 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Usage: omxplayer [OPTIONS] [FILE] -v --version Print version info -k --keys Print key bindings -n --aidx index Audio stream index : e.g. 1 - -o --adev device Audio out device : e.g. hdmi/local/both + -o --adev device Audio out device : e.g. hdmi/local/both/alsa -i --info Dump stream format and exit -I --with-info dump stream format before playback -s --stats Pts and buffer stats diff --git a/alsa/omx_alsasink_component.cpp b/alsa/omx_alsasink_component.cpp new file mode 100644 index 0000000..9803e63 --- /dev/null +++ b/alsa/omx_alsasink_component.cpp @@ -0,0 +1,1035 @@ +/** + @file src/components/alsa/omx_alsasink_component.c + + OpenMAX ALSA sink component. This component is an audio sink that uses ALSA library. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-08-08 06:56:06 +0200 (Fri, 08 Aug 2008) $ + Revision $Rev: 581 $ + Author $Author: pankaj_sen $ + +*/ + +#undef OMX_SKIP64BIT +#include +#include +#include +#include + +/** Maximum Number of AlsaSink Instance*/ +#define MAX_COMPONENT_ALSASINK 1 + +/** Number of AlsaSink Instance*/ +static OMX_U32 noAlsasinkInstance=0; + +#ifdef AV_SYNC_LOG /* for checking AV sync */ //TODO : give seg fault if enabled +static FILE *fd = NULL; +#endif + +/** The Constructor + */ +OMX_ERRORTYPE omx_alsasink_component_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName) { + int err; + int omxErr; + omx_base_audio_PortType *pPort; + omx_alsasink_component_PrivateType* omx_alsasink_component_Private; + + if (!openmaxStandComp->pComponentPrivate) { + openmaxStandComp->pComponentPrivate = calloc(1, sizeof(omx_alsasink_component_PrivateType)); + if(openmaxStandComp->pComponentPrivate==NULL) { + return OMX_ErrorInsufficientResources; + } + } + + omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*)openmaxStandComp->pComponentPrivate; + omx_alsasink_component_Private->ports = NULL; + + omxErr = omx_base_sink_Constructor(openmaxStandComp,cComponentName); + if (omxErr != OMX_ErrorNone) { + return OMX_ErrorInsufficientResources; + } + + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio].nStartPortNumber = 0; + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts = 1; + + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther].nStartPortNumber = 1; + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts = 1; + + /** Allocate Ports and call port constructor. */ + if ((omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts) + && !omx_alsasink_component_Private->ports) { + omx_alsasink_component_Private->ports = (omx_base_PortType**)calloc((omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts), sizeof(omx_base_PortType *)); + if (!omx_alsasink_component_Private->ports) { + return OMX_ErrorInsufficientResources; + } + omx_alsasink_component_Private->ports[0] = (omx_base_PortType*)calloc(1, sizeof(omx_base_audio_PortType)); + if (!omx_alsasink_component_Private->ports[0]) { + return OMX_ErrorInsufficientResources; + } + base_audio_port_Constructor(openmaxStandComp, &omx_alsasink_component_Private->ports[0], 0, OMX_TRUE); + + omx_alsasink_component_Private->ports[1] = (omx_base_PortType*)calloc(1, sizeof(omx_base_clock_PortType)); + if (!omx_alsasink_component_Private->ports[1]) { + return OMX_ErrorInsufficientResources; + } + base_clock_port_Constructor(openmaxStandComp, &omx_alsasink_component_Private->ports[1], 1, OMX_TRUE); + omx_alsasink_component_Private->ports[1]->sPortParam.bEnabled = OMX_FALSE; + } + + pPort = (omx_base_audio_PortType *) omx_alsasink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + + // set the pPort params, now that the ports exist + /** Domain specific section for the ports. */ + pPort->sPortParam.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + /*Input pPort buffer size is equal to the size of the output buffer of the previous component*/ + pPort->sPortParam.nBufferSize = DEFAULT_OUT_BUFFER_SIZE; + + /* Initializing the function pointers */ + omx_alsasink_component_Private->BufferMgmtCallback = omx_alsasink_component_BufferMgmtCallback; + omx_alsasink_component_Private->destructor = omx_alsasink_component_Destructor; + pPort->Port_SendBufferFunction = omx_alsasink_component_port_SendBufferFunction; + pPort->FlushProcessingBuffers = omx_alsasink_component_port_FlushProcessingBuffers; + + setHeader(&pPort->sAudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); + pPort->sAudioParam.nPortIndex = 0; + pPort->sAudioParam.nIndex = 0; + pPort->sAudioParam.eEncoding = OMX_AUDIO_CodingPCM; + + /* OMX_AUDIO_PARAM_PCMMODETYPE */ + setHeader(&omx_alsasink_component_Private->sPCMModeParam, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + omx_alsasink_component_Private->sPCMModeParam.nPortIndex = 0; + omx_alsasink_component_Private->sPCMModeParam.nChannels = 2; + omx_alsasink_component_Private->sPCMModeParam.eNumData = OMX_NumericalDataSigned; + omx_alsasink_component_Private->sPCMModeParam.eEndian = OMX_EndianLittle; + omx_alsasink_component_Private->sPCMModeParam.bInterleaved = OMX_TRUE; + omx_alsasink_component_Private->sPCMModeParam.nBitPerSample = 16; + omx_alsasink_component_Private->sPCMModeParam.nSamplingRate = 44100; + omx_alsasink_component_Private->sPCMModeParam.ePCMMode = OMX_AUDIO_PCMModeLinear; + omx_alsasink_component_Private->sPCMModeParam.eChannelMapping[0] = OMX_AUDIO_ChannelNone; + +/* testing the A/V sync */ +#ifdef AV_SYNC_LOG + fd = fopen("audio_timestamps.out","w"); + if(!fd) { + DEBUG(DEB_LEV_ERR, "Couldn't open audio timestamp log err=%d\n",errno); + } +#endif + + noAlsasinkInstance++; + if(noAlsasinkInstance > MAX_COMPONENT_ALSASINK) { + return OMX_ErrorInsufficientResources; + } + + /* Allocate the playback handle and the hardware parameter structure */ + char* name = "default"; + if ((err = snd_pcm_open (&omx_alsasink_component_Private->playback_handle, name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot open audio device %s (%s)\n", name, snd_strerror (err)); + return OMX_ErrorHardware; + } + else + DEBUG(DEB_LEV_SIMPLE_SEQ, "Got playback handle at %p %p in %i\n", omx_alsasink_component_Private->playback_handle, &omx_alsasink_component_Private->playback_handle, getpid()); + + if (snd_pcm_status_malloc(&omx_alsasink_component_Private->pcm_status) < 0 ) { + DEBUG(DEB_LEV_ERR, "%s: failed allocating pcm_status\n", __func__); + return OMX_ErrorHardware; + } + + openmaxStandComp->SetParameter = omx_alsasink_component_SetParameter; + openmaxStandComp->GetParameter = omx_alsasink_component_GetParameter; + openmaxStandComp->GetConfig = omx_alsasink_component_GetConfig; + + /* Write in the default parameters */ + omx_alsasink_component_Private->AudioPCMConfigured = 0; + omx_alsasink_component_Private->eState = OMX_TIME_ClockStateStopped; + omx_alsasink_component_Private->xScale = 1<<16; + + if (!omx_alsasink_component_Private->AudioPCMConfigured) { + DEBUG(DEB_LEV_SIMPLE_SEQ, "Configuring the PCM interface in the Init function\n"); + omxErr = omx_alsasink_component_SetParameter(openmaxStandComp, OMX_IndexParamAudioPcm, &omx_alsasink_component_Private->sPCMModeParam); + if(omxErr != OMX_ErrorNone){ + DEBUG(DEB_LEV_ERR, "In %s Error %08x\n",__func__,omxErr); + } + } + + return OMX_ErrorNone; +} + +/** The Destructor + */ +OMX_ERRORTYPE omx_alsasink_component_Destructor(OMX_COMPONENTTYPE *openmaxStandComp) { + omx_alsasink_component_PrivateType* omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*)openmaxStandComp->pComponentPrivate; + OMX_U32 i; + + if(omx_alsasink_component_Private->pcm_status) { + snd_pcm_status_free(omx_alsasink_component_Private->pcm_status); + } + if(omx_alsasink_component_Private->playback_handle) { + snd_pcm_close(omx_alsasink_component_Private->playback_handle); + } + + /* frees port/s */ + if (omx_alsasink_component_Private->ports) { + for (i=0; i < (omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts); i++) { + if(omx_alsasink_component_Private->ports[i]) + omx_alsasink_component_Private->ports[i]->PortDestructor(omx_alsasink_component_Private->ports[i]); + } + free(omx_alsasink_component_Private->ports); + omx_alsasink_component_Private->ports=NULL; + } + +#ifdef AV_SYNC_LOG + fclose(fd); +#endif + + noAlsasinkInstance--; + + return omx_base_sink_Destructor(openmaxStandComp); + +} + +/** @brief the entry point for sending buffers to the alsa sink port + * + * This function can be called by the EmptyThisBuffer or FillThisBuffer. It depends on + * the nature of the port, that can be an input or output port. + */ +OMX_ERRORTYPE omx_alsasink_component_port_SendBufferFunction(omx_base_PortType *openmaxStandPort, OMX_BUFFERHEADERTYPE* pBuffer) { + + OMX_ERRORTYPE err; + OMX_U32 portIndex; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + OMX_BOOL SendFrame; + omx_base_clock_PortType* pClockPort; +#if NO_GST_OMX_PATCH + unsigned int i; +#endif + + portIndex = (openmaxStandPort->sPortParam.eDir == OMX_DirInput)?pBuffer->nInputPortIndex:pBuffer->nOutputPortIndex; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s portIndex %lu\n", __func__, (unsigned long)portIndex); + + if (portIndex != openmaxStandPort->sPortParam.nPortIndex) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port for this operation portIndex=%d port->portIndex=%d\n", + __func__, (int)portIndex, (int)openmaxStandPort->sPortParam.nPortIndex); + return OMX_ErrorBadPortIndex; + } + + if(omx_base_component_Private->state == OMX_StateInvalid) { + DEBUG(DEB_LEV_ERR, "In %s: we are in OMX_StateInvalid\n", __func__); + return OMX_ErrorInvalidState; + } + + if(omx_base_component_Private->state != OMX_StateExecuting && + omx_base_component_Private->state != OMX_StatePause && + omx_base_component_Private->state != OMX_StateIdle) { + DEBUG(DEB_LEV_ERR, "In %s: we are not in executing/paused/idle state, but in %d\n", __func__, omx_base_component_Private->state); + return OMX_ErrorIncorrectStateOperation; + } + if (!PORT_IS_ENABLED(openmaxStandPort) || (PORT_IS_BEING_DISABLED(openmaxStandPort) && !PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) || + (omx_base_component_Private->transientState == OMX_TransStateExecutingToIdle && + (PORT_IS_TUNNELED(openmaxStandPort) && !PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)))) { + DEBUG(DEB_LEV_ERR, "In %s: Port %d is disabled comp = %s \n", __func__, (int)portIndex,omx_base_component_Private->name); + return OMX_ErrorIncorrectStateOperation; + } + + /* Temporarily disable this check for gst-openmax */ +#if NO_GST_OMX_PATCH + { + OMX_BOOL foundBuffer = OMX_FALSE; + if(pBuffer!=NULL && pBuffer->pBuffer!=NULL) { + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (pBuffer->pBuffer == openmaxStandPort->pInternalBufferStorage[i]->pBuffer) { + foundBuffer = OMX_TRUE; + break; + } + } + } + if (!foundBuffer) { + return OMX_ErrorBadParameter; + } + } +#endif + + if ((err = checkHeader(pBuffer, sizeof(OMX_BUFFERHEADERTYPE))) != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s: received wrong buffer header on input port\n", __func__); + return err; + } + + /* And notify the buffer management thread we have a fresh new buffer to manage */ + if(!PORT_IS_BEING_FLUSHED(openmaxStandPort) && !(PORT_IS_BEING_DISABLED(openmaxStandPort) && PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort))){ + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + //DEBUG(DEB_LEV_PARAMS, "In %s Signalling bMgmtSem Port Index=%d\n",__func__, (int)portIndex); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + }else if(PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)){ + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Comp %s received io:%d buffer\n", + __func__,omx_base_component_Private->name,(int)openmaxStandPort->sPortParam.nPortIndex); + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + } + else { // If port being flushed and not tunneled then return error + DEBUG(DEB_LEV_FULL_SEQ, "In %s \n", __func__); + return OMX_ErrorIncorrectStateOperation; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_alsasink_component_GetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_INOUT OMX_PTR pComponentConfigStructure) { + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (nIndex == OMX_IndexConfigAudioRenderingLatency) { + OMX_PARAM_U32TYPE* param = (OMX_PARAM_U32TYPE*)pComponentConfigStructure; + + omx_alsasink_component_PrivateType* omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + + if (param->nPortIndex == OMX_BASE_SINK_INPUTPORT_INDEX ) { + // As this is used only as bool, we can return 'just something' here. + // TODO: Add appropriate processing when needed + param->nU32 = omx_alsasink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]->pBufferQueue->nelem; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_IndexConfigAudioRenderingLatency return %d\n", __func__, param->nU32); + return OMX_ErrorNone; + } + } + + return OMX_ErrorNotImplemented; +} + + +OMX_BOOL omx_alsasink_component_ClockPortHandleFunction(omx_alsasink_component_PrivateType* omx_alsasink_component_Private, OMX_BUFFERHEADERTYPE* inputbuffer){ + omx_base_clock_PortType* pClockPort; + OMX_BUFFERHEADERTYPE* clockBuffer; + OMX_TIME_MEDIATIMETYPE* pMediaTime; + OMX_HANDLETYPE hclkComponent; + OMX_TIME_CONFIG_TIMESTAMPTYPE sClientTimeStamp; + OMX_ERRORTYPE err; + OMX_BOOL SendFrame=OMX_TRUE; + omx_base_audio_PortType *pAudioPort; + + int static count=0; //frame counter + + pClockPort = (omx_base_clock_PortType*)omx_alsasink_component_Private->ports[OMX_BASE_SINK_CLOCKPORT_INDEX]; + pAudioPort = (omx_base_audio_PortType *) omx_alsasink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + hclkComponent = pClockPort->hTunneledComponent; + setHeader(&pClockPort->sMediaTimeRequest, sizeof(OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE)); + + /* check for any scale change information from the clock component */ + if(pClockPort->pBufferSem->semval>0){ + omx_tsem_down(pClockPort->pBufferSem); + if(pClockPort->pBufferQueue->nelem > 0) { + clockBuffer = (OMX_BUFFERHEADERTYPE*)omx_dequeue(pClockPort->pBufferQueue); + pMediaTime = (OMX_TIME_MEDIATIMETYPE*)clockBuffer->pBuffer; + if(pMediaTime->eUpdateType==OMX_TIME_UpdateScaleChanged) { + //if((pMediaTime->xScale>>16)==1){ /* check with Q16 format only */ + // /* rebase the clock time base when turning to normal play mode*/ + // hclkComponent = pClockPort->hTunneledComponent; + // setHeader(&sClientTimeStamp, sizeof(OMX_TIME_CONFIG_TIMESTAMPTYPE)); + // sClientTimeStamp.nPortIndex = pClockPort->nTunneledPort; + // sClientTimeStamp.nTimestamp = inputbuffer->nTimeStamp; + // err = OMX_SetConfig(hclkComponent, OMX_IndexConfigTimeCurrentAudioReference, &sClientTimeStamp); + // if(err!=OMX_ErrorNone) { + // DEBUG(DEB_LEV_ERR,"Error %08x In OMX_SetConfig in func=%s line=%d\n",err,__func__, __LINE__); + // } + //} + omx_alsasink_component_Private->eState = pMediaTime->eState; + omx_alsasink_component_Private->xScale = pMediaTime->xScale; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s OMX_TIME_UpdateScaleChanged Line=%d new eState=%d xScale=%d\n", + __func__, __LINE__, pMediaTime->eState, pMediaTime->xScale); + /// AND + } else if(pMediaTime->eUpdateType==OMX_TIME_UpdateClockStateChanged) { + omx_alsasink_component_Private->eState = pMediaTime->eState; + omx_alsasink_component_Private->xScale = pMediaTime->xScale; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s OMX_TIME_UpdateClockStateChanged Line=%d new eState=%d xScale=%d\n", + __func__, __LINE__, pMediaTime->eState, pMediaTime->xScale); + } + /// AND + pClockPort->ReturnBufferFunction((omx_base_PortType*)pClockPort,clockBuffer); + } + } + + /* if first time stamp is received then notify the clock component */ + if(inputbuffer->nFlags == OMX_BUFFERFLAG_STARTTIME) { + DEBUG(DEB_LEV_FULL_SEQ,"In %s first time stamp = %llx \n", __func__,(long long)inputbuffer->nTimeStamp); + inputbuffer->nFlags = 0; + hclkComponent = pClockPort->hTunneledComponent; + setHeader(&sClientTimeStamp, sizeof(OMX_TIME_CONFIG_TIMESTAMPTYPE)); + sClientTimeStamp.nPortIndex = pClockPort->nTunneledPort; + sClientTimeStamp.nTimestamp = inputbuffer->nTimeStamp; + err = OMX_SetConfig(hclkComponent, OMX_IndexConfigTimeClientStartTime, &sClientTimeStamp); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"Error %08x In OMX_SetConfig in func=%s \n",err,__func__); + } + + if(!PORT_IS_BEING_FLUSHED(pAudioPort) && !PORT_IS_BEING_FLUSHED(pClockPort)) { + omx_tsem_down(pClockPort->pBufferSem); /* wait for state change notification from clock src*/ + + /* update the clock state and clock scale info into the alsa sink private data */ + if(pClockPort->pBufferQueue->nelem > 0) { + clockBuffer = (OMX_BUFFERHEADERTYPE*)omx_dequeue(pClockPort->pBufferQueue); + pMediaTime = (OMX_TIME_MEDIATIMETYPE*)clockBuffer->pBuffer; + omx_alsasink_component_Private->eState = pMediaTime->eState; + omx_alsasink_component_Private->xScale = pMediaTime->xScale; + pClockPort->ReturnBufferFunction((omx_base_PortType*)pClockPort,clockBuffer); + } + } + } + + /* do not send the data to alsa and return back, if the clock is not running or the scale is anything but 1*/ + /*if(!(omx_alsasink_component_Private->eState==OMX_TIME_ClockStateRunning && omx_alsasink_component_Private->xScale==(1<<16))){ + // TODO: 0 means PAUSED. is correct to keep that frame? + if ((omx_alsasink_component_Private->xScale!=0) && (omx_alsasink_component_Private->xScale!=(1<<16))){ + inputbuffer->nFilledLen=0; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s Dropping frame !!!!! eState=%d xScale=%d\n", __func__, omx_alsasink_component_Private->eState, omx_alsasink_component_Private->xScale); + } + //return; + SendFrame = OMX_FALSE; + return SendFrame; + }*/ + + count++; + if(count==15) { //send request for every 15th frame + count=0; + + OMX_TIME_CONFIG_TIMESTAMPTYPE ts; + setHeader(&ts, sizeof(OMX_TIME_CONFIG_TIMESTAMPTYPE)); + ts.nPortIndex = pClockPort->nTunneledPort; + + snd_pcm_sframes_t avail = 0; + int diff = 0; + snd_pcm_sframes_t delay = 0; + + OMX_AUDIO_PARAM_PCMMODETYPE* sPCMModeParam = &omx_alsasink_component_Private->sPCMModeParam; + + //snd_pcm_delay(omx_alsasink_component_Private->playback_handle, &delay); + // snd_pcm_avail() & snd_pcm_avail_update() are broken on raspberry pi!!!! + //avail = snd_pcm_avail(omx_alsasink_component_Private->playback_handle); + + if (snd_pcm_status(omx_alsasink_component_Private->playback_handle, omx_alsasink_component_Private->pcm_status) < 0) { + DEBUG(DEB_LEV_ERR,"In %s unable to obtain pcm_status.\n",__func__); + } + + delay = snd_pcm_status_get_delay(omx_alsasink_component_Private->pcm_status); + avail = (snd_pcm_sframes_t) snd_pcm_status_get_avail(omx_alsasink_component_Private->pcm_status); + + diff = ((double)(delay - avail) / sPCMModeParam->nSamplingRate) * 1000 * 1000; // in microseconds !!! + + //DEBUG(DEB_LEV_FULL_SEQ,"In %s delay=%d avail=%d diff=%d inputbuffer->nTimeStamp=%lld corected nTimeStamp=%lld\n", + // __func__, delay, avail, diff, inputbuffer->nTimeStamp, inputbuffer->nTimeStamp - (OMX_TICKS)diff); + + ts.nTimestamp = inputbuffer->nTimeStamp - (OMX_TICKS)diff; + + if (OMX_ErrorNone != OMX_SetConfig(hclkComponent, OMX_IndexConfigTimeCurrentAudioReference,&ts)) { + DEBUG(DEB_LEV_ERR,"In %s unable to update reference clock.\n",__func__); + } + +#if 0 + /* requesting for the timestamp for the data delivery */ + if(!PORT_IS_BEING_FLUSHED(pAudioPort) && !PORT_IS_BEING_FLUSHED(pClockPort)&& + omx_alsasink_component_Private->transientState != OMX_TransStateExecutingToIdle) { + pClockPort->sMediaTimeRequest.nOffset = 100; /*set the requested offset */ + pClockPort->sMediaTimeRequest.nPortIndex = pClockPort->nTunneledPort; + pClockPort->sMediaTimeRequest.pClientPrivate = NULL; /* fill the appropriate value */ + pClockPort->sMediaTimeRequest.nMediaTimestamp = inputbuffer->nTimeStamp; + err = OMX_SetConfig(hclkComponent, OMX_IndexConfigTimeMediaTimeRequest, &pClockPort->sMediaTimeRequest); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"Error %08x In OMX_SetConfig in func=%s \n",err,__func__); + } + if(!PORT_IS_BEING_FLUSHED(pAudioPort) && !PORT_IS_BEING_FLUSHED(pClockPort) && + omx_alsasink_component_Private->transientState != OMX_TransStateExecutingToIdle) { + omx_tsem_down(pClockPort->pBufferSem); /* wait for the request fullfillment */ + if(pClockPort->pBufferQueue->nelem > 0) { + clockBuffer = omx_dequeue(pClockPort->pBufferQueue); + pMediaTime = (OMX_TIME_MEDIATIMETYPE*)clockBuffer->pBuffer; + if(pMediaTime->eUpdateType==OMX_TIME_UpdateScaleChanged) { + /// AND + //if((pMediaTime->xScale>>16)==1){ /* check with Q16 format only */ + // /* rebase the clock time base when turning to normal play mode*/ + // hclkComponent = pClockPort->hTunneledComponent; + // setHeader(&sClientTimeStamp, sizeof(OMX_TIME_CONFIG_TIMESTAMPTYPE)); + // sClientTimeStamp.nPortIndex = pClockPort->nTunneledPort; + // sClientTimeStamp.nTimestamp = inputbuffer->nTimeStamp; + // err = OMX_SetConfig(hclkComponent, OMX_IndexConfigTimeCurrentAudioReference, &sClientTimeStamp); + // if(err!=OMX_ErrorNone) { + // DEBUG(DEB_LEV_ERR,"Error %08x In OMX_SetConfig in func=%s line=%d\n",err,__func__, __LINE__); + // } + //} + /// AND + omx_alsasink_component_Private->eState = pMediaTime->eState; + omx_alsasink_component_Private->xScale = pMediaTime->xScale; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s OMX_TIME_UpdateScaleChanged Line=%d new eState=%d xScale=%d\n", + __func__, __LINE__, pMediaTime->eState, pMediaTime->xScale); + /// AND + } else if(pMediaTime->eUpdateType==OMX_TIME_UpdateClockStateChanged) { + omx_alsasink_component_Private->eState = pMediaTime->eState; + omx_alsasink_component_Private->xScale = pMediaTime->xScale; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s OMX_TIME_UpdateClockStateChanged Line=%d new eState=%d xScale=%d\n", + __func__, __LINE__, pMediaTime->eState, pMediaTime->xScale); + } + /// AND + if(pMediaTime->eUpdateType==OMX_TIME_UpdateRequestFulfillment) { + if((pMediaTime->nOffset)>0) { +#ifdef AV_SYNC_LOG + fprintf(fd,"%lld %lld\n",inputbuffer->nTimeStamp,pMediaTime->nWallTimeAtMediaTime); +#endif + SendFrame = OMX_TRUE; /* as offset is >0 send the data to the device */ + } + else { + SendFrame = OMX_FALSE; /* as offset is <0 do not send the data to the device */ + //DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s Dropping frame !!!!! nOffset>0 !!! nOffset=%ll\n", __func__, pMediaTime->nOffset); + } + } + pClockPort->ReturnBufferFunction((omx_base_PortType*)pClockPort,clockBuffer); + } + } + } +#endif + } + + return(SendFrame); +} + +/** @brief Releases buffers under processing. + * This function must be implemented in the derived classes, for the + * specific processing + */ +OMX_ERRORTYPE omx_alsasink_component_port_FlushProcessingBuffers(omx_base_PortType *openmaxStandPort) { + omx_base_component_PrivateType* omx_base_component_Private; + omx_alsasink_component_PrivateType* omx_alsasink_component_Private; + OMX_BUFFERHEADERTYPE* pBuffer; + omx_base_clock_PortType *pClockPort; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandPort->standCompContainer->pComponentPrivate; + omx_alsasink_component_Private = ( omx_alsasink_component_PrivateType*) omx_base_component_Private; + + pClockPort = (omx_base_clock_PortType*) omx_alsasink_component_Private->ports[OMX_BASE_SINK_CLOCKPORT_INDEX]; + + if (!PORT_IS_ENABLED(openmaxStandPort) || PORT_IS_BEING_DISABLED(openmaxStandPort)) { + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s ---------- waiting for buffers. qelem=%d\n",__func__,openmaxStandPort->pBufferQueue->nelem); + int nRetry = 0; + while((openmaxStandPort->pBufferQueue->nelem != openmaxStandPort->nNumAssignedBuffers) && + (nRetry < TUNNEL_USE_BUFFER_RETRY)){ + usleep(TUNNEL_USE_BUFFER_RETRY_USLEEP_TIME); + nRetry++; + } + if (nRetry == TUNNEL_USE_BUFFER_RETRY){ + // In some rare cases we can't collect all buffers back + DEBUG(DEB_LEV_ERR, "In %s Failed to get buffers back. Got a buffer qelem=%d\n",__func__,openmaxStandPort->pBufferQueue->nelem); + } + else{ + DEBUG(DEB_LEV_FULL_SEQ, "In %s All buffers returned in %d iterations.\n",__func__, nRetry); + } + + omx_tsem_reset(openmaxStandPort->pBufferSem); + } + return OMX_ErrorNone; + } + + if(openmaxStandPort->sPortParam.eDomain!=OMX_PortDomainOther) { /* clock buffers not used in the clients buffer managment function */ + pthread_mutex_lock(&omx_base_component_Private->flush_mutex); + openmaxStandPort->bIsPortFlushed=OMX_TRUE; + /*Signal the buffer management thread of port flush,if it is waiting for buffers*/ + if(omx_base_component_Private->bMgmtSem->semval==0) { + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + + if(omx_base_component_Private->state==OMX_StatePause ) { + /*Waiting at paused state*/ + omx_tsem_signal(omx_base_component_Private->bStateSem); + } + DEBUG(DEB_LEV_FULL_SEQ, "In %s waiting for flush all condition port index =%d\n", __func__,(int)openmaxStandPort->sPortParam.nPortIndex); + /* Wait until flush is completed */ + pthread_mutex_unlock(&omx_base_component_Private->flush_mutex); + + /*Dummy signal to clock port*/ + if(pClockPort->pBufferSem->semval == 0) { + omx_tsem_up(pClockPort->pBufferSem); + } + omx_tsem_down(omx_base_component_Private->flush_all_condition); + if(pClockPort->pBufferSem->semval > 0) { + omx_tsem_down(pClockPort->pBufferSem); + } + } + + omx_tsem_reset(omx_base_component_Private->bMgmtSem); + + /* Flush all the buffers not under processing */ + while (openmaxStandPort->pBufferSem->semval > 0) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s TFlag=%x Flusing Port=%d,Semval=%d Qelem=%d\n", + __func__,(int)openmaxStandPort->nTunnelFlags,(int)openmaxStandPort->sPortParam.nPortIndex, + (int)openmaxStandPort->pBufferSem->semval,(int)openmaxStandPort->pBufferQueue->nelem); + + omx_tsem_down(openmaxStandPort->pBufferSem); + pBuffer = (OMX_BUFFERHEADERTYPE*)omx_dequeue(openmaxStandPort->pBufferQueue); + if (PORT_IS_TUNNELED(openmaxStandPort)) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Comp %s is returning io:%d buffer\n", + __func__,omx_base_component_Private->name,(int)openmaxStandPort->sPortParam.nPortIndex); + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->FillThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + } else { + ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->EmptyThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + } + } else { + (*(openmaxStandPort->BufferProcessedCallback))( + openmaxStandPort->standCompContainer, + omx_base_component_Private->callbackData, + pBuffer); + } + } + + pthread_mutex_lock(&omx_base_component_Private->flush_mutex); + openmaxStandPort->bIsPortFlushed=OMX_FALSE; + pthread_mutex_unlock(&omx_base_component_Private->flush_mutex); + + omx_tsem_up(omx_base_component_Private->flush_condition); + + DEBUG(DEB_LEV_FULL_SEQ, "Out %s Port Index=%d bIsPortFlushed=%d Component %s\n", __func__, + (int)openmaxStandPort->sPortParam.nPortIndex,(int)openmaxStandPort->bIsPortFlushed,omx_base_component_Private->name); + + DEBUG(DEB_LEV_PARAMS, "In %s TFlag=%x Qelem=%d BSem=%d bMgmtsem=%d component=%s\n", __func__, + (int)openmaxStandPort->nTunnelFlags, + (int)openmaxStandPort->pBufferQueue->nelem, + (int)openmaxStandPort->pBufferSem->semval, + (int)omx_base_component_Private->bMgmtSem->semval, + omx_base_component_Private->name); + + DEBUG(DEB_LEV_FUNCTION_NAME, "Out %s Port Index=%d\n", __func__,(int)openmaxStandPort->sPortParam.nPortIndex); + + return OMX_ErrorNone; +} + +/** + * This function plays the input buffer. When fully consumed it returns. + */ +void omx_alsasink_component_BufferMgmtCallback(OMX_COMPONENTTYPE *openmaxStandComp, OMX_BUFFERHEADERTYPE* inputbuffer) { + OMX_U32 frameSize; + OMX_S32 written; + OMX_S32 totalBuffer; + OMX_S32 offsetBuffer; + OMX_BOOL allDataSent; + omx_alsasink_component_PrivateType* omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*) openmaxStandComp->pComponentPrivate; + + frameSize = (omx_alsasink_component_Private->sPCMModeParam.nChannels * omx_alsasink_component_Private->sPCMModeParam.nBitPerSample) >> 3; + //DEBUG(DEB_LEV_FULL_SEQ, "Framesize is %u chl=%d bufSize=%d\n", + //(int)frameSize, (int)omx_alsasink_component_Private->sPCMModeParam.nChannels, (int)inputbuffer->nFilledLen); + + if(inputbuffer->nFilledLen < frameSize){ + DEBUG(DEB_LEV_ERR, "Ouch!! In %s input buffer filled len(%d) less than frame size(%d)\n",__func__, (int)inputbuffer->nFilledLen, (int)frameSize); + return; + } + + allDataSent = OMX_FALSE; + + totalBuffer = inputbuffer->nFilledLen/frameSize; + + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omx_alsasink_component_Private; + omx_base_clock_PortType*pClockPort = (omx_base_clock_PortType*)omx_base_component_Private->ports[OMX_BASE_SINK_CLOCKPORT_INDEX]; + omx_base_PortType *openmaxStandPort = omx_base_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + if(PORT_IS_TUNNELED(pClockPort) && !PORT_IS_BEING_FLUSHED(openmaxStandPort) && + (omx_base_component_Private->transientState != OMX_TransStateExecutingToIdle) && + (inputbuffer->nFlags != OMX_BUFFERFLAG_EOS)){ + omx_alsasink_component_ClockPortHandleFunction(omx_alsasink_component_Private, inputbuffer); + if(inputbuffer->nFilledLen == 0) + { + // Dropped frame by clock + return; + } + } + + /* Feed it to ALSA */ + + offsetBuffer = 0; + while (!allDataSent) { + DEBUG(DEB_LEV_SIMPLE_SEQ, "Writing to the device ..\n"); + written = snd_pcm_writei(omx_alsasink_component_Private->playback_handle, inputbuffer->pBuffer + (offsetBuffer * frameSize), totalBuffer); + if (written < 0) { + if(written == -EPIPE){ + DEBUG(DEB_LEV_ERR, "ALSA Underrun..\n"); + snd_pcm_prepare(omx_alsasink_component_Private->playback_handle); + written = 0; + } else { + DEBUG(DEB_LEV_ERR, "Cannot send any data to the audio device %s (%s)\n", "default", snd_strerror (written)); + DEBUG(DEB_LEV_ERR, "IB FilledLen=%d,totalBuffer=%d,frame size=%d,offset=%d\n", + (int)inputbuffer->nFilledLen, (int)totalBuffer, (int)frameSize, (int)offsetBuffer); + break; + return; + } + } + + if(written != totalBuffer){ + totalBuffer = totalBuffer - written; + offsetBuffer = written; + } else { + DEBUG(DEB_LEV_FULL_SEQ, "Buffer successfully sent to ALSA. Length was %i\n", (int)inputbuffer->nFilledLen); + allDataSent = OMX_TRUE; + } + } + + inputbuffer->nFilledLen=0; +} + +OMX_ERRORTYPE omx_alsasink_component_SetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_IN OMX_PTR ComponentParameterStructure) +{ + int err; + OMX_ERRORTYPE omxErr = OMX_ErrorNone; + OMX_AUDIO_PARAM_PORTFORMATTYPE *pAudioPortFormat; + OMX_OTHER_PARAM_PORTFORMATTYPE *pOtherPortFormat; + OMX_AUDIO_PARAM_MP3TYPE * pAudioMp3; + OMX_U32 portIndex; + + /* Check which structure we are being fed and make control its header */ + OMX_COMPONENTTYPE *openmaxStandComp = (OMX_COMPONENTTYPE*)hComponent; + omx_alsasink_component_PrivateType* omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*)openmaxStandComp->pComponentPrivate; + omx_base_audio_PortType* pPort = (omx_base_audio_PortType *) omx_alsasink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + omx_base_clock_PortType *pClockPort; + snd_pcm_t* playback_handle = omx_alsasink_component_Private->playback_handle; + + if (ComponentParameterStructure == NULL) { + return OMX_ErrorBadParameter; + } + + DEBUG(DEB_LEV_SIMPLE_SEQ, " Setting parameter %i\n", nParamIndex); + + switch(nParamIndex) { + case OMX_IndexParamAudioPortFormat: + pAudioPortFormat = (OMX_AUDIO_PARAM_PORTFORMATTYPE*)ComponentParameterStructure; + portIndex = pAudioPortFormat->nPortIndex; + /*Check Structure Header and verify component state*/ + omxErr = omx_base_component_ParameterSanityCheck(hComponent, portIndex, pAudioPortFormat, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); + if(omxErr!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Parameter Check Error=%x\n", __func__, omxErr); + break; + } + if (portIndex < 1) { + memcpy(&pPort->sAudioParam,pAudioPortFormat,sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); + } else { + return OMX_ErrorBadPortIndex; + } + break; + case OMX_IndexParamOtherPortFormat: + pOtherPortFormat = (OMX_OTHER_PARAM_PORTFORMATTYPE*)ComponentParameterStructure; + portIndex = pOtherPortFormat->nPortIndex; + err = omx_base_component_ParameterSanityCheck(hComponent, portIndex, pOtherPortFormat, sizeof(OMX_OTHER_PARAM_PORTFORMATTYPE)); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Parameter Check Error=%x\n",__func__,err); + break; + } + if(portIndex != 1) { + return OMX_ErrorBadPortIndex; + } + pClockPort = (omx_base_clock_PortType *) omx_alsasink_component_Private->ports[portIndex]; + + pClockPort->sOtherParam.eFormat = pOtherPortFormat->eFormat; + break; + case OMX_IndexParamAudioPcm: + { + unsigned int rate; + OMX_AUDIO_PARAM_PCMMODETYPE* sPCMModeParam = (OMX_AUDIO_PARAM_PCMMODETYPE*)ComponentParameterStructure; + snd_pcm_hw_params_t *hw_params; + snd_pcm_hw_params_alloca(&hw_params); + + /** Each time we are (re)configuring the hw_params thing + * we need to reinitialize it, otherwise previous changes will not take effect. + * e.g.: changing a previously configured sampling rate does not have + * any effect if we are not calling this each time. + */ + snd_pcm_hw_params_any(omx_alsasink_component_Private->playback_handle, hw_params); + + portIndex = sPCMModeParam->nPortIndex; + /*Check Structure Header and verify component state*/ + omxErr = omx_base_component_ParameterSanityCheck(hComponent, portIndex, sPCMModeParam, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + if(omxErr!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Parameter Check Error=%x\n", __func__, omxErr); + break; + } + + omx_alsasink_component_Private->AudioPCMConfigured = 1; + if(sPCMModeParam->nPortIndex != omx_alsasink_component_Private->sPCMModeParam.nPortIndex){ + DEBUG(DEB_LEV_ERR, "Error setting input pPort index\n"); + omxErr = OMX_ErrorBadParameter; + break; + } + + if(snd_pcm_hw_params_set_channels(playback_handle, hw_params, sPCMModeParam->nChannels)){ + DEBUG(DEB_LEV_ERR, "Error setting number of channels\n"); + return OMX_ErrorBadParameter; + } + + if(sPCMModeParam->bInterleaved == OMX_TRUE){ + if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set access type intrleaved (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + } + else{ + if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set access type non interleaved (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + } + rate = sPCMModeParam->nSamplingRate; + if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set sample rate (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + else{ + DEBUG(DEB_LEV_SIMPLE_SEQ, "Set correctly sampling rate from %lu to %lu\n", (unsigned long)sPCMModeParam->nSamplingRate, (unsigned long)rate); + sPCMModeParam->nSamplingRate = rate; + } + + if(sPCMModeParam->ePCMMode == OMX_AUDIO_PCMModeLinear){ + snd_pcm_format_t snd_pcm_format = SND_PCM_FORMAT_UNKNOWN; + DEBUG(DEB_LEV_SIMPLE_SEQ, "Bit per sample %i, signed=%i, little endian=%i\n", + (int)sPCMModeParam->nBitPerSample, + (int)sPCMModeParam->eNumData == OMX_NumericalDataSigned, + (int)sPCMModeParam->eEndian == OMX_EndianLittle); + + switch(sPCMModeParam->nBitPerSample){ + case 8: + if(sPCMModeParam->eNumData == OMX_NumericalDataSigned) { + snd_pcm_format = SND_PCM_FORMAT_S8; + } else { + snd_pcm_format = SND_PCM_FORMAT_U8; + } + break; + case 16: + if(sPCMModeParam->eNumData == OMX_NumericalDataSigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle) { + snd_pcm_format = SND_PCM_FORMAT_S16_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_S16_BE; + } + } + if(sPCMModeParam->eNumData == OMX_NumericalDataUnsigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle){ + snd_pcm_format = SND_PCM_FORMAT_U16_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_U16_BE; + } + } + break; + case 24: + if(sPCMModeParam->eNumData == OMX_NumericalDataSigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle) { + snd_pcm_format = SND_PCM_FORMAT_S24_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_S24_BE; + } + } + if(sPCMModeParam->eNumData == OMX_NumericalDataUnsigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle) { + snd_pcm_format = SND_PCM_FORMAT_U24_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_U24_BE; + } + } + break; + + case 32: + if(sPCMModeParam->eNumData == OMX_NumericalDataSigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle) { + snd_pcm_format = SND_PCM_FORMAT_S32_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_S32_BE; + } + } + if(sPCMModeParam->eNumData == OMX_NumericalDataUnsigned){ + if(sPCMModeParam->eEndian == OMX_EndianLittle) { + snd_pcm_format = SND_PCM_FORMAT_U32_LE; + } else { + snd_pcm_format = SND_PCM_FORMAT_U32_BE; + } + } + break; + default: + omxErr = OMX_ErrorBadParameter; + break; + } + + if(snd_pcm_format != SND_PCM_FORMAT_UNKNOWN){ + if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, snd_pcm_format)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set sample format (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + memcpy(&omx_alsasink_component_Private->sPCMModeParam, ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + } else{ + DEBUG(DEB_LEV_SIMPLE_SEQ, "ALSA OMX_IndexParamAudioPcm configured\n"); + memcpy(&omx_alsasink_component_Private->sPCMModeParam, ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + } + } + else if(sPCMModeParam->ePCMMode == OMX_AUDIO_PCMModeALaw){ + DEBUG(DEB_LEV_SIMPLE_SEQ, "Configuring ALAW format\n\n"); + if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_A_LAW)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set sample format (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + memcpy(&omx_alsasink_component_Private->sPCMModeParam, ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + } + else if(sPCMModeParam->ePCMMode == OMX_AUDIO_PCMModeMULaw){ + DEBUG(DEB_LEV_SIMPLE_SEQ, "Configuring ALAW format\n\n"); + if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_MU_LAW)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set sample format (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + memcpy(&omx_alsasink_component_Private->sPCMModeParam, ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + } + + snd_pcm_uframes_t periodSize, bufferSize; + bufferSize = sPCMModeParam->nSamplingRate / 5; + periodSize = bufferSize / 4; //sPCMModeParam->nSamplingRate / 20; + + snd_pcm_uframes_t periodSizeMax = bufferSize / 3; + DEBUG(DEB_LEV_SIMPLE_SEQ, "trying snd_pcm_hw_params_set_period_size_max (%d)\n", (int)periodSizeMax); + if ((err = snd_pcm_hw_params_set_period_size_max(omx_alsasink_component_Private->playback_handle, hw_params, &periodSizeMax, NULL)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot snd_pcm_hw_params_set_period_size_max (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + + DEBUG(DEB_LEV_SIMPLE_SEQ, "trying snd_pcm_hw_params_set_buffer_size_near (%d)\n", (int)bufferSize); + if ((err = snd_pcm_hw_params_set_buffer_size_near(omx_alsasink_component_Private->playback_handle, hw_params, &bufferSize)) < 0) { + //if (err = snd_pcm_hw_params_set_buffer_size(omx_alsasink_component_Private->playback_handle, hw_params, bufferSize) < 0) { + DEBUG(DEB_LEV_ERR, "cannot snd_pcm_hw_params_set_buffer_size_near (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + DEBUG(DEB_LEV_SIMPLE_SEQ, "snd_pcm_hw_params_set_buffer_size_near returned (%d)\n", (int)bufferSize); + + DEBUG(DEB_LEV_SIMPLE_SEQ, "trying snd_pcm_hw_params_set_period_size_near (%d)\n", (int)periodSize); + if ((err = snd_pcm_hw_params_set_period_size_near(omx_alsasink_component_Private->playback_handle, hw_params, &periodSize, NULL)) < 0) { + //if (err = snd_pcm_hw_params_set_period_size(omx_alsasink_component_Private->playback_handle, hw_params, periodSize, 0) < 0) { + DEBUG(DEB_LEV_ERR, "cannot snd_pcm_hw_params_set_period_size_near (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + DEBUG(DEB_LEV_SIMPLE_SEQ, "snd_pcm_hw_params_set_period_size_near returned (%d)\n", (int)periodSize); + /* + unsigned int val = 200000; + DEBUG(DEB_LEV_SIMPLE_SEQ, "trying snd_pcm_hw_params_set_buffer_time_near (%d)\n", val); + if (err = snd_pcm_hw_params_set_buffer_time_near(omx_alsasink_component_Private->playback_handle, hw_params, &val, NULL) < 0 ) { + DEBUG(DEB_LEV_ERR, "cannot snd_pcm_hw_params_set_buffer_time (%s)\n", snd_strerror (err)); + return; + } + DEBUG(DEB_LEV_SIMPLE_SEQ, "snd_pcm_hw_params_set_buffer_time_near returned (%d)\n", val); + */ + + /** Configure and prepare the ALSA handle */ + DEBUG(DEB_LEV_SIMPLE_SEQ, "Configuring the PCM interface\n"); + if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot set parameters (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + + if ((err = snd_pcm_prepare (playback_handle)) < 0) { + DEBUG(DEB_LEV_ERR, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); + return OMX_ErrorHardware; + } + } + break; + case OMX_IndexParamAudioMp3: + pAudioMp3 = (OMX_AUDIO_PARAM_MP3TYPE*)ComponentParameterStructure; + /*Check Structure Header and verify component state*/ + omxErr = omx_base_component_ParameterSanityCheck(hComponent, pAudioMp3->nPortIndex, pAudioMp3, sizeof(OMX_AUDIO_PARAM_MP3TYPE)); + if(omxErr != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Parameter Check Error=%x\n", __func__, omxErr); + break; + } + break; + default: /*Call the base component function*/ + return omx_base_component_SetParameter(hComponent, nParamIndex, ComponentParameterStructure); + } + return omxErr; +} + +OMX_ERRORTYPE omx_alsasink_component_GetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_INOUT OMX_PTR ComponentParameterStructure) +{ + OMX_AUDIO_PARAM_PORTFORMATTYPE *pAudioPortFormat; + OMX_OTHER_PARAM_PORTFORMATTYPE *pOtherPortFormat; + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_COMPONENTTYPE *openmaxStandComp = (OMX_COMPONENTTYPE*)hComponent; + omx_alsasink_component_PrivateType* omx_alsasink_component_Private = (omx_alsasink_component_PrivateType*)openmaxStandComp->pComponentPrivate; + omx_base_audio_PortType *pPort = (omx_base_audio_PortType *) omx_alsasink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + omx_base_clock_PortType *pClockPort = (omx_base_clock_PortType *) omx_alsasink_component_Private->ports[1]; + if (ComponentParameterStructure == NULL) { + return OMX_ErrorBadParameter; + } + DEBUG(DEB_LEV_SIMPLE_SEQ, " Getting parameter %i\n", nParamIndex); + /* Check which structure we are being fed and fill its header */ + switch(nParamIndex) { + case OMX_IndexParamAudioInit: + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PORT_PARAM_TYPE))) != OMX_ErrorNone) { + break; + } + memcpy(ComponentParameterStructure, &omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainAudio], sizeof(OMX_PORT_PARAM_TYPE)); + break; + case OMX_IndexParamOtherInit: + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PORT_PARAM_TYPE))) != OMX_ErrorNone) { + break; + } + memcpy(ComponentParameterStructure, &omx_alsasink_component_Private->sPortTypesParam[OMX_PortDomainOther], sizeof(OMX_PORT_PARAM_TYPE)); + break; + case OMX_IndexParamAudioPortFormat: + pAudioPortFormat = (OMX_AUDIO_PARAM_PORTFORMATTYPE*)ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE))) != OMX_ErrorNone) { + break; + } + if (pAudioPortFormat->nPortIndex < 1) { + memcpy(pAudioPortFormat, &pPort->sAudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); + } else { + return OMX_ErrorBadPortIndex; + } + break; + case OMX_IndexParamAudioPcm: + if(((OMX_AUDIO_PARAM_PCMMODETYPE*)ComponentParameterStructure)->nPortIndex != + omx_alsasink_component_Private->sPCMModeParam.nPortIndex) { + return OMX_ErrorBadParameter; + } + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE))) != OMX_ErrorNone) { + break; + } + memcpy(ComponentParameterStructure, &omx_alsasink_component_Private->sPCMModeParam, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)); + break; + case OMX_IndexParamOtherPortFormat: + + pOtherPortFormat = (OMX_OTHER_PARAM_PORTFORMATTYPE*)ComponentParameterStructure; + + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_OTHER_PARAM_PORTFORMATTYPE))) != OMX_ErrorNone) { + break; + } + if (pOtherPortFormat->nPortIndex == 1) { + memcpy(pOtherPortFormat, &pClockPort->sOtherParam, sizeof(OMX_OTHER_PARAM_PORTFORMATTYPE)); + } else { + return OMX_ErrorBadPortIndex; + } + break; + default: /*Call the base component function*/ + return omx_base_component_GetParameter(hComponent, nParamIndex, ComponentParameterStructure); + } + return err; +} diff --git a/alsa/omx_alsasink_component.h b/alsa/omx_alsasink_component.h new file mode 100644 index 0000000..a6f2e7d --- /dev/null +++ b/alsa/omx_alsasink_component.h @@ -0,0 +1,94 @@ +/** + @file src/components/alsa/omx_alsasink_component.h + + OpenMAX ALSA sink component. This component is an audio sink that uses ALSA library. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-08-08 06:56:06 +0200 (Fri, 08 Aug 2008) $ + Revision $Rev: 581 $ + Author $Author: pankaj_sen $ + +*/ + +#ifndef _OMX_ALSASINK_COMPONENT_H_ +#define _OMX_ALSASINK_COMPONENT_H_ + +//#include +//#include +//#include +//#include +#include +#include +#include + +/** Alsasinkport component private structure. + * see the define above + * @param sPCMModeParam Audio PCM specific OpenMAX parameter + * @param AudioPCMConfigured boolean flag to check if the audio has been configured + * @param playback_handle ALSA specif handle for audio player + * @param xScale the scale of the media clock + * @param eState the state of the media clock + * @param hw_params ALSA specif hardware parameters + */ +DERIVEDCLASS(omx_alsasink_component_PrivateType, omx_base_sink_PrivateType) +#define omx_alsasink_component_PrivateType_FIELDS omx_base_sink_PrivateType_FIELDS \ + OMX_AUDIO_PARAM_PCMMODETYPE sPCMModeParam; \ + char AudioPCMConfigured; \ + snd_pcm_t* playback_handle; \ + snd_pcm_status_t* pcm_status; \ + OMX_S32 xScale; \ + OMX_TIME_CLOCKSTATE eState; +ENDCLASS(omx_alsasink_component_PrivateType) + +/* Component private entry points declaration */ +OMX_ERRORTYPE omx_alsasink_component_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName); +OMX_ERRORTYPE omx_alsasink_component_Destructor(OMX_COMPONENTTYPE *openmaxStandComp); + +void omx_alsasink_component_BufferMgmtCallback( + OMX_COMPONENTTYPE *openmaxStandComp, + OMX_BUFFERHEADERTYPE* inputbuffer); + +OMX_ERRORTYPE omx_alsasink_component_port_SendBufferFunction( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer); + +/* to handle the communication at the clock port */ +OMX_BOOL omx_alsasink_component_ClockPortHandleFunction( + omx_alsasink_component_PrivateType* omx_alsasink_component_Private, + OMX_BUFFERHEADERTYPE* inputbuffer); + +OMX_ERRORTYPE omx_alsasink_component_GetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_INOUT OMX_PTR ComponentParameterStructure); + +OMX_ERRORTYPE omx_alsasink_component_SetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_IN OMX_PTR ComponentParameterStructure); + +OMX_ERRORTYPE omx_alsasink_component_GetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_INOUT OMX_PTR pComponentConfigStructure); + +OMX_ERRORTYPE omx_alsasink_component_port_FlushProcessingBuffers(omx_base_PortType *openmaxStandPort); + +#endif diff --git a/alsa/omx_base_audio_port.cpp b/alsa/omx_base_audio_port.cpp new file mode 100644 index 0000000..fb611d7 --- /dev/null +++ b/alsa/omx_base_audio_port.cpp @@ -0,0 +1,111 @@ +/** + @file src/base/omx_base_audio_port.c + + Base Audio Port class for OpenMAX ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-08-07 12:42:40 +0200 (Thu, 07 Aug 2008) $ + Revision $Rev: 580 $ + Author $Author: pankaj_sen $ +*/ + +#include +#include +#include +//#include +//#include + +#include "omx_base_component.h" +#include "omx_base_audio_port.h" + +/** + * @brief The base contructor for the generic OpenMAX ST Audio port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandComp pointer to the Handle of the component + * @param openmaxStandPort the ST port to be initialized + * @param nPortIndex Index of the port to be constructed + * @param isInput specifices if the port is an input or an output + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ + +OMX_ERRORTYPE base_audio_port_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,omx_base_PortType **openmaxStandPort,OMX_U32 nPortIndex, OMX_BOOL isInput) { + + omx_base_audio_PortType *omx_base_audio_Port; + + if (!(*openmaxStandPort)) { + *openmaxStandPort = (omx_base_PortType *) calloc(1,sizeof (omx_base_audio_PortType)); + } + + if (!(*openmaxStandPort)) { + return OMX_ErrorInsufficientResources; + } + + base_port_Constructor(openmaxStandComp,openmaxStandPort,nPortIndex, isInput); + + omx_base_audio_Port = (omx_base_audio_PortType *)*openmaxStandPort; + + setHeader(&omx_base_audio_Port->sAudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); + omx_base_audio_Port->sAudioParam.nPortIndex = nPortIndex; + omx_base_audio_Port->sAudioParam.nIndex = 0; + omx_base_audio_Port->sAudioParam.eEncoding = OMX_AUDIO_CodingUnused; + + omx_base_audio_Port->sPortParam.eDomain = OMX_PortDomainAudio; + omx_base_audio_Port->sPortParam.format.audio.cMIMEType = (OMX_STRING) malloc(DEFAULT_MIME_STRING_LENGTH); + strcpy(omx_base_audio_Port->sPortParam.format.audio.cMIMEType, "raw/audio"); + omx_base_audio_Port->sPortParam.format.audio.pNativeRender = 0; + omx_base_audio_Port->sPortParam.format.audio.bFlagErrorConcealment = OMX_FALSE; + omx_base_audio_Port->sPortParam.format.audio.eEncoding = OMX_AUDIO_CodingUnused; + + omx_base_audio_Port->sPortParam.nBufferSize = (isInput == OMX_TRUE)?DEFAULT_IN_BUFFER_SIZE:DEFAULT_OUT_BUFFER_SIZE ; + + omx_base_audio_Port->PortDestructor = &base_audio_port_Destructor; + + return OMX_ErrorNone; +} + +/** + * @brief The base audio port destructor for the generic OpenMAX ST Audio port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the port. + * It takes care of destructing the instance of the port + * + * @param openmaxStandPort the ST port to be destructed + * + * @return OMX_ErrorNone + */ + +OMX_ERRORTYPE base_audio_port_Destructor(omx_base_PortType *openmaxStandPort){ + + if(openmaxStandPort->sPortParam.format.audio.cMIMEType) { + free(openmaxStandPort->sPortParam.format.audio.cMIMEType); + openmaxStandPort->sPortParam.format.audio.cMIMEType = NULL; + } + + base_port_Destructor(openmaxStandPort); + + return OMX_ErrorNone; +} diff --git a/alsa/omx_base_audio_port.h b/alsa/omx_base_audio_port.h new file mode 100644 index 0000000..d03a83c --- /dev/null +++ b/alsa/omx_base_audio_port.h @@ -0,0 +1,88 @@ +/** + @file src/base/omx_base_audio_port.h + + Base Audio Port class for OpenMAX ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-07-07 14:30:38 +0200 (Mon, 07 Jul 2008) $ + Revision $Rev: 562 $ + Author $Author: gsent $ + +*/ + +#include "omx_classmagic.h" +#include "omx_base_port.h" + +#ifndef __OMX_BASE_AUDIO_PORT_H__ +#define __OMX_BASE_AUDIO_PORT_H__ + +/** + * @brief the base audio domain structure that describes each port. + * + * The data structure is derived from base port class and contain audio + * domain specific parameters. + * Other elements can be added in the derived components structures. + */ + +DERIVEDCLASS(omx_base_audio_PortType, omx_base_PortType) +#define omx_base_audio_PortType_FIELDS omx_base_PortType_FIELDS \ + /** @param sAudioParam Domain specific (audio) OpenMAX port parameter */ \ + OMX_AUDIO_PARAM_PORTFORMATTYPE sAudioParam; +ENDCLASS(omx_base_audio_PortType) + +/** + * @brief the base contructor for the generic OpenMAX ST Audio port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandComp pointer to the Handle of the component + * @param openmaxStandPort the ST port to be initialized + * @param nPortIndex Index of the port to be constructed + * @param isInput specifices if the port is an input or an output + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ + +OMX_ERRORTYPE base_audio_port_Constructor( + OMX_COMPONENTTYPE *openmaxStandComp, + omx_base_PortType **openmaxStandPort, + OMX_U32 nPortIndex, + OMX_BOOL isInput); + +/** + * @brief the base audio port destructor for the generic OpenMAX ST Audio port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the port. + * It takes care of destructing the instance of the port + * + * @param openmaxStandPort the ST port to be destructed + * + * @return OMX_ErrorNone + */ + + +OMX_ERRORTYPE base_audio_port_Destructor( + omx_base_PortType *openmaxStandPort); + +#endif diff --git a/alsa/omx_base_clock_port.cpp b/alsa/omx_base_clock_port.cpp new file mode 100644 index 0000000..cf27b71 --- /dev/null +++ b/alsa/omx_base_clock_port.cpp @@ -0,0 +1,209 @@ +/** + @file src/base/omx_base_clock_port.c + + Base Clock Port class for OpenMAX clock ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-07-04 11:48:31 +0200 (Fri, 04 Jul 2008) $ + Revision $Rev: 560 $ + Author $Author: gsent $ +*/ + +#undef OMX_SKIP64BIT +#include +#include +#include +//#include +//#include +#include "omx_base_component.h" +#include "omx_base_clock_port.h" + +/** + * @brief the base contructor for the generic openmax ST Clock port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandComp pointer to the Handle of the component + * @param openmaxStandPort the ST port to be initialized + * @param nPortIndex Index of the port to be constructed + * @param isInput specifices if the port is an input or an output + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ + +OMX_ERRORTYPE base_clock_port_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,omx_base_PortType **openmaxStandPort,OMX_U32 nPortIndex, OMX_BOOL isInput) { + + omx_base_clock_PortType *omx_base_clock_Port; + + if (!(*openmaxStandPort)) { + *openmaxStandPort = (omx_base_PortType*)calloc(1,sizeof (omx_base_clock_PortType)); + } + + if (!(*openmaxStandPort)) { + return OMX_ErrorInsufficientResources; + } + + base_port_Constructor(openmaxStandComp,openmaxStandPort,nPortIndex, isInput); + + omx_base_clock_Port = (omx_base_clock_PortType *)*openmaxStandPort; + + setHeader(&omx_base_clock_Port->sOtherParam, sizeof(OMX_OTHER_PARAM_PORTFORMATTYPE)); + omx_base_clock_Port->sOtherParam.nPortIndex = nPortIndex; + omx_base_clock_Port->sOtherParam.nIndex = 0; + omx_base_clock_Port->sOtherParam.eFormat = OMX_OTHER_FormatTime; + + omx_base_clock_Port->sPortParam.eDomain = OMX_PortDomainOther; + omx_base_clock_Port->sPortParam.format.other.eFormat = OMX_OTHER_FormatTime; + omx_base_clock_Port->sPortParam.nBufferSize = sizeof(OMX_TIME_MEDIATIMETYPE) ; + omx_base_clock_Port->sPortParam.nBufferCountActual = 1; + omx_base_clock_Port->sPortParam.nBufferCountMin = 1; + omx_base_clock_Port->sPortParam.format.other.eFormat = OMX_OTHER_FormatTime; + + setHeader(&omx_base_clock_Port->sTimeStamp, sizeof(OMX_TIME_CONFIG_TIMESTAMPTYPE)); + omx_base_clock_Port->sTimeStamp.nPortIndex = nPortIndex; + omx_base_clock_Port->sTimeStamp.nTimestamp = 0x00; + + + setHeader(&omx_base_clock_Port->sMediaTime, sizeof(OMX_TIME_MEDIATIMETYPE)); + omx_base_clock_Port->sMediaTime.nClientPrivate = 0; + omx_base_clock_Port->sMediaTime.nOffset = 0x0; + omx_base_clock_Port->sMediaTime.xScale = 1; + + setHeader(&omx_base_clock_Port->sMediaTimeRequest, sizeof(OMX_TIME_MEDIATIMETYPE)); + omx_base_clock_Port->sMediaTimeRequest.nPortIndex = nPortIndex; + omx_base_clock_Port->sMediaTimeRequest.pClientPrivate = NULL; + omx_base_clock_Port->sMediaTimeRequest.nOffset = 0x0; + + omx_base_clock_Port->Port_SendBufferFunction = &base_clock_port_SendBufferFunction; + omx_base_clock_Port->PortDestructor = &base_clock_port_Destructor; + + return OMX_ErrorNone; +} + +/** + * @brief the base clock port destructor for the generic openmax ST clock port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the port. + * It takes care of destructing the instance of the port + * + * @param openmaxStandPort the ST port to be destructed + * + * @return OMX_ErrorNone + */ + +OMX_ERRORTYPE base_clock_port_Destructor(omx_base_PortType *openmaxStandPort){ + + base_port_Destructor(openmaxStandPort); + + return OMX_ErrorNone; +} + +/** @brief the entry point for sending buffers to the port + * + * This function can be called by the EmptyThisBuffer or FillThisBuffer. It depends on + * the nature of the port, that can be an input or output port. + */ +OMX_ERRORTYPE base_clock_port_SendBufferFunction( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer) { + + OMX_ERRORTYPE err; + OMX_U32 portIndex; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; +#if NO_GST_OMX_PATCH + unsigned int i; +#endif + portIndex = (openmaxStandPort->sPortParam.eDir == OMX_DirInput)?pBuffer->nInputPortIndex:pBuffer->nOutputPortIndex; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s portIndex %lu\n", __func__, (unsigned long)portIndex); + + if (portIndex != openmaxStandPort->sPortParam.nPortIndex) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port for this operation portIndex=%d port->portIndex=%d\n", __func__, (int)portIndex, (int)openmaxStandPort->sPortParam.nPortIndex); + return OMX_ErrorBadPortIndex; + } + + if(omx_base_component_Private->state == OMX_StateInvalid) { + DEBUG(DEB_LEV_ERR, "In %s: we are in OMX_StateInvalid\n", __func__); + return OMX_ErrorInvalidState; + } + + if(omx_base_component_Private->state != OMX_StateExecuting && + omx_base_component_Private->state != OMX_StatePause && + omx_base_component_Private->state != OMX_StateIdle) { + DEBUG(DEB_LEV_ERR, "In %s: we are not in executing/paused/idle state, but in %d\n", __func__, omx_base_component_Private->state); + return OMX_ErrorIncorrectStateOperation; + } + if (!PORT_IS_ENABLED(openmaxStandPort) || (PORT_IS_BEING_DISABLED(openmaxStandPort) && !PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) || + (omx_base_component_Private->transientState == OMX_TransStateExecutingToIdle && + (PORT_IS_TUNNELED(openmaxStandPort) && !PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)))) { + DEBUG(DEB_LEV_ERR, "In %s: Port %d is disabled comp = %s \n", __func__, (int)portIndex,omx_base_component_Private->name); + return OMX_ErrorIncorrectStateOperation; + } + + /* Temporarily disable this check for gst-openmax */ +#if NO_GST_OMX_PATCH + { + OMX_BOOL foundBuffer = OMX_FALSE; + if(pBuffer!=NULL && pBuffer->pBuffer!=NULL) { + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (pBuffer->pBuffer == openmaxStandPort->pInternalBufferStorage[i]->pBuffer) { + foundBuffer = OMX_TRUE; + break; + } + } + } + if (!foundBuffer) { + return OMX_ErrorBadParameter; + } + } +#endif + + if ((err = checkHeader(pBuffer, sizeof(OMX_BUFFERHEADERTYPE))) != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s: received wrong buffer header on input port\n", __func__); + return err; + } + /*If port is not tunneled then simply return the buffer except paused state*/ + if (!PORT_IS_TUNNELED(openmaxStandPort) && (omx_base_component_Private->state != OMX_StatePause)) { + openmaxStandPort->ReturnBufferFunction(openmaxStandPort,pBuffer); + return OMX_ErrorNone; + } + + /* And notify the buffer management thread we have a fresh new buffer to manage */ + if(!PORT_IS_BEING_FLUSHED(openmaxStandPort) && !(PORT_IS_BEING_DISABLED(openmaxStandPort) && PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort))){ + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + DEBUG(DEB_LEV_PARAMS, "In %s Signalling bMgmtSem Port Index=%d\n",__func__, (int)portIndex); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + }else if(PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)){ + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Comp %s received io:%d buffer\n", + __func__,omx_base_component_Private->name,(int)openmaxStandPort->sPortParam.nPortIndex); + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + } + else { // If port being flushed and not tunneled then return error + DEBUG(DEB_LEV_FULL_SEQ, "In %s \n", __func__); + return OMX_ErrorIncorrectStateOperation; + } + return OMX_ErrorNone; +} diff --git a/alsa/omx_base_clock_port.h b/alsa/omx_base_clock_port.h new file mode 100644 index 0000000..97f543e --- /dev/null +++ b/alsa/omx_base_clock_port.h @@ -0,0 +1,95 @@ +/** + @file src/base/omx_base_clock_port.h + + Base Clock Port class for OpenMAX clock ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-07-04 11:48:31 +0200 (Fri, 04 Jul 2008) $ + Revision $Rev: 560 $ + Author $Author: gsent $ + +*/ + +#include "omx_classmagic.h" +#include "omx_base_port.h" + +#ifndef __OMX_BASE_CLOCK_PORT_H__ +#define __OMX_BASE_CLOCK_PORT_H__ + +/** + * @brief the base clock domain structure that describes each port. + * + * The data structure is derived from base port class and contain clock + * domain specific parameters. + * Other elements can be added in the derived components structures. + * + * @param sOtherParam Domain specific (other) OpenMAX port parameter + */ + +DERIVEDCLASS(omx_base_clock_PortType, omx_base_PortType) +#define omx_base_clock_PortType_FIELDS omx_base_PortType_FIELDS \ + OMX_TIME_CONFIG_TIMESTAMPTYPE sTimeStamp; /**< General OpenMAX configuration time stamp parameter */ \ + OMX_TIME_MEDIATIMETYPE sMediaTime; \ + OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE sMediaTimeRequest; \ + OMX_OTHER_PARAM_PORTFORMATTYPE sOtherParam; /**< Domain specific (other) OpenMAX port parameter */ +ENDCLASS(omx_base_clock_PortType) + +/** + * @brief the base contructor for the generic openmax ST clock port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandComp pointer to the Handle of the component + * @param openmaxStandPort the ST port to be initialized + * @param nPortIndex Index of the port to be constructed + * @param isInput specifices if the port is an input or an output + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ + +OMX_ERRORTYPE base_clock_port_Constructor( + OMX_COMPONENTTYPE *openmaxStandComp, + omx_base_PortType **openmaxStandPort, + OMX_U32 nPortIndex, + OMX_BOOL isInput); + +/** + * @brief the base clock port destructor for the generic openmax ST clock port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the port. + * It takes care of destructing the instance of the port + * + * @param openmaxStandPort the ST port to be destructed + * + * @return OMX_ErrorNone + */ + +OMX_ERRORTYPE base_clock_port_Destructor( + omx_base_PortType *openmaxStandPort); + +OMX_ERRORTYPE base_clock_port_SendBufferFunction( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer); + +#endif diff --git a/alsa/omx_base_component.cpp b/alsa/omx_base_component.cpp new file mode 100644 index 0000000..8396979 --- /dev/null +++ b/alsa/omx_base_component.cpp @@ -0,0 +1,1755 @@ +/** + @file src/base/omx_base_component.c + + OpenMAX base_component component. This component does not perform any multimedia + processing. It is used as a base_component for new components development. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-09-16 15:59:45 +0200 (Tue, 16 Sep 2008) $ + Revision $Rev: 621 $ + Author $Author: gsent $ + +*/ + +#include +#include +#include +#include +#include + +//#include +//#include + +#include "omx_semaphore.h" +#include "omx_base_component.h" + +/** + * @brief The base contructor for the OpenMAX st components + * + * This function is executed by the ST static component loader. + * It takes care of constructing the instance of the component. + * For the base_component component, the following is done: + * + * 1) Fills the basic OpenMAX structure. The fields can be overwritten + * by derived components. + * 2) Allocates (if needed) the omx_base_component_PrivateType private structure + * + * @param openmaxStandComp the ST component to be initialized + * @param cComponentName the OpenMAX string that describes the component + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ +OMX_ERRORTYPE omx_base_component_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName) { + omx_base_component_PrivateType* omx_base_component_Private; + OMX_U32 i; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (openmaxStandComp->pComponentPrivate) { + omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + } else { + omx_base_component_Private = (omx_base_component_PrivateType*)calloc(1,sizeof(omx_base_component_PrivateType)); + if (!omx_base_component_Private) { + return OMX_ErrorInsufficientResources; + } + } + + if(!omx_base_component_Private->messageQueue) { + omx_base_component_Private->messageQueue = (omx_queue_t*)calloc(1,sizeof(omx_queue_t)); + omx_queue_init(omx_base_component_Private->messageQueue); + } + + if(!omx_base_component_Private->messageSem) { + omx_base_component_Private->messageSem = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + omx_tsem_init(omx_base_component_Private->messageSem, 0); + } + if(!omx_base_component_Private->bMgmtSem) { + omx_base_component_Private->bMgmtSem = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + omx_tsem_init(omx_base_component_Private->bMgmtSem, 0); + } + + if(!omx_base_component_Private->bStateSem) { + omx_base_component_Private->bStateSem = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + omx_tsem_init(omx_base_component_Private->bStateSem, 0); + } + + openmaxStandComp->nSize = sizeof(OMX_COMPONENTTYPE); + openmaxStandComp->pApplicationPrivate = NULL; + openmaxStandComp->GetComponentVersion = omx_base_component_GetComponentVersion; + openmaxStandComp->SendCommand = omx_base_component_SendCommand; + openmaxStandComp->GetParameter = omx_base_component_GetParameter; + openmaxStandComp->SetParameter = omx_base_component_SetParameter; + openmaxStandComp->GetConfig = omx_base_component_GetConfig; + openmaxStandComp->SetConfig = omx_base_component_SetConfig; + openmaxStandComp->GetExtensionIndex = omx_base_component_GetExtensionIndex; + openmaxStandComp->GetState = omx_base_component_GetState; + openmaxStandComp->SetCallbacks = omx_base_component_SetCallbacks; + openmaxStandComp->ComponentDeInit = omx_base_component_ComponentDeInit; + openmaxStandComp->ComponentRoleEnum = omx_base_component_ComponentRoleEnum; + openmaxStandComp->ComponentTunnelRequest =omx_base_component_ComponentTunnelRequest; + + /*Will make Specific port Allocate buffer call*/ + openmaxStandComp->AllocateBuffer = omx_base_component_AllocateBuffer; + openmaxStandComp->UseBuffer = omx_base_component_UseBuffer; + openmaxStandComp->UseEGLImage = omx_base_component_UseEGLImage; + openmaxStandComp->FreeBuffer = omx_base_component_FreeBuffer; + openmaxStandComp->EmptyThisBuffer = omx_base_component_EmptyThisBuffer; + openmaxStandComp->FillThisBuffer = omx_base_component_FillThisBuffer; + + openmaxStandComp->nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; + openmaxStandComp->nVersion.s.nVersionMinor = OMX_VERSION_MINOR; + openmaxStandComp->nVersion.s.nRevision = OMX_VERSION_REVISION; + openmaxStandComp->nVersion.s.nStep = OMX_VERSION_STEP; + + omx_base_component_Private->name = (char*)calloc(1,OMX_MAX_STRINGNAME_SIZE); + if (!omx_base_component_Private->name) { + return OMX_ErrorInsufficientResources; + } + strcpy(omx_base_component_Private->name,cComponentName); + omx_base_component_Private->state = OMX_StateLoaded; + omx_base_component_Private->transientState = OMX_TransStateMax; + omx_base_component_Private->callbacks = NULL; + omx_base_component_Private->callbackData = NULL; + omx_base_component_Private->nGroupPriority = 0; + omx_base_component_Private->nGroupID = 0; + omx_base_component_Private->pMark.hMarkTargetComponent = NULL; + omx_base_component_Private->pMark.pMarkData = NULL; + omx_base_component_Private->openmaxStandComp=openmaxStandComp; + omx_base_component_Private->DoStateSet = &omx_base_component_DoStateSet; + omx_base_component_Private->messageHandler = omx_base_component_MessageHandler; + omx_base_component_Private->destructor = omx_base_component_Destructor; + omx_base_component_Private->bufferMgmtThreadID = -1; + + pthread_mutex_init(&omx_base_component_Private->flush_mutex, NULL); + + if(!omx_base_component_Private->flush_all_condition) { + omx_base_component_Private->flush_all_condition = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + omx_tsem_init(omx_base_component_Private->flush_all_condition, 0); + } + + if(!omx_base_component_Private->flush_condition) { + omx_base_component_Private->flush_condition = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + omx_tsem_init(omx_base_component_Private->flush_condition, 0); + } + + for(i=0;isPortTypesParam[i], 0, sizeof(OMX_PORT_PARAM_TYPE)); + setHeader(&omx_base_component_Private->sPortTypesParam[i], sizeof(OMX_PORT_PARAM_TYPE)); + } + + omx_base_component_Private->messageHandlerThreadID = pthread_create(&omx_base_component_Private->messageHandlerThread, + NULL, + compMessageHandlerFunction, + openmaxStandComp); + + DEBUG(DEB_LEV_FUNCTION_NAME,"Out of %s\n",__func__); + return OMX_ErrorNone; +} + +/** @brief The base destructor for ST OpenMAX components + * + * This function is called by the standard function ComponentDeInit() + * that is called by the IL core during the execution of the FreeHandle() + * + * @param openmaxStandComp the ST OpenMAX component to be disposed + */ +OMX_ERRORTYPE omx_base_component_Destructor(OMX_COMPONENTTYPE *openmaxStandComp) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + int err; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + omx_base_component_Private->state = OMX_StateInvalid; + + /*Send Dummy signal to Component Message handler to exit*/ + omx_tsem_up(omx_base_component_Private->messageSem); + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s messageSem signaled. messageSem->semval=%d\n", __func__, omx_base_component_Private->messageSem->semval); + + err = pthread_join(omx_base_component_Private->messageHandlerThread,NULL); + if(err!=0) { + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s pthread_join returned err=%d\n", __func__, err); + } + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s past pthread_join\n", __func__); + + omx_base_component_Private->callbacks=NULL; + + /*Deinitialize and free message queue*/ + if(omx_base_component_Private->messageQueue) { + omx_queue_deinit(omx_base_component_Private->messageQueue); + free(omx_base_component_Private->messageQueue); + omx_base_component_Private->messageQueue=NULL; + } + + /*Deinitialize and free buffer management semaphore*/ + if(omx_base_component_Private->bMgmtSem){ + omx_tsem_deinit(omx_base_component_Private->bMgmtSem); + free(omx_base_component_Private->bMgmtSem); + omx_base_component_Private->bMgmtSem=NULL; + } + + /*Deinitialize and free message semaphore*/ + if(omx_base_component_Private->messageSem) { + omx_tsem_deinit(omx_base_component_Private->messageSem); + free(omx_base_component_Private->messageSem); + omx_base_component_Private->messageSem=NULL; + } + + if(omx_base_component_Private->bStateSem){ + omx_tsem_deinit(omx_base_component_Private->bStateSem); + free(omx_base_component_Private->bStateSem); + omx_base_component_Private->bStateSem=NULL; + } + + if(omx_base_component_Private->name){ + free(omx_base_component_Private->name); + omx_base_component_Private->name=NULL; + } + + pthread_mutex_destroy(&omx_base_component_Private->flush_mutex); + + if(omx_base_component_Private->flush_all_condition){ + omx_tsem_deinit(omx_base_component_Private->flush_all_condition); + free(omx_base_component_Private->flush_all_condition); + omx_base_component_Private->flush_all_condition=NULL; + } + + if(omx_base_component_Private->flush_condition){ + omx_tsem_deinit(omx_base_component_Private->flush_condition); + free(omx_base_component_Private->flush_condition); + omx_base_component_Private->flush_condition=NULL; + } + + DEBUG(DEB_LEV_FUNCTION_NAME,"Out of %s\n",__func__); + return OMX_ErrorNone; +} + +/** @brief This standard functionality is called when the component is + * destroyed in the FreeHandle standard call. + * + * In this way the implementation of the FreeHandle is standard, + * and it does not need a support by a specific component loader. + * The implementaiton of the ComponentDeInit contains the + * implementation specific part of the destroying phase. + */ +OMX_ERRORTYPE omx_base_component_ComponentDeInit( + OMX_IN OMX_HANDLETYPE hComponent) { + OMX_COMPONENTTYPE *openmaxStandComp = (OMX_COMPONENTTYPE *)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s pComponentPrivate =%x \n", __func__,(int)openmaxStandComp->pComponentPrivate); + omx_base_component_Private->destructor(openmaxStandComp); + + free(openmaxStandComp->pComponentPrivate); + openmaxStandComp->pComponentPrivate=NULL; + return OMX_ErrorNone; +} + +/** Changes the state of a component taking proper actions depending on + * the transiotion requested. This base function cover only the state + * changes that do not involve any port + * + * @param openmaxStandComp the OpenMAX component which state is to be changed + * @param destinationState the requested target state + * + * @return OMX_ErrorNotImplemented if the state change is noty handled in this base class, but needs + * a specific handling + */ +OMX_ERRORTYPE omx_base_component_DoStateSet(OMX_COMPONENTTYPE *openmaxStandComp, OMX_U32 destinationState) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + omx_base_PortType *pPort; + OMX_U32 i,j,k; + OMX_ERRORTYPE err=OMX_ErrorNone; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + DEBUG(DEB_LEV_PARAMS, "Changing state from %i to %i\n", omx_base_component_Private->state, (int)destinationState); + + if(destinationState == OMX_StateLoaded){ + switch(omx_base_component_Private->state){ + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + case OMX_StateWaitForResources: + /* return back from wait for resources */ + omx_base_component_Private->state = OMX_StateLoaded; + break; + case OMX_StateLoaded: + err = OMX_ErrorSameState; + break; + case OMX_StateIdle: + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + + pPort = omx_base_component_Private->ports[i]; + if (PORT_IS_TUNNELED(pPort) && PORT_IS_BUFFER_SUPPLIER(pPort)) { + while(pPort->pBufferQueue->nelem > 0) { + DEBUG(DEB_LEV_PARAMS, "In %s Buffer %d remained in the port %d queue of comp%s\n", + __func__,(int)pPort->pBufferQueue->nelem,(int)i,omx_base_component_Private->name); + omx_dequeue(pPort->pBufferQueue); + } + /* Freeing here the buffers allocated for the tunneling:*/ + err = pPort->Port_FreeTunnelBuffer(pPort,i); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Freeing Tunnel Buffer Error=%x\n",__func__,err); + return err; + } + } else { + DEBUG(DEB_LEV_FULL_SEQ, "In %s nPortIndex=%d pAllocSem Semval=%x\n", __func__,(int)i,(int)pPort->pAllocSem->semval); + + /*If ports are enabled then wait till all buffers are freed*/ + if(PORT_IS_ENABLED(pPort)) { + omx_tsem_down(pPort->pAllocSem); + } + } + pPort->sPortParam.bPopulated = OMX_FALSE; + + if(pPort->bTunnelTearDown == OMX_TRUE){ + DEBUG(DEB_LEV_PARAMS, "In %s TearDown tunnel\n", __func__); + pPort->hTunneledComponent = 0; + pPort->nTunneledPort = 0; + pPort->nTunnelFlags = 0; + pPort->eBufferSupplier=OMX_BufferSupplyUnspecified; + pPort->bTunnelTearDown = OMX_FALSE; + } + + if(pPort->pInternalBufferStorage != NULL) { + free(pPort->pInternalBufferStorage); + pPort->pInternalBufferStorage=NULL; + } + + if(pPort->bBufferStateAllocated != NULL) { + free(pPort->bBufferStateAllocated); + pPort->bBufferStateAllocated=NULL; + } + } + } + omx_base_component_Private->state = OMX_StateLoaded; + + if(omx_base_component_Private->bufferMgmtThreadID == 0 ){ + /*Signal Buffer Management thread to exit*/ + omx_tsem_up(omx_base_component_Private->bMgmtSem); + pthread_join(omx_base_component_Private->bufferMgmtThread,NULL); + omx_base_component_Private->bufferMgmtThreadID = -1; + if(err != 0) { + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s pthread_join returned err=%d\n",__func__,err); + } + } + + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: state transition not allowed\n", __func__); + err = OMX_ErrorIncorrectStateTransition; + break; + } + return err; + } + + if(destinationState == OMX_StateWaitForResources){ + switch(omx_base_component_Private->state){ + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + case OMX_StateLoaded: + omx_base_component_Private->state = OMX_StateWaitForResources; + break; + case OMX_StateWaitForResources: + err = OMX_ErrorSameState; + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: state transition not allowed\n", __func__); + err = OMX_ErrorIncorrectStateTransition; + break; + } + return err; + } + + if(destinationState == OMX_StateIdle){ + switch(omx_base_component_Private->state){ + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + case OMX_StateWaitForResources: + omx_base_component_Private->state = OMX_StateIdle; + break; + case OMX_StateLoaded: + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort = omx_base_component_Private->ports[i]; + if (PORT_IS_TUNNELED(pPort) && PORT_IS_BUFFER_SUPPLIER(pPort)) { + if(PORT_IS_ENABLED(pPort)) { + /** Allocate here the buffers needed for the tunneling */ + err= pPort->Port_AllocateTunnelBuffer(pPort, i, omx_base_component_Private->ports[i]->sPortParam.nBufferSize); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Allocating Tunnel Buffer Port=%d, Error=%x\n",__func__,i,err); + return err; + } + } + } else { + if(PORT_IS_ENABLED(pPort)) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s: wait for buffers. port enabled %i, port populated %i\n", + __func__, pPort->sPortParam.bEnabled,pPort->sPortParam.bPopulated); + omx_tsem_down(pPort->pAllocSem); + pPort->sPortParam.bPopulated = OMX_TRUE; + } + else + DEBUG(DEB_LEV_ERR, "In %s: Port %i Disabled So no wait\n",__func__,(int)i); + } + DEBUG(DEB_LEV_SIMPLE_SEQ, "---> Tunnel status : port %d flags 0x%x\n",(int)i, (int)pPort->nTunnelFlags); + } + } + omx_base_component_Private->state = OMX_StateIdle; + /** starting buffer management thread */ + omx_base_component_Private->bufferMgmtThreadID = pthread_create(&omx_base_component_Private->bufferMgmtThread, + NULL, + omx_base_component_Private->BufferMgmtFunction, + openmaxStandComp); + if(omx_base_component_Private->bufferMgmtThreadID < 0){ + DEBUG(DEB_LEV_ERR, "Starting buffer management thread failed\n"); + return OMX_ErrorUndefined; + } + break; + case OMX_StateIdle: + err = OMX_ErrorSameState; + break; + case OMX_StateExecuting: + /*Flush Ports*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + DEBUG(DEB_LEV_FULL_SEQ, "Flushing Port %i\n",(int)i); + pPort = omx_base_component_Private->ports[i]; + if(PORT_IS_ENABLED(pPort)) { + pPort->FlushProcessingBuffers(pPort); + } + } + } + omx_base_component_Private->state = OMX_StateIdle; + break; + case OMX_StatePause: + omx_base_component_Private->state = OMX_StateIdle; + /*Signal buffer management thread if waiting at paused state*/ + omx_tsem_signal(omx_base_component_Private->bStateSem); + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: state transition not allowed\n", __func__); + err = OMX_ErrorIncorrectStateTransition; + break; + } + return err; + } + + if(destinationState == OMX_StatePause) { + switch(omx_base_component_Private->state) { + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + case OMX_StatePause: + err = OMX_ErrorSameState; + break; + case OMX_StateExecuting: + case OMX_StateIdle: + omx_base_component_Private->state = OMX_StatePause; + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: state transition not allowed\n", __func__); + err = OMX_ErrorIncorrectStateTransition; + break; + } + return err; + } + + if(destinationState == OMX_StateExecuting) { + switch(omx_base_component_Private->state) { + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + case OMX_StateIdle: + omx_base_component_Private->state=OMX_StateExecuting; + /*Send Tunneled Buffer to the Neighbouring Components*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort = omx_base_component_Private->ports[i]; + if (PORT_IS_TUNNELED(pPort) && PORT_IS_BUFFER_SUPPLIER(pPort) && PORT_IS_ENABLED(pPort)) { + for(k=0;knNumTunnelBuffer;k++) { + omx_tsem_up(pPort->pBufferSem); + /*signal buffer management thread availability of buffers*/ + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + } + omx_base_component_Private->transientState = OMX_TransStateMax; + err = OMX_ErrorNone; + break; + case OMX_StatePause: + omx_base_component_Private->state=OMX_StateExecuting; + + /* Tunneled Supplier Ports were enabled in paused state. So signal buffer managment thread*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + + pPort=omx_base_component_Private->ports[i]; + DEBUG(DEB_LEV_PARAMS, "In %s: state transition Paused 2 Executing, nelem=%d,semval=%d,Buf Count Actual=%d\n", __func__, + pPort->pBufferQueue->nelem,pPort->pBufferSem->semval,(int)pPort->sPortParam.nBufferCountActual); + + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(pPort) && + (pPort->pBufferQueue->nelem == (pPort->pBufferSem->semval + pPort->sPortParam.nBufferCountActual))) { + for(k=0; k < pPort->sPortParam.nBufferCountActual;k++) { + omx_tsem_up(pPort->pBufferSem); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + } + /*Signal buffer management thread if waiting at paused state*/ + omx_tsem_signal(omx_base_component_Private->bStateSem); + break; + case OMX_StateExecuting: + err = OMX_ErrorSameState; + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: state transition not allowed\n", __func__); + err = OMX_ErrorIncorrectStateTransition; + break; + } + return err; + } + + if(destinationState == OMX_StateInvalid) { + switch(omx_base_component_Private->state) { + case OMX_StateInvalid: + err = OMX_ErrorInvalidState; + break; + default: + omx_base_component_Private->state = OMX_StateInvalid; + + if(omx_base_component_Private->bufferMgmtThreadID == 0 ){ + /*Signal Buffer Management Thread to Exit*/ + omx_tsem_up(omx_base_component_Private->bMgmtSem); + pthread_join(omx_base_component_Private->bufferMgmtThread,NULL); + omx_base_component_Private->bufferMgmtThreadID = -1; + if(err!=0) { + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s pthread_join returned err=%d\n",__func__,err); + } + } + err = OMX_ErrorInvalidState; + break; + } + return err; + } + return OMX_ErrorNone; +} + +/** @brief Checks the header of a structure for consistency + * with size and spec version + * + * @param header Pointer to the structure to be checked + * @param size Size of the structure. it is in general obtained + * with a sizeof call applied to the structure + * + * @return OMX error code. If the header has failed the check, + * OMX_ErrorVersionMismatch is returned. + * If the header fails the size check OMX_ErrorBadParameter is returned + */ +OMX_ERRORTYPE checkHeader(OMX_PTR header, OMX_U32 size) { + OMX_VERSIONTYPE* ver; + if (header == NULL) { + DEBUG(DEB_LEV_ERR, "In %s the header is null\n",__func__); + return OMX_ErrorBadParameter; + } + ver = (OMX_VERSIONTYPE*)((char*)header + sizeof(OMX_U32)); + if(*((OMX_U32*)header) != size) { + DEBUG(DEB_LEV_ERR, "In %s the header has a wrong size %i should be %i\n",__func__,(int)*((OMX_U32*)header),(int)size); + return OMX_ErrorBadParameter; + } + if(ver->s.nVersionMajor != OMX_VERSION_MAJOR || + ver->s.nVersionMinor != OMX_VERSION_MINOR) { + DEBUG(DEB_LEV_ERR, "The version does not match\n"); + return OMX_ErrorVersionMismatch; + } + return OMX_ErrorNone; +} + +/** @brief Simply fills the first two fields in any OMX structure + * with the size and the version + * + * @param header pointer to the structure to be filled + * @param size size of the structure. It can be obtained with + * a call to sizeof of the structure type + */ +void setHeader(OMX_PTR header, OMX_U32 size) { + OMX_VERSIONTYPE* ver = (OMX_VERSIONTYPE*)((char*)header + sizeof(OMX_U32)); + *((OMX_U32*)header) = size; + + ver->s.nVersionMajor = OMX_VERSION_MAJOR; + ver->s.nVersionMinor = OMX_VERSION_MINOR; + ver->s.nRevision = OMX_VERSION_REVISION; + ver->s.nStep = OMX_VERSION_STEP; +} + +/** + * This function verify Component State and Structure header + */ +OMX_ERRORTYPE omx_base_component_ParameterSanityCheck(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pStructure, + OMX_IN size_t size) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)(((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate); + omx_base_PortType *pPort; + int nNumPorts; + + nNumPorts = omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts; + + if (nPortIndex >= nNumPorts) { + DEBUG(DEB_LEV_ERR, "Bad Port index %i when the component has %i ports\n", (int)nPortIndex, (int)nNumPorts); + return OMX_ErrorBadPortIndex; + } + + pPort = omx_base_component_Private->ports[nPortIndex]; + + if (omx_base_component_Private->state != OMX_StateLoaded && omx_base_component_Private->state != OMX_StateWaitForResources) { + if(PORT_IS_ENABLED(pPort)) { + DEBUG(DEB_LEV_ERR, "In %s Incorrect State=%x lineno=%d\n",__func__,omx_base_component_Private->state,__LINE__); + return OMX_ErrorIncorrectStateOperation; + } + } + + return checkHeader(pStructure , size); +} + +/** @brief Standard OpenMAX function + * + * it returns the version of the component. See OMX_Core.h + */ +OMX_ERRORTYPE omx_base_component_GetComponentVersion(OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_STRING pComponentName, + OMX_OUT OMX_VERSIONTYPE* pComponentVersion, + OMX_OUT OMX_VERSIONTYPE* pSpecVersion, + OMX_OUT OMX_UUIDTYPE* pComponentUUID) { + + OMX_COMPONENTTYPE* omx_component = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omx_component->pComponentPrivate; + + OMX_U32 uuid[3]; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + /* Fill component name */ + strcpy(pComponentName, omx_base_component_Private->name); + + /* Fill component version */ + pComponentVersion->s.nVersionMajor = OMX_VERSION_MAJOR; + pComponentVersion->s.nVersionMinor = OMX_VERSION_MINOR; + pComponentVersion->s.nRevision = OMX_VERSION_REVISION; + pComponentVersion->s.nStep = OMX_VERSION_STEP; + + /* Fill spec version (copy from component field) */ + memcpy(pSpecVersion, &omx_component->nVersion, sizeof(OMX_VERSIONTYPE)); + + /* Fill UUID with handle address, PID and UID. + * This should guarantee uiniqness */ + uuid[0] = (OMX_U32)omx_component; + uuid[1] = getpid(); + uuid[2] = getuid(); + memcpy(*pComponentUUID, uuid, 3*sizeof(uuid)); + + DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__); + return OMX_ErrorNone; +} + +/** @brief Enumerates all the roles of the component. + * + * This function is intended to be used only by a core. The ST static core + * in any case does not use this function, because it can not be used before the + * creation of the component, but uses a static list. + * It is implemented only for API completion,and it will be not overriden + * by a derived component + */ +OMX_ERRORTYPE omx_base_component_ComponentRoleEnum( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_U8 *cRole, + OMX_IN OMX_U32 nIndex) { + strcat((char*)cRole, "\0"); + return OMX_ErrorNoMore; +} + +/** @brief standard OpenMAX function + * + * it sets the callback functions given by the IL client. + * See OMX_Component.h + */ +OMX_ERRORTYPE omx_base_component_SetCallbacks( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_CALLBACKTYPE* pCallbacks, + OMX_IN OMX_PTR pAppData) { + + OMX_COMPONENTTYPE *omxcomponent = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxcomponent->pComponentPrivate; + omx_base_PortType *pPort; + OMX_U32 i,j; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + omx_base_component_Private->callbacks = pCallbacks; + omx_base_component_Private->callbackData = pAppData; + + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort = omx_base_component_Private->ports[i]; + if (pPort->sPortParam.eDir == OMX_DirInput) { + pPort->BufferProcessedCallback = omx_base_component_Private->callbacks->EmptyBufferDone; + } else { + pPort->BufferProcessedCallback = omx_base_component_Private->callbacks->FillBufferDone; + } + } + } + return OMX_ErrorNone; +} + +/** @brief Part of the standard OpenMAX function + * + * This function return the parameters not related to any port. + * These parameters are handled in the derived components + * See OMX_Core.h for standard reference + * + * @return OMX_ErrorUnsupportedIndex if the index is not supported or not handled here + */ +OMX_ERRORTYPE omx_base_component_GetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_INOUT OMX_PTR ComponentParameterStructure) { + + OMX_COMPONENTTYPE *omxcomponent = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxcomponent->pComponentPrivate; + OMX_PRIORITYMGMTTYPE* pPrioMgmt; + OMX_PARAM_PORTDEFINITIONTYPE *pPortDef; + OMX_PARAM_BUFFERSUPPLIERTYPE *pBufferSupplier; + omx_base_PortType *pPort; + OMX_PORT_PARAM_TYPE* pPortDomains; + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_VENDOR_PROP_TUNNELSETUPTYPE *pPropTunnelSetup; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + DEBUG(DEB_LEV_PARAMS, "Getting parameter %i\n", nParamIndex); + if (ComponentParameterStructure == NULL) { + return OMX_ErrorBadParameter; + } + switch(nParamIndex) { + case OMX_IndexParamAudioInit: + case OMX_IndexParamVideoInit: + case OMX_IndexParamImageInit: + case OMX_IndexParamOtherInit: + pPortDomains = (OMX_PORT_PARAM_TYPE*)ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PORT_PARAM_TYPE))) != OMX_ErrorNone) { + break; + } + pPortDomains->nPorts = 0; + pPortDomains->nStartPortNumber = 0; + break; + case OMX_IndexParamPortDefinition: + pPortDef = (OMX_PARAM_PORTDEFINITIONTYPE*) ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PARAM_PORTDEFINITIONTYPE))) != OMX_ErrorNone) { + break; + } + if (pPortDef->nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + return OMX_ErrorBadPortIndex; + } + + memcpy(pPortDef, &omx_base_component_Private->ports[pPortDef->nPortIndex]->sPortParam, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + break; + case OMX_IndexParamPriorityMgmt: + pPrioMgmt = (OMX_PRIORITYMGMTTYPE*)ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PRIORITYMGMTTYPE))) != OMX_ErrorNone) { + break; + } + pPrioMgmt->nGroupPriority = omx_base_component_Private->nGroupPriority; + pPrioMgmt->nGroupID = omx_base_component_Private->nGroupID; + break; + case OMX_IndexParamCompBufferSupplier: + pBufferSupplier = (OMX_PARAM_BUFFERSUPPLIERTYPE*)ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PARAM_BUFFERSUPPLIERTYPE))) != OMX_ErrorNone) { + break; + } + if (pBufferSupplier->nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + return OMX_ErrorBadPortIndex; + } + + pPort = omx_base_component_Private->ports[pBufferSupplier->nPortIndex]; + + if (pPort->sPortParam.eDir == OMX_DirInput) { + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyInput; + } else if (PORT_IS_TUNNELED(pPort)) { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyOutput; + } else { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyUnspecified; + } + } else { + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyOutput; + } else if (PORT_IS_TUNNELED(pPort)) { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyInput; + } else { + pBufferSupplier->eBufferSupplier = OMX_BufferSupplyUnspecified; + } + } + break; + case OMX_IndexVendorCompPropTunnelFlags: + pPropTunnelSetup = (OMX_VENDOR_PROP_TUNNELSETUPTYPE*)ComponentParameterStructure; + + if (pPropTunnelSetup->nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + + DEBUG(DEB_LEV_ERR,"In %s OMX_IndexVendorCompPropTunnelFlags nPortIndex=%d Line=%d \n", + __func__,(int)pPropTunnelSetup->nPortIndex,__LINE__); + + return OMX_ErrorBadPortIndex; + } + + pPort = omx_base_component_Private->ports[pPropTunnelSetup->nPortIndex]; + + pPropTunnelSetup->nTunnelSetup.nTunnelFlags = pPort->nTunnelFlags; + pPropTunnelSetup->nTunnelSetup.eSupplier = pPort->eBufferSupplier; + break; + default: + err = OMX_ErrorUnsupportedIndex; + break; + } + return err; +} + +/** @brief Part of the standard OpenMAX function + * + * This function sets the parameters not related to any port. + * These parameters are handled in the derived components + * See OMX_Core.h for standard reference + * + * @return OMX_ErrorUnsupportedIndex if the index is not supported or not handled here + */ +OMX_ERRORTYPE omx_base_component_SetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_IN OMX_PTR ComponentParameterStructure) { + + OMX_PRIORITYMGMTTYPE* pPrioMgmt; + OMX_PARAM_PORTDEFINITIONTYPE *pPortDef; + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_COMPONENTTYPE *omxcomponent = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxcomponent->pComponentPrivate; + OMX_PARAM_BUFFERSUPPLIERTYPE *pBufferSupplier; + omx_base_PortType *pPort; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + DEBUG(DEB_LEV_PARAMS, "Setting parameter %x\n", nParamIndex); + if (ComponentParameterStructure == NULL) { + DEBUG(DEB_LEV_ERR, "In %s parameter provided is null! err = %x\n", __func__, err); + return OMX_ErrorBadParameter; + } + + switch(nParamIndex) { + case OMX_IndexParamAudioInit: + case OMX_IndexParamVideoInit: + case OMX_IndexParamImageInit: + case OMX_IndexParamOtherInit: + /* pPortParam = (OMX_PORT_PARAM_TYPE* ) ComponentParameterStructure;*/ + if (omx_base_component_Private->state != OMX_StateLoaded && + omx_base_component_Private->state != OMX_StateWaitForResources) { + return OMX_ErrorIncorrectStateOperation; + } + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PORT_PARAM_TYPE))) != OMX_ErrorNone) { + break; + } + err = OMX_ErrorUndefined; + break; + case OMX_IndexParamPortDefinition: + pPortDef = (OMX_PARAM_PORTDEFINITIONTYPE*) ComponentParameterStructure; + DEBUG(DEB_LEV_PARAMS, "Setting parameter OMX_IndexParamPortDefinition for port %d\n", pPortDef->nPortIndex); + err = omx_base_component_ParameterSanityCheck(hComponent, pPortDef->nPortIndex, pPortDef, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Parameter Check Error=%x\n",__func__,err); + break; + } + { + OMX_PARAM_PORTDEFINITIONTYPE *pPortParam; + OMX_U32 j,old_nBufferCountActual=0; + pPortParam = &omx_base_component_Private->ports[pPortDef->nPortIndex]->sPortParam; + if(pPortDef->nBufferCountActual < pPortParam->nBufferCountMin) { + DEBUG(DEB_LEV_ERR, "In %s nBufferCountActual of param (%i) is < of nBufferCountMin of port(%i)\n",__func__, (int)pPortDef->nBufferCountActual, (int)pPortParam->nBufferCountMin); + err = OMX_ErrorBadParameter; + break; + } + old_nBufferCountActual = pPortParam->nBufferCountActual; + pPortParam->nBufferCountActual = pPortDef->nBufferCountActual; + + switch(pPortDef->eDomain) { + case OMX_PortDomainAudio: + memcpy(&pPortParam->format.audio, &pPortDef->format.audio, sizeof(OMX_AUDIO_PORTDEFINITIONTYPE)); + break; + case OMX_PortDomainVideo: + pPortParam->format.video.pNativeRender = pPortDef->format.video.pNativeRender; + pPortParam->format.video.nFrameWidth = pPortDef->format.video.nFrameWidth; + pPortParam->format.video.nFrameHeight = pPortDef->format.video.nFrameHeight; + pPortParam->format.video.nStride = pPortDef->format.video.nStride; + pPortParam->format.video.xFramerate = pPortDef->format.video.xFramerate; + pPortParam->format.video.bFlagErrorConcealment = pPortDef->format.video.bFlagErrorConcealment; + pPortParam->format.video.eCompressionFormat = pPortDef->format.video.eCompressionFormat; + pPortParam->format.video.eColorFormat = pPortDef->format.video.eColorFormat; + pPortParam->format.video.pNativeWindow = pPortDef->format.video.pNativeWindow; + break; + case OMX_PortDomainImage: + pPortParam->format.image.nFrameWidth = pPortDef->format.image.nFrameWidth; + pPortParam->format.image.nFrameHeight = pPortDef->format.image.nFrameHeight; + pPortParam->format.image.nStride = pPortDef->format.image.nStride; + pPortParam->format.image.bFlagErrorConcealment = pPortDef->format.image.bFlagErrorConcealment; + pPortParam->format.image.eCompressionFormat = pPortDef->format.image.eCompressionFormat; + pPortParam->format.image.eColorFormat = pPortDef->format.image.eColorFormat; + pPortParam->format.image.pNativeWindow = pPortDef->format.image.pNativeWindow; + break; + case OMX_PortDomainOther: + memcpy(&pPortParam->format.other, &pPortDef->format.other, sizeof(OMX_OTHER_PORTDEFINITIONTYPE)); + break; + default: + DEBUG(DEB_LEV_ERR, "In %s wrong port domain. Out of OpenMAX scope\n",__func__); + err = OMX_ErrorBadParameter; + break; + } + + /*If component state Idle/Pause/Executing and re-alloc the following private variables */ + if ((omx_base_component_Private->state == OMX_StateIdle || + omx_base_component_Private->state == OMX_StatePause || + omx_base_component_Private->state == OMX_StateExecuting) && + (pPortParam->nBufferCountActual > old_nBufferCountActual)) { + + pPort = omx_base_component_Private->ports[pPortDef->nPortIndex]; + if(pPort->pInternalBufferStorage) { + if(PORT_IS_TUNNELED(pPort)){ + DEBUG(DEB_LEV_ERR, "In %s Attempt to reallocate tunneled buffers!\n",__func__); + return OMX_ErrorIncorrectStateOperation; + } + pPort->pInternalBufferStorage = (OMX_BUFFERHEADERTYPE**)realloc(pPort->pInternalBufferStorage,pPort->sPortParam.nBufferCountActual*sizeof(OMX_BUFFERHEADERTYPE *)); + } + + if(pPort->bBufferStateAllocated) { + pPort->bBufferStateAllocated = (BUFFER_STATUS_FLAG*)realloc(pPort->bBufferStateAllocated,pPort->sPortParam.nBufferCountActual*sizeof(BUFFER_STATUS_FLAG)); + for(j=0; j < pPort->sPortParam.nBufferCountActual; j++) { + pPort->bBufferStateAllocated[j] = BUFFER_FREE; + } + } + } + } + break; + case OMX_IndexParamPriorityMgmt: + if (omx_base_component_Private->state != OMX_StateLoaded && + omx_base_component_Private->state != OMX_StateWaitForResources) { + return OMX_ErrorIncorrectStateOperation; + } + pPrioMgmt = (OMX_PRIORITYMGMTTYPE*)ComponentParameterStructure; + if ((err = checkHeader(ComponentParameterStructure, sizeof(OMX_PRIORITYMGMTTYPE))) != OMX_ErrorNone) { + break; + } + omx_base_component_Private->nGroupPriority = pPrioMgmt->nGroupPriority; + omx_base_component_Private->nGroupID = pPrioMgmt->nGroupID; + break; + case OMX_IndexParamCompBufferSupplier: + pBufferSupplier = (OMX_PARAM_BUFFERSUPPLIERTYPE*)ComponentParameterStructure; + + DEBUG(DEB_LEV_PARAMS, "In %s Buf Sup Port index=%d\n", __func__,(int)pBufferSupplier->nPortIndex); + + if(pBufferSupplier == NULL) { + DEBUG(DEB_LEV_ERR, "In %s pBufferSupplier is null!\n",__func__); + return OMX_ErrorBadParameter; + } + if(pBufferSupplier->nPortIndex > (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + return OMX_ErrorBadPortIndex; + } + err = omx_base_component_ParameterSanityCheck(hComponent, pBufferSupplier->nPortIndex, pBufferSupplier, sizeof(OMX_PARAM_BUFFERSUPPLIERTYPE)); + if(err==OMX_ErrorIncorrectStateOperation) { + if (PORT_IS_ENABLED(omx_base_component_Private->ports[pBufferSupplier->nPortIndex])) { + DEBUG(DEB_LEV_ERR, "In %s Incorrect State=%x\n",__func__,omx_base_component_Private->state); + return OMX_ErrorIncorrectStateOperation; + } + } else if (err != OMX_ErrorNone) { + break; + } + + if (pBufferSupplier->eBufferSupplier == OMX_BufferSupplyUnspecified) { + DEBUG(DEB_LEV_PARAMS, "In %s: port is already buffer supplier unspecified\n", __func__); + return OMX_ErrorNone; + } + if ((PORT_IS_TUNNELED(omx_base_component_Private->ports[pBufferSupplier->nPortIndex])) == 0) { + return OMX_ErrorNone; + } + + pPort = omx_base_component_Private->ports[pBufferSupplier->nPortIndex]; + + if ((pBufferSupplier->eBufferSupplier == OMX_BufferSupplyInput) && + (pPort->sPortParam.eDir == OMX_DirInput)) { + /** These two cases regard the first stage of client override */ + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + err = OMX_ErrorNone; + } + pPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + pBufferSupplier->nPortIndex = pPort->nTunneledPort; + err = OMX_SetParameter(pPort->hTunneledComponent, OMX_IndexParamCompBufferSupplier, pBufferSupplier); + } else if ((pBufferSupplier->eBufferSupplier == OMX_BufferSupplyOutput) && + (pPort->sPortParam.eDir == OMX_DirInput)) { + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + pPort->nTunnelFlags &= ~TUNNEL_IS_SUPPLIER; + pBufferSupplier->nPortIndex = pPort->nTunneledPort; + err = OMX_SetParameter(pPort->hTunneledComponent, OMX_IndexParamCompBufferSupplier, pBufferSupplier); + } + err = OMX_ErrorNone; + } else if ((pBufferSupplier->eBufferSupplier == OMX_BufferSupplyOutput) && + (pPort->sPortParam.eDir == OMX_DirOutput)) { + /** these two cases regard the second stage of client override */ + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + err = OMX_ErrorNone; + } + pPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + } else { + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + pPort->nTunnelFlags &= ~TUNNEL_IS_SUPPLIER; + err = OMX_ErrorNone; + } + err = OMX_ErrorNone; + } + DEBUG(DEB_LEV_PARAMS, "In %s port %d Tunnel flag=%x \n", __func__,(int)pBufferSupplier->nPortIndex, (int)pPort->nTunnelFlags); + break; + default: + err = OMX_ErrorUnsupportedIndex; + break; + } + return err; +} + +/** @brief base GetConfig function + * + * This base function is not implemented. If a derived component + * needs to support any config, it must implement a derived + * version of this function and assign it to the correct pointer + * in the private component descriptor + */ +OMX_ERRORTYPE omx_base_component_GetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_INOUT OMX_PTR pComponentConfigStructure) { + return OMX_ErrorNotImplemented; +} + +/** @brief base SetConfig function + * + * This base function is not implemented. If a derived component + * needs to support any config, it must implement a derived + * version of this function and assign it to the correct pointer + * in the private component descriptor + */ +OMX_ERRORTYPE omx_base_component_SetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_IN OMX_PTR pComponentConfigStructure) { + // TODO: For now, do not return OMX_ErrorNotImplemented here because it breaks current COMXAudio + return OMX_ErrorNone; +} + +/** @brief base function not implemented + * + * This function can be eventually implemented by a + * derived component if needed + */ +OMX_ERRORTYPE omx_base_component_GetExtensionIndex( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_STRING cParameterName, + OMX_OUT OMX_INDEXTYPE* pIndexType) { + + DEBUG(DEB_LEV_FUNCTION_NAME,"In %s \n",__func__); + + return OMX_ErrorBadParameter; +} + +/** @return the state of the component + * + * This function does not need any override by derived components + */ +OMX_ERRORTYPE omx_base_component_GetState( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_STATETYPE* pState) { + OMX_COMPONENTTYPE *omxcomponent = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxcomponent->pComponentPrivate; + *pState = omx_base_component_Private->state; + return OMX_ErrorNone; +} + +/** @brief standard SendCommand function + * + * In general this function does not need a overwrite, but + * a special derived component could do it. + */ +OMX_ERRORTYPE omx_base_component_SendCommand( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_COMMANDTYPE Cmd, + OMX_IN OMX_U32 nParam, + OMX_IN OMX_PTR pCmdData) { + OMX_COMPONENTTYPE* omxComponent = (OMX_COMPONENTTYPE*)hComponent; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + internalRequestMessageType *message; + omx_queue_t* messageQueue; + omx_tsem_t* messageSem; + OMX_U32 i,j,k; + omx_base_PortType *pPort; + OMX_ERRORTYPE err = OMX_ErrorNone; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + messageQueue = omx_base_component_Private->messageQueue; + messageSem = omx_base_component_Private->messageSem; + + if (omx_base_component_Private->state == OMX_StateInvalid) { + return OMX_ErrorInvalidState; + } + + message = (internalRequestMessageType*)calloc(1,sizeof(internalRequestMessageType)); + message->messageParam = nParam; + message->pCmdData=pCmdData; + /** Fill in the message */ + switch (Cmd) { + case OMX_CommandStateSet: + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_CommandStateSet desired state=%d\n", __func__, nParam); + message->messageType = OMX_CommandStateSet; + if ((nParam == OMX_StateIdle) && (omx_base_component_Private->state == OMX_StateLoaded)) { + /*Allocate Internal Buffer Storage and Buffer Allocation State flags*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + + pPort = omx_base_component_Private->ports[i]; + + if(pPort->pInternalBufferStorage == NULL) { + pPort->pInternalBufferStorage = (OMX_BUFFERHEADERTYPE**)calloc(pPort->sPortParam.nBufferCountActual,sizeof(OMX_BUFFERHEADERTYPE *)); + } + + if(pPort->bBufferStateAllocated == NULL) { + pPort->bBufferStateAllocated = (BUFFER_STATUS_FLAG*)calloc(pPort->sPortParam.nBufferCountActual,sizeof(BUFFER_STATUS_FLAG)); + for(k=0; k < pPort->sPortParam.nBufferCountActual; k++) + { + pPort->bBufferStateAllocated[k] = BUFFER_FREE; + } + } + } + } + + omx_base_component_Private->transientState = OMX_TransStateLoadedToIdle; + } else if ((nParam == OMX_StateLoaded) && (omx_base_component_Private->state == OMX_StateIdle)) { + omx_base_component_Private->transientState = OMX_TransStateIdleToLoaded; + } else if ((nParam == OMX_StateIdle) && (omx_base_component_Private->state == OMX_StateExecuting)) { + omx_base_component_Private->transientState = OMX_TransStateExecutingToIdle; + } + break; + case OMX_CommandFlush: + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_CommandFlush port=%d\n", __func__, nParam); + if (nParam >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts) && nParam != OMX_ALL) { + return OMX_ErrorBadPortIndex; + } + message->messageType = OMX_CommandFlush; + break; + case OMX_CommandPortDisable: + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_CommandPortDisable port=%d\n", __func__, nParam); + if (nParam >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts) && nParam != OMX_ALL) { + return OMX_ErrorBadPortIndex; + } + message->messageType = OMX_CommandPortDisable; + if(message->messageParam == OMX_ALL) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + omx_base_component_Private->ports[i]->bIsTransientToDisabled = OMX_TRUE; + } + } + } else { + omx_base_component_Private->ports[message->messageParam]->bIsTransientToDisabled = OMX_TRUE; + } + break; + case OMX_CommandPortEnable: + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_CommandPortEnable port=%d\n", __func__, nParam); + if (nParam >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts) && nParam != OMX_ALL) { + return OMX_ErrorBadPortIndex; + } + message->messageType = OMX_CommandPortEnable; + if(message->messageParam == OMX_ALL) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + omx_base_component_Private->ports[i]->bIsTransientToEnabled = OMX_TRUE; + } + } + } else { + omx_base_component_Private->ports[message->messageParam]->bIsTransientToEnabled = OMX_TRUE; + } + break; + case OMX_CommandMarkBuffer: + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s OMX_CommandMarkBuffer port=%d\n", __func__, nParam); + if (nParam >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts) && nParam != OMX_ALL) { + return OMX_ErrorBadPortIndex; + } + message->messageType = OMX_CommandMarkBuffer; + break; + default: + err = OMX_ErrorUnsupportedIndex; + break; + } + + if (err == OMX_ErrorNone) + { + omx_queue(messageQueue, message); + omx_tsem_up(messageSem); + } + + DEBUG(DEB_LEV_FULL_SEQ, "In %s messageSem up param=%d\n", __func__,message->messageParam); + + return err; +} + +/** @brief Component's message handler thread function + * + * Handles all messages coming from components and + * processes them by dispatching them back to the + * triggering component. + */ +void* compMessageHandlerFunction(void* param) { + OMX_COMPONENTTYPE *openmaxStandComp = (OMX_COMPONENTTYPE *)param; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + internalRequestMessageType *message; + + while(1){ + if (omx_base_component_Private == NULL) { + break; + } + + /* Wait for an incoming message */ + omx_tsem_down(omx_base_component_Private->messageSem); + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + /*Destructor has been called. So exit from the loop*/ + if(omx_base_component_Private->state == OMX_StateInvalid) { + break; + } + + /* Dequeue it */ + message = (internalRequestMessageType*)omx_dequeue(omx_base_component_Private->messageQueue); + if(message == NULL){ + DEBUG(DEB_LEV_ERR, "In %s: ouch!! had null message!\n", __func__); + break; + } + /* Process it by calling component's message handler method */ + omx_base_component_Private->messageHandler(openmaxStandComp,message); + /* Message ownership has been transferred to us + * so we gonna free it when finished. + */ + free(message); + message = NULL; + } + DEBUG(DEB_LEV_FUNCTION_NAME,"Exiting Message Handler thread\n"); + return NULL; +} + +/** This is called by the component message entry point. + * In thea base version this function is named compMessageHandlerFunction + * + * A request is made by the component when some asynchronous services are needed: + * 1) A SendCommand() is to be processed + * 2) An error needs to be notified + * 3) ... + * + * @param openmaxStandComp the component itself + * @param message the message that has been passed to core + */ +OMX_ERRORTYPE omx_base_component_MessageHandler(OMX_COMPONENTTYPE *openmaxStandComp,internalRequestMessageType* message) { + omx_base_component_PrivateType* omx_base_component_Private=(omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + OMX_U32 i,j,k; + OMX_ERRORTYPE err = OMX_ErrorNone; + omx_base_PortType* pPort; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + /* Dealing with a SendCommand call. + * -messageType contains the command to execute + * -messageParam contains the parameter of the command + * (destination state in case of a state change command). + */ + switch(message->messageType){ + case OMX_CommandStateSet: { + /* Do the actual state change */ + err = (*(omx_base_component_Private->DoStateSet))(openmaxStandComp, message->messageParam); + if (err != OMX_ErrorNone) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + err, /* The commands was a OMX_CommandStateSet */ + 0, /* The state has been changed in message->messageParam */ + NULL); + } else { + /* And run the callback */ + DEBUG(DEB_LEV_FULL_SEQ,"running callback in %s\n",__func__); + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandStateSet, /* The commands was a OMX_CommandStateSet */ + message->messageParam, /* The state has been changed in message->messageParam */ + NULL); + } + } + break; + case OMX_CommandFlush: { + /*Flush port/s*/ + if(message->messageParam == OMX_ALL) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + omx_base_component_Private->ports[i]->bIsPortFlushed = OMX_TRUE; + } + } + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort=omx_base_component_Private->ports[i]; + err = pPort->FlushProcessingBuffers(pPort); + } + } + } + else { + pPort=omx_base_component_Private->ports[message->messageParam]; + err = pPort->FlushProcessingBuffers(pPort); + } + if (err != OMX_ErrorNone) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + err, /* The commands was a OMX_CommandStateSet */ + 0, /* The state has been changed in message->messageParam */ + NULL); + } else { + if(message->messageParam == OMX_ALL){ /*Flush all port*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandFlush, /* The commands was a OMX_CommandStateSet */ + i, /* The state has been changed in message->messageParam */ + NULL); + + pPort=omx_base_component_Private->ports[i]; + /* Signal the buffer Semaphore and the buffer managment semaphore, to restart the exchange of buffers after flush */ + if (PORT_IS_TUNNELED(pPort) && PORT_IS_BUFFER_SUPPLIER(pPort)) { + for(k=0;knNumTunnelBuffer;k++) { + omx_tsem_up(pPort->pBufferSem); + /*signal buffer management thread availability of buffers*/ + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + } + } else {/*Flush input/output port*/ + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandFlush, /* The commands was a OMX_CommandStateSet */ + message->messageParam, /* The state has been changed in message->messageParam */ + NULL); + /* Signal the buffer Semaphore and the buffer managment semaphore, to restart the exchange of buffers after flush */ + if (PORT_IS_TUNNELED(omx_base_component_Private->ports[message->messageParam]) + && PORT_IS_BUFFER_SUPPLIER(omx_base_component_Private->ports[message->messageParam])) { + for(j=0;jports[message->messageParam]->nNumTunnelBuffer;j++) { + omx_tsem_up(omx_base_component_Private->ports[message->messageParam]->pBufferSem); + /*signal buffer management thread availability of buffers*/ + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + } + } + break; + case OMX_CommandPortDisable: { + /*Flush port/s*/ + if(message->messageParam == OMX_ALL) { + /*If Component is not in loaded state,then First Flush all buffers then disable the port*/ + if(omx_base_component_Private->state!=OMX_StateLoaded) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort=omx_base_component_Private->ports[i]; + err = pPort->FlushProcessingBuffers(pPort); + } + } + } + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort=omx_base_component_Private->ports[i]; + err = pPort->Port_DisablePort(pPort); + } + } + } + else { + pPort=omx_base_component_Private->ports[message->messageParam]; + if(omx_base_component_Private->state!=OMX_StateLoaded) { + err = pPort->FlushProcessingBuffers(pPort); + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Port Flush completed for Comp %s\n",__func__,omx_base_component_Private->name); + } + err = pPort->Port_DisablePort(pPort); + } + /** This condition is added to pass the tests, it is not significant for the environment */ + if (err != OMX_ErrorNone) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + err, /* The commands was a OMX_CommandStateSet */ + 0, /* The state has been changed in message->messageParam */ + NULL); + } else { + if(message->messageParam == OMX_ALL){ /*Disable all ports*/ + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandPortDisable, /* The commands was a OMX_CommandStateSet */ + i, /* The state has been changed in message->messageParam */ + NULL); + } + } + } else { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandPortDisable, /* The commands was a OMX_CommandStateSet */ + message->messageParam, /* The state has been changed in message->messageParam */ + NULL); + } + } + } + break; + case OMX_CommandPortEnable:{ + /*Flush port/s*/ + if(message->messageParam == OMX_ALL) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort=omx_base_component_Private->ports[i]; + err = pPort->Port_EnablePort(pPort); + } + } + } else { + pPort=omx_base_component_Private->ports[message->messageParam]; + err = pPort->Port_EnablePort(pPort); + } + if (err != OMX_ErrorNone) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + err, /* The commands was a OMX_CommandStateSet */ + 0, /* The state has been changed in message->messageParam */ + NULL); + } else { + if(message->messageParam != OMX_ALL) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandPortEnable, /* The commands was a OMX_CommandStateSet */ + message->messageParam, /* The state has been changed in message->messageParam */ + NULL); + + if (omx_base_component_Private->state==OMX_StateExecuting) { + pPort=omx_base_component_Private->ports[message->messageParam]; + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + for(i=0; i < pPort->sPortParam.nBufferCountActual;i++) { + omx_tsem_up(pPort->pBufferSem); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + + } else { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventCmdComplete, /* The command was completed */ + OMX_CommandPortEnable, /* The commands was a OMX_CommandStateSet */ + i, /* The state has been changed in message->messageParam */ + NULL); + } + } + + if (omx_base_component_Private->state==OMX_StateExecuting) { + /* for all ports */ + for(j = 0; j < NUM_DOMAINS; j++) { + for(i = omx_base_component_Private->sPortTypesParam[j].nStartPortNumber; + i < omx_base_component_Private->sPortTypesParam[j].nStartPortNumber + + omx_base_component_Private->sPortTypesParam[j].nPorts; i++) { + pPort=omx_base_component_Private->ports[i]; + if (PORT_IS_BUFFER_SUPPLIER(pPort)) { + for(k=0; k < pPort->sPortParam.nBufferCountActual;k++) { + omx_tsem_up(pPort->pBufferSem); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + } + } + } + } + } + } + break; + case OMX_CommandMarkBuffer: { + omx_base_component_Private->pMark.hMarkTargetComponent = ((OMX_MARKTYPE *)message->pCmdData)->hMarkTargetComponent; + omx_base_component_Private->pMark.pMarkData = ((OMX_MARKTYPE *)message->pCmdData)->pMarkData; + } + break; + default: + DEBUG(DEB_LEV_ERR, "In %s: Unrecognized command %i\n", __func__, message->messageType); + break; + } + DEBUG(DEB_LEV_SIMPLE_SEQ, "Returning from %s: \n", __func__); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_base_component_AllocateBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pAppPrivate, + OMX_IN OMX_U32 nSizeBytes) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + + if (nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port index\n", __func__); + return OMX_ErrorBadPortIndex; + } + pPort = omx_base_component_Private->ports[nPortIndex]; + + return pPort->Port_AllocateBuffer(pPort, + ppBuffer, + nPortIndex, + pAppPrivate, + nSizeBytes); +} + +OMX_ERRORTYPE omx_base_component_UseBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pAppPrivate, + OMX_IN OMX_U32 nSizeBytes, + OMX_IN OMX_U8* pBuffer) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + + if (nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port index\n", __func__); + return OMX_ErrorBadPortIndex; + } + pPort = omx_base_component_Private->ports[nPortIndex]; + + return pPort->Port_UseBuffer(pPort, + ppBufferHdr, + nPortIndex, + pAppPrivate, + nSizeBytes, + pBuffer); +} + +OMX_ERRORTYPE omx_base_component_UseEGLImage ( + OMX_HANDLETYPE hComponent, + OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + void* eglImage) { + return OMX_ErrorNotImplemented; +} + +OMX_ERRORTYPE omx_base_component_FreeBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + + if (nPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port index\n", __func__); + return OMX_ErrorBadPortIndex; + } + + pPort = omx_base_component_Private->ports[nPortIndex]; + + return pPort->Port_FreeBuffer(pPort, + nPortIndex, + pBuffer); +} + +OMX_ERRORTYPE omx_base_component_EmptyThisBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + //DEBUG(DEB_LEV_FUNCTION_NAME, "In %s pBuffer=0x%x pBuffer->pBuffer=0x%x nInputPortIndex=%d nOutputPortIndex=%d nAllocLen=%d nFilledLen=%d\n", + // __func__, pBuffer, pBuffer->pBuffer, pBuffer->nInputPortIndex, pBuffer->nOutputPortIndex, pBuffer->nAllocLen, pBuffer->nFilledLen); + + if (pBuffer->nInputPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port index\n", __func__); + return OMX_ErrorBadPortIndex; + } + pPort = omx_base_component_Private->ports[pBuffer->nInputPortIndex]; + if (pPort->sPortParam.eDir != OMX_DirInput) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port direction in Component %s\n", __func__,omx_base_component_Private->name); + return OMX_ErrorBadPortIndex; + } + return pPort->Port_SendBufferFunction(pPort, pBuffer); +} + +OMX_ERRORTYPE omx_base_component_FillThisBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { + + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + if (pBuffer->nOutputPortIndex >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port index\n", __func__); + return OMX_ErrorBadPortIndex; + } + pPort = omx_base_component_Private->ports[pBuffer->nOutputPortIndex]; + if (pPort->sPortParam.eDir != OMX_DirOutput) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port direction in Component %s\n", __func__,omx_base_component_Private->name); + return OMX_ErrorBadPortIndex; + } + return pPort->Port_SendBufferFunction(pPort, pBuffer); +} + +OMX_ERRORTYPE omx_base_component_ComponentTunnelRequest( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_U32 nPort, + OMX_IN OMX_HANDLETYPE hTunneledComp, + OMX_IN OMX_U32 nTunneledPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup) { + + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + omx_base_PortType *pPort; + + if (nPort >= (omx_base_component_Private->sPortTypesParam[OMX_PortDomainAudio].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainVideo].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainImage].nPorts + + omx_base_component_Private->sPortTypesParam[OMX_PortDomainOther].nPorts)) { + return OMX_ErrorBadPortIndex; + } + + pPort = omx_base_component_Private->ports[nPort]; + + return pPort->ComponentTunnelRequest(pPort, hTunneledComp, nTunneledPort, pTunnelSetup); +} diff --git a/alsa/omx_base_component.h b/alsa/omx_base_component.h new file mode 100644 index 0000000..9134119 --- /dev/null +++ b/alsa/omx_base_component.h @@ -0,0 +1,412 @@ +/** + @file src/base/omx_base_component.h + + OpenMAX base component. This component does not perform any multimedia + processing.It is used as a base component for new components development. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-09-11 11:45:59 +0200 (Thu, 11 Sep 2008) $ + Revision $Rev: 613 $ + Author $Author: pankaj_sen $ + +*/ +#ifndef _OMX_BASE_COMPONENT_H_ +#define _OMX_BASE_COMPONENT_H_ + +#include + +#include "omx_semaphore.h" +#include "omx_queue.h" +#include "omx_classmagic.h" +#include "omx_base_port.h" + +/** Default size of the internal input buffer */ +#define DEFAULT_IN_BUFFER_SIZE 4 * 1024 +/** Default size of the internal output buffer */ +#define DEFAULT_OUT_BUFFER_SIZE 16 * 1024 /*32 * 1024*/ /*16 * 1024 */ // TODO - check this size is ok +/** Default MIME string length */ +#define DEFAULT_MIME_STRING_LENGTH 128 + +#define NUM_DOMAINS 4 + +/* Check if Component is deinitalizing*/ +#define IS_COMPONENT_DEINIT(component_Private, exit_condition) \ + pthread_mutex_lock(&component_Private->exit_mutex) ,\ + exit_condition = component_Private->bIsComponentDeinit ,\ + pthread_mutex_unlock(&component_Private->exit_mutex) ,\ + (exit_condition == OMX_TRUE) ? OMX_TRUE:OMX_FALSE \ + +typedef struct OMX_VENDOR_EXTRADATATYPE { + OMX_U32 nPortIndex; + OMX_U32 nDataSize; // Size of the supporting data to follow + OMX_U8 *pData; // Supporting data hint +} OMX_VENDOR_EXTRADATATYPE; + +typedef struct OMX_VENDOR_PROP_TUNNELSETUPTYPE { + OMX_U32 nPortIndex; + OMX_TUNNELSETUPTYPE nTunnelSetup; // Tunnel setup flags +} OMX_VENDOR_PROP_TUNNELSETUPTYPE; + +/** this is the list of custom vendor index */ +typedef enum OMX_INDEXVENDORTYPE { + /** only one index for file reader component input file */ + OMX_IndexVendorFileReadInputFilename = 0xFF000001, + OMX_IndexVendorParser3gpInputFilename = 0xFF000002, + OMX_IndexVendorVideoExtraData = 0xFF000003, + OMX_IndexVendorAudioExtraData = 0xFF000004, + OMX_IndexVendorCompPropTunnelFlags = 0xFF000005 /* Will use OMX_TUNNELSETUPTYPE structure*/ +} OMX_INDEXVENDORTYPE; + +/** This enum defines the transition states of the Component*/ +typedef enum OMX_TRANS_STATETYPE { + OMX_TransStateInvalid, + OMX_TransStateLoadedToIdle, + OMX_TransStateIdleToPause, + OMX_TransStatePauseToExecuting, + OMX_TransStateIdleToExecuting, + OMX_TransStateExecutingToIdle, + OMX_TransStateExecutingToPause, + OMX_TransStatePauseToIdle, + OMX_TransStateIdleToLoaded, + OMX_TransStateMax = 0X7FFFFFFF +} OMX_TRANS_STATETYPE; + +/** @brief Enumerates all the possible types of messages + * handled internally by the component + */ +typedef enum INTERNAL_MESSAGE_TYPE { + SENDCOMMAND_MSG_TYPE = 1,/**< this flag specifies that the message send is a command */ + ERROR_MSG_TYPE,/**< this flag specifies that the message send is an error message */ + WARNING_MSG_TYPE /**< this flag specifies that the message send is a warning message */ +} INTERNAL_MESSAGE_TYPE; + +/** @brief The container of an internal message + * + * This structure contains a generic OpenMAX request (from send command). + * It is processed by the internal message handler thread + */ +typedef struct internalRequestMessageType { + int messageType; /**< the flag that specifies if the message is a command, a warning or an error */ + int messageParam; /**< the second field of the message. Its use is the same as specified for the command in OpenMAX spec */ + OMX_PTR pCmdData; /**< This pointer could contain some proprietary data not covered by the standard */ +} internalRequestMessageType; + +/** + * @brief the base descriptor for a ST component + */ +CLASS(omx_base_component_PrivateType) +#define omx_base_component_PrivateType_FIELDS \ + OMX_COMPONENTTYPE *openmaxStandComp; /**< The OpenMAX standard data structure describing a component */ \ + omx_base_PortType **ports; /** @param ports The ports of the component */ \ + OMX_PORT_PARAM_TYPE sPortTypesParam[NUM_DOMAINS]; /** @param sPortTypesParam OpenMAX standard parameter that contains a short description of the available ports */ \ + char uniqueID; /**< ID code that identifies an ST static component*/ \ + char* name; /**< component name */\ + OMX_STATETYPE state; /**< The state of the component */ \ + OMX_TRANS_STATETYPE transientState; /**< The transient state in case of transition between \ + Loaded/waitForResources - Idle. It is equal to \ + Invalid if the state or transition are not corect \ + Loaded when the transition is from Idle to Loaded \ + Idle when the transition is from Loaded to Idle */ \ + OMX_CALLBACKTYPE* callbacks; /**< pointer to every client callback function, \ + as specified by the standard*/ \ + OMX_PTR callbackData;/**< Private data that can be send with \ + the client callbacks. Not specified by the standard */ \ + omx_queue_t* messageQueue;/**< the queue of all the messages recevied by the component */\ + omx_tsem_t* messageSem;/**< the semaphore that coordinates the access to the message queue */\ + OMX_U32 nGroupPriority; /**< @param nGroupPriority Resource management field: component priority (common to a group of components) */\ + OMX_U32 nGroupID; /**< @param nGroupID ID of a group of components that share the same logical chain */\ + OMX_MARKTYPE pMark; /**< @param pMark This field holds the private data associated with a mark request, if any */\ + pthread_mutex_t flush_mutex; /** @param flush_mutex mutex for the flush condition from buffers */ \ + omx_tsem_t* flush_all_condition; /** @param flush_all_condition condition for the flush all buffers */ \ + omx_tsem_t* flush_condition; /** @param The flush_condition condition */ \ + omx_tsem_t* bMgmtSem;/**< @param bMgmtSem the semaphore that control BufferMgmtFunction processing */\ + omx_tsem_t* bStateSem;/**< @param bMgmtSem the semaphore that control BufferMgmtFunction processing */\ + int messageHandlerThreadID; /** @param messageHandlerThreadID The ID of the pthread that handles the messages for the components */ \ + pthread_t messageHandlerThread; /** @param messageHandlerThread This field contains the reference to the thread that receives messages for the components */ \ + int bufferMgmtThreadID; /** @param bufferMgmtThreadID The ID of the pthread that process buffers */ \ + pthread_t bufferMgmtThread; /** @param bufferMgmtThread This field contains the reference to the thread that process buffers */ \ + void *loader; /**< pointer to the loader that created this component, used for destruction */ \ + void* (*BufferMgmtFunction)(void* param); /** @param BufferMgmtFunction This function processes input output buffers */ \ + OMX_ERRORTYPE (*messageHandler)(OMX_COMPONENTTYPE*,internalRequestMessageType*);/** This function receives messages from the message queue. It is needed for each Linux ST OpenMAX component */ \ + OMX_ERRORTYPE (*DoStateSet)(OMX_COMPONENTTYPE *openmaxStandComp, OMX_U32); /**< @param DoStateSet internal function called when a generic state transition is requested*/ \ + OMX_ERRORTYPE (*destructor)(OMX_COMPONENTTYPE *openmaxStandComp); /** Component Destructor*/ +ENDCLASS(omx_base_component_PrivateType) + +/** + * @brief The base contructor for the OpenMAX ST components + * + * This function is executed by the ST static component loader. + * It takes care of constructing the instance of the component. + * For the base_component component, the following is done: + * + * 1) Fills the basic OpenMAX structure. The fields can be overwritten + * by derived components. + * 2) Allocates (if needed) the omx_base_component_PrivateType private structure + * + * @param openmaxStandComp the ST component to be initialized + * @param cComponentName the OpenMAX string that describes the component + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ +OMX_ERRORTYPE omx_base_component_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName); + +/** @brief the base destructor for ST OpenMAX components + * + * This function is called by the standard function ComponentDeInit() + * that is called by the IL core during the execution of the FreeHandle() + * + * @param openmaxStandComp the ST OpenMAX component to be disposed + */ +OMX_ERRORTYPE omx_base_component_Destructor(OMX_COMPONENTTYPE *openmaxStandComp); + +/** Changes the state of a component taking proper actions depending on + * the transiotion requested. This base function cover only the state + * changes that do not involve any port + * + * @param openmaxStandComp the OpenMAX component which state is to be changed + * @param destinationState the requested target state + * + * @return OMX_ErrorNotImplemented if the state change is noty handled + * in this base class, but needs a specific handling + */ +OMX_ERRORTYPE omx_base_component_DoStateSet( + OMX_COMPONENTTYPE *openmaxStandComp, + OMX_U32 destinationState); + +/** @brief Checks the header of a structure for consistency + * with size and spec version + * + * @param header Pointer to the structure to be checked + * @param size Size of the structure. it is in general obtained + * with a sizeof call applied to the structure + * + * @return OMX error code. If the header has failed the check, + * OMX_ErrorVersionMismatch is returned. + * If the header fails the size check OMX_ErrorBadParameter is returned + */ +OMX_ERRORTYPE checkHeader(OMX_PTR header, OMX_U32 size); + +/** @brief Simply fills the first two fields in any OMX structure + * with the size and the version + * + * @param header pointer to the structure to be filled + * @param size size of the structure. It can be obtained with + * a call to sizeof of the structure type + */ +void setHeader(OMX_PTR header, OMX_U32 size); + +/** @brief standard openmax function + * + * it returns the version of the component. See OMX_Core.h + */ +OMX_ERRORTYPE omx_base_component_GetComponentVersion(OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_STRING pComponentName, + OMX_OUT OMX_VERSIONTYPE* pComponentVersion, + OMX_OUT OMX_VERSIONTYPE* pSpecVersion, + OMX_OUT OMX_UUIDTYPE* pComponentUUID); + +/** @brief Enumerates all the role of the component. + * + * This function is intended to be used only by a core. The ST static core + * in any case does not use this function, because it can not be used before the + * creation of the component, but uses a static list. + * It is implemented only for API completion, and it will be not overriden + * by a derived component. + * + * @param hComponent handle of the component + * @param cRole the output string containing the n-role of the component + * @param nIndex the index of the role requested + */ +OMX_ERRORTYPE omx_base_component_ComponentRoleEnum( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_U8 *cRole, + OMX_IN OMX_U32 nIndex); + +/** @brief standard OpenMAX function + * + * it sets the callback functions given by the IL client. + * See OMX_Component.h + */ +OMX_ERRORTYPE omx_base_component_SetCallbacks( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_CALLBACKTYPE* pCallbacks, + OMX_IN OMX_PTR pAppData); + +/** @brief Part of the standard OpenMAX function + * + * This function return the parameters not related to any port. + * These parameters are handled in the derived components + * See OMX_Core.h for standard reference. + */ +OMX_ERRORTYPE omx_base_component_GetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_INOUT OMX_PTR ComponentParameterStructure); + +/** @brief part of the standard openmax function + * + * This function return the parameters not related to any port, + * These parameters are handled in the derived components + * See OMX_Core.h for standard reference. + * + * @return OMX_ErrorUnsupportedIndex if the index is not supported or not handled here + */ +OMX_ERRORTYPE omx_base_component_SetParameter( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nParamIndex, + OMX_IN OMX_PTR ComponentParameterStructure); + +/** @brief base GetConfig function + * + * This base function is not implemented. If a derived component + * needs to support any config, it must implement a derived + * version of this function and assign it to the correct pointer + * in the private component descriptor. + */ +OMX_ERRORTYPE omx_base_component_GetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_INOUT OMX_PTR pComponentConfigStructure); + +/** @brief base SetConfig function + * + * This base function is not implemented. If a derived component + * needs to support any config, it must implement a derived + * version of this function and assign it to the correct pointer + * in the private component descriptor. + */ +OMX_ERRORTYPE omx_base_component_SetConfig( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_INDEXTYPE nIndex, + OMX_IN OMX_PTR pComponentConfigStructure); + +/** @brief base function not implemented + * + * This function can be eventually implemented by a + * derived component if needed. + */ +OMX_ERRORTYPE omx_base_component_GetExtensionIndex( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_STRING cParameterName, + OMX_OUT OMX_INDEXTYPE* pIndexType); + +/** @returns the state of the component + * + * This function does not need any override by derived components. + */ +OMX_ERRORTYPE omx_base_component_GetState( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_OUT OMX_STATETYPE* pState); + +/** @brief standard SendCommand function + * + * In general this function does not need a overwrite, but + * a special derived component could do it. + */ +OMX_ERRORTYPE omx_base_component_SendCommand( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_COMMANDTYPE Cmd, + OMX_IN OMX_U32 nParam, + OMX_IN OMX_PTR pCmdData); + +/** @brief This standard functionality is called when the component is + * destroyed in the FreeHandle standard call. + * + * In this way the implementation of the FreeHandle is standard, + * and it does not need a support by a specific component loader. + * The implementaiton of the ComponentDeInit contains the + * implementation specific part of the destroying phase. + */ +OMX_ERRORTYPE omx_base_component_ComponentDeInit( + OMX_IN OMX_HANDLETYPE hComponent); + +/** @brief Component's message handler thread function + * + * Handles all messages coming from components and + * processes them by dispatching them back to the + * triggering component. + */ +void* compMessageHandlerFunction(void*); + +/** This is called by the component message entry point. + * In thea base version this function is named compMessageHandlerFunction + * + * A request is made by the component when some asynchronous services are needed: + * 1) A SendCommand() is to be processed + * 2) An error needs to be notified + * 3) ... + * + * @param openmaxStandComp the component itself + * @param message the message that has been passed to core + */ +OMX_ERRORTYPE omx_base_component_MessageHandler(OMX_COMPONENTTYPE *openmaxStandComp,internalRequestMessageType* message); + +/** + * This function verify Component State and Structure header + */ +OMX_ERRORTYPE omx_base_component_ParameterSanityCheck( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pStructure, + OMX_IN size_t size); + +OMX_ERRORTYPE omx_base_component_AllocateBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pAppPrivate, + OMX_IN OMX_U32 nSizeBytes); + +OMX_ERRORTYPE omx_base_component_UseBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pAppPrivate, + OMX_IN OMX_U32 nSizeBytes, + OMX_IN OMX_U8* pBuffer); + +OMX_ERRORTYPE omx_base_component_UseEGLImage ( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_PTR pAppPrivate, + OMX_IN void* eglImage); + +OMX_ERRORTYPE omx_base_component_FreeBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +OMX_ERRORTYPE omx_base_component_EmptyThisBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +OMX_ERRORTYPE omx_base_component_FillThisBuffer( + OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +OMX_ERRORTYPE omx_base_component_ComponentTunnelRequest( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 nPort, + OMX_IN OMX_HANDLETYPE hTunneledComp, + OMX_IN OMX_U32 nTunneledPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup); + +#endif diff --git a/alsa/omx_base_port.cpp b/alsa/omx_base_port.cpp new file mode 100644 index 0000000..67d003a --- /dev/null +++ b/alsa/omx_base_port.cpp @@ -0,0 +1,1163 @@ +/** + @file src/base/omx_base_port.c + + Base class for OpenMAX ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-09-11 15:28:59 +0200 (Thu, 11 Sep 2008) $ + Revision $Rev: 614 $ + Author $Author: gsent $ +*/ + +#include +#include +#include +//#include +//#include + +#include "omx_base_component.h" +#include "omx_base_port.h" + +/** The default value for the number of needed buffers for each port. */ +#define DEFAULT_NUMBER_BUFFERS_PER_PORT 4 +/** The default value for the minimum number of needed buffers for each port. */ +#define DEFAULT_MIN_NUMBER_BUFFERS_PER_PORT 4 +/** + * @brief The base contructor for the generic OpenMAX ST port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandComp in the component that holds the port + * @param openmaxStandPort the ST port to be initialized + * @param nPortIndex the index of the port + * @param isInput specifices if the port is an input or an output + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ + +OMX_ERRORTYPE base_port_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,omx_base_PortType **openmaxStandPort,OMX_U32 nPortIndex, OMX_BOOL isInput) { + + /* omx_base_component_PrivateType* omx_base_component_Private; */ + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + /* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; */ + + // create ports, but only if the subclass hasn't done it + if (!(*openmaxStandPort)) { + *openmaxStandPort = (omx_base_PortType*)calloc(1,sizeof (omx_base_PortType)); + } + + if (!(*openmaxStandPort)) { + return OMX_ErrorInsufficientResources; + } + + (*openmaxStandPort)->hTunneledComponent = NULL; + (*openmaxStandPort)->nTunnelFlags=0; + (*openmaxStandPort)->nTunneledPort=0; + (*openmaxStandPort)->eBufferSupplier=OMX_BufferSupplyUnspecified; + (*openmaxStandPort)->nNumTunnelBuffer=0; + (*openmaxStandPort)->bTunnelTearDown = OMX_FALSE; + + if((*openmaxStandPort)->pAllocSem==NULL) { + (*openmaxStandPort)->pAllocSem = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + if((*openmaxStandPort)->pAllocSem==NULL) { + return OMX_ErrorInsufficientResources; + } + omx_tsem_init((*openmaxStandPort)->pAllocSem, 0); + } + (*openmaxStandPort)->nNumBufferFlushed=0; + (*openmaxStandPort)->bIsPortFlushed=OMX_FALSE; + /** Allocate and initialize buffer queue */ + if(!(*openmaxStandPort)->pBufferQueue) { + (*openmaxStandPort)->pBufferQueue = (omx_queue_t*)calloc(1,sizeof(omx_queue_t)); + if((*openmaxStandPort)->pBufferQueue==NULL) return OMX_ErrorInsufficientResources; + omx_queue_init((*openmaxStandPort)->pBufferQueue); + } + /*Allocate and initialise port semaphores*/ + if(!(*openmaxStandPort)->pBufferSem) { + (*openmaxStandPort)->pBufferSem = (omx_tsem_t*)calloc(1,sizeof(omx_tsem_t)); + if((*openmaxStandPort)->pBufferSem==NULL) return OMX_ErrorInsufficientResources; + omx_tsem_init((*openmaxStandPort)->pBufferSem, 0); + } + + (*openmaxStandPort)->nNumAssignedBuffers=0; + setHeader(&(*openmaxStandPort)->sPortParam, sizeof (OMX_PARAM_PORTDEFINITIONTYPE)); + (*openmaxStandPort)->sPortParam.nPortIndex = nPortIndex; + (*openmaxStandPort)->sPortParam.nBufferCountActual = DEFAULT_NUMBER_BUFFERS_PER_PORT; + (*openmaxStandPort)->sPortParam.nBufferCountMin = DEFAULT_MIN_NUMBER_BUFFERS_PER_PORT; + (*openmaxStandPort)->sPortParam.bEnabled = OMX_TRUE; + (*openmaxStandPort)->sPortParam.bPopulated = OMX_FALSE; + (*openmaxStandPort)->sPortParam.eDir = (isInput == OMX_TRUE)?OMX_DirInput:OMX_DirOutput; + + (*openmaxStandPort)->standCompContainer=openmaxStandComp; + (*openmaxStandPort)->bIsTransientToEnabled=OMX_FALSE; + (*openmaxStandPort)->bIsTransientToDisabled=OMX_FALSE; + (*openmaxStandPort)->bIsFullOfBuffers=OMX_FALSE; + (*openmaxStandPort)->bIsEmptyOfBuffers=OMX_FALSE; + (*openmaxStandPort)->bBufferStateAllocated = NULL; + (*openmaxStandPort)->pInternalBufferStorage = NULL; + + (*openmaxStandPort)->PortDestructor = &base_port_Destructor; + (*openmaxStandPort)->Port_AllocateBuffer = &base_port_AllocateBuffer; + (*openmaxStandPort)->Port_UseBuffer = &base_port_UseBuffer; + (*openmaxStandPort)->Port_FreeBuffer = &base_port_FreeBuffer; + (*openmaxStandPort)->Port_DisablePort = &base_port_DisablePort; + (*openmaxStandPort)->Port_EnablePort = &base_port_EnablePort; + (*openmaxStandPort)->Port_SendBufferFunction = &base_port_SendBufferFunction; + (*openmaxStandPort)->FlushProcessingBuffers = &base_port_FlushProcessingBuffers; + (*openmaxStandPort)->ReturnBufferFunction = &base_port_ReturnBufferFunction; + (*openmaxStandPort)->ComponentTunnelRequest = &base_port_ComponentTunnelRequest; + (*openmaxStandPort)->Port_AllocateTunnelBuffer = &base_port_AllocateTunnelBuffer; + (*openmaxStandPort)->Port_FreeTunnelBuffer = &base_port_FreeTunnelBuffer; + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE base_port_Destructor(omx_base_PortType *openmaxStandPort){ + + if(openmaxStandPort->pAllocSem) { + omx_tsem_deinit(openmaxStandPort->pAllocSem); + free(openmaxStandPort->pAllocSem); + openmaxStandPort->pAllocSem=NULL; + } + /** Allocate and initialize buffer queue */ + if(openmaxStandPort->pBufferQueue) { + omx_queue_deinit(openmaxStandPort->pBufferQueue); + free(openmaxStandPort->pBufferQueue); + openmaxStandPort->pBufferQueue=NULL; + } + /*Allocate and initialise port semaphores*/ + if(openmaxStandPort->pBufferSem) { + omx_tsem_deinit(openmaxStandPort->pBufferSem); + free(openmaxStandPort->pBufferSem); + openmaxStandPort->pBufferSem=NULL; + } + + free(openmaxStandPort); + openmaxStandPort = NULL; + return OMX_ErrorNone; +} + +/** @brief Releases buffers under processing. + * This function must be implemented in the derived classes, for the + * specific processing + */ +OMX_ERRORTYPE base_port_FlushProcessingBuffers(omx_base_PortType *openmaxStandPort) { + omx_base_component_PrivateType* omx_base_component_Private; + OMX_BUFFERHEADERTYPE* pBuffer; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandPort->standCompContainer->pComponentPrivate; + + if(openmaxStandPort->sPortParam.eDomain!=OMX_PortDomainOther) { /* clock buffers not used in the clients buffer managment function */ + pthread_mutex_lock(&omx_base_component_Private->flush_mutex); + openmaxStandPort->bIsPortFlushed=OMX_TRUE; + /*Signal the buffer management thread of port flush,if it is waiting for buffers*/ + if(omx_base_component_Private->bMgmtSem->semval==0) { + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + + if(omx_base_component_Private->state==OMX_StatePause ) { + /*Waiting at paused state*/ + omx_tsem_signal(omx_base_component_Private->bStateSem); + } + DEBUG(DEB_LEV_FULL_SEQ, "In %s waiting for flush all condition port index =%d\n", __func__,(int)openmaxStandPort->sPortParam.nPortIndex); + /* Wait until flush is completed */ + pthread_mutex_unlock(&omx_base_component_Private->flush_mutex); + omx_tsem_down(omx_base_component_Private->flush_all_condition); + } + + omx_tsem_reset(omx_base_component_Private->bMgmtSem); + + /* Flush all the buffers not under processing */ + while (openmaxStandPort->pBufferSem->semval > 0) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s TFlag=%x Flusing Port=%d,Semval=%d Qelem=%d\n", + __func__,(int)openmaxStandPort->nTunnelFlags,(int)openmaxStandPort->sPortParam.nPortIndex, + (int)openmaxStandPort->pBufferSem->semval,(int)openmaxStandPort->pBufferQueue->nelem); + + omx_tsem_down(openmaxStandPort->pBufferSem); + pBuffer = (OMX_BUFFERHEADERTYPE*)omx_dequeue(openmaxStandPort->pBufferQueue); + if (PORT_IS_TUNNELED(openmaxStandPort) && !PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Comp %s is returning io:%d buffer\n", + __func__,omx_base_component_Private->name,(int)openmaxStandPort->sPortParam.nPortIndex); + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->FillThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + } else { + ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->EmptyThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + } + } else if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + omx_queue(openmaxStandPort->pBufferQueue,pBuffer); + } else { + (*(openmaxStandPort->BufferProcessedCallback))( + openmaxStandPort->standCompContainer, + omx_base_component_Private->callbackData, + pBuffer); + } + } + /*Port is tunneled and supplier and didn't received all it's buffer then wait for the buffers*/ + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + while(openmaxStandPort->pBufferQueue->nelem!= openmaxStandPort->nNumAssignedBuffers){ + omx_tsem_down(openmaxStandPort->pBufferSem); + DEBUG(DEB_LEV_PARAMS, "In %s Got a buffer qelem=%d\n",__func__,openmaxStandPort->pBufferQueue->nelem); + } + omx_tsem_reset(openmaxStandPort->pBufferSem); + } + + pthread_mutex_lock(&omx_base_component_Private->flush_mutex); + openmaxStandPort->bIsPortFlushed=OMX_FALSE; + pthread_mutex_unlock(&omx_base_component_Private->flush_mutex); + + omx_tsem_up(omx_base_component_Private->flush_condition); + + DEBUG(DEB_LEV_FULL_SEQ, "Out %s Port Index=%d bIsPortFlushed=%d Component %s\n", __func__, + (int)openmaxStandPort->sPortParam.nPortIndex,(int)openmaxStandPort->bIsPortFlushed,omx_base_component_Private->name); + + DEBUG(DEB_LEV_PARAMS, "In %s TFlag=%x Qelem=%d BSem=%d bMgmtsem=%d component=%s\n", __func__, + (int)openmaxStandPort->nTunnelFlags, + (int)openmaxStandPort->pBufferQueue->nelem, + (int)openmaxStandPort->pBufferSem->semval, + (int)omx_base_component_Private->bMgmtSem->semval, + omx_base_component_Private->name); + + DEBUG(DEB_LEV_FUNCTION_NAME, "Out %s Port Index=%d\n", __func__,(int)openmaxStandPort->sPortParam.nPortIndex); + + return OMX_ErrorNone; +} + +/** @brief Disables the port. + * + * This function is called due to a request by the IL client + * + * @param openmaxStandPort the reference to the port + * + */ +OMX_ERRORTYPE base_port_DisablePort(omx_base_PortType *openmaxStandPort) { + omx_base_component_PrivateType* omx_base_component_Private; + OMX_ERRORTYPE err=OMX_ErrorNone; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s Port Index=%d\n", __func__,(int)openmaxStandPort->sPortParam.nPortIndex); + omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandPort->standCompContainer->pComponentPrivate; + if (! PORT_IS_ENABLED(openmaxStandPort)) { + return OMX_ErrorNone; + } + + if(omx_base_component_Private->state!=OMX_StateLoaded) { + if(!PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)) { + /*Signal Buffer Mgmt Thread if it's holding any buffer*/ + if(omx_base_component_Private->bMgmtSem->semval==0) { + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + /*Wait till all buffers are freed*/ + omx_tsem_down(openmaxStandPort->pAllocSem); + omx_tsem_reset(omx_base_component_Private->bMgmtSem); + } else { + /*Since port is being disabled then remove buffers from the queue*/ + while(openmaxStandPort->pBufferQueue->nelem > 0) { + omx_dequeue(openmaxStandPort->pBufferQueue); + } + + err = openmaxStandPort->Port_FreeTunnelBuffer(openmaxStandPort,openmaxStandPort->sPortParam.nPortIndex); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Freeing Tunnel Buffer Error=%x\n",__func__,err); + } + DEBUG(DEB_LEV_PARAMS, "In %s Qelem=%d\n", __func__,openmaxStandPort->pBufferQueue->nelem); + } + + if(openmaxStandPort->bTunnelTearDown == OMX_TRUE){ + DEBUG(DEB_LEV_PARAMS, "In %s TearDown tunnel\n", __func__); + openmaxStandPort->hTunneledComponent = 0; + openmaxStandPort->nTunneledPort = 0; + openmaxStandPort->nTunnelFlags = 0; + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyUnspecified; + openmaxStandPort->bTunnelTearDown = OMX_FALSE; + } + } + + DEBUG(DEB_LEV_PARAMS, "In %s TFlag=%x Qelem=%d BSem=%d bMgmtsem=%d component=%s\n", __func__, + (int)openmaxStandPort->nTunnelFlags, + (int)openmaxStandPort->pBufferQueue->nelem, + (int)openmaxStandPort->pBufferSem->semval, + (int)omx_base_component_Private->bMgmtSem->semval, + omx_base_component_Private->name); + openmaxStandPort->bIsTransientToDisabled = OMX_FALSE; + openmaxStandPort->sPortParam.bEnabled = OMX_FALSE; + DEBUG(DEB_LEV_FUNCTION_NAME, "Out %s Port Index=%d isEnabled=%d\n", __func__, + (int)openmaxStandPort->sPortParam.nPortIndex, + (int)openmaxStandPort->sPortParam.bEnabled); + return err; +} + +/** @brief Enables the port. + * + * This function is called due to a request by the IL client + * + * @param openmaxStandPort the reference to the port + * + */ +OMX_ERRORTYPE base_port_EnablePort(omx_base_PortType *openmaxStandPort) { + omx_base_component_PrivateType* omx_base_component_Private; + OMX_ERRORTYPE err=OMX_ErrorNone; + OMX_U32 i; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + if (PORT_IS_ENABLED(openmaxStandPort)) { + return OMX_ErrorNone; + } + omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandPort->standCompContainer->pComponentPrivate; + + openmaxStandPort->sPortParam.bEnabled = OMX_TRUE; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s port T flag=%x popu=%d state=%x\n", __func__, + (int)openmaxStandPort->nTunnelFlags, + (int)openmaxStandPort->sPortParam.bPopulated, + (int)omx_base_component_Private->state); + + + if (!PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)) { + /*Wait Till All buffers are allocated if the component state is not Loaded*/ + if (omx_base_component_Private->state!=OMX_StateLoaded && omx_base_component_Private->state!=OMX_StateWaitForResources) { + omx_tsem_down(openmaxStandPort->pAllocSem); + openmaxStandPort->sPortParam.bPopulated = OMX_TRUE; + } + } else { //Port Tunneled and supplier. Then allocate tunnel buffers + err= openmaxStandPort->Port_AllocateTunnelBuffer(openmaxStandPort, openmaxStandPort->sPortParam.nPortIndex, openmaxStandPort->sPortParam.nBufferSize); + if(err!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s Allocating Tunnel Buffer Error=%x\n",__func__,err); + return err; + } + openmaxStandPort->sPortParam.bPopulated = OMX_TRUE; + if (omx_base_component_Private->state==OMX_StateExecuting) { + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual;i++) { + omx_tsem_up(openmaxStandPort->pBufferSem); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + } + } + DEBUG(DEB_LEV_PARAMS, "In %s Qelem=%d BSem=%d\n", __func__,openmaxStandPort->pBufferQueue->nelem,openmaxStandPort->pBufferSem->semval); + } + + openmaxStandPort->bIsTransientToEnabled = OMX_FALSE; + + DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__); + + return OMX_ErrorNone; +} + +/** @brief Called by the standard allocate buffer, it implements a base functionality. + * + * This function can be overriden if the allocation of the buffer is not a simply calloc call. + * The parameters are the same as the standard function, except for the handle of the port + * instead of the handler of the component + * When the buffers needed by this port are all assigned or allocated, the variable + * bIsFullOfBuffers becomes equal to OMX_TRUE + */ +OMX_ERRORTYPE base_port_AllocateBuffer( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE** pBuffer, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes) { + + unsigned int i; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (nPortIndex != openmaxStandPort->sPortParam.nPortIndex) { + return OMX_ErrorBadPortIndex; + } + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + return OMX_ErrorBadPortIndex; + } + + if ((omx_base_component_Private->transientState != OMX_TransStateLoadedToIdle) || (omx_base_component_Private->state!=OMX_StateLoaded)) { + if (!openmaxStandPort->bIsTransientToEnabled) { + DEBUG(DEB_LEV_ERR, "In %s: The port is not allowed to receive buffers\n", __func__); + return OMX_ErrorIncorrectStateTransition; + } + } + + if(nSizeBytes < openmaxStandPort->sPortParam.nBufferSize) { + DEBUG(DEB_LEV_ERR, "In %s: Requested Buffer Size %lu is less than Minimum Buffer Size %lu\n", __func__, (unsigned long)nSizeBytes, (unsigned long)openmaxStandPort->sPortParam.nBufferSize); + return OMX_ErrorIncorrectStateTransition; + } + + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (openmaxStandPort->bBufferStateAllocated[i] == BUFFER_FREE) { + openmaxStandPort->pInternalBufferStorage[i] = (OMX_BUFFERHEADERTYPE*)calloc(1,sizeof(OMX_BUFFERHEADERTYPE)); + if (!openmaxStandPort->pInternalBufferStorage[i]) { + return OMX_ErrorInsufficientResources; + } + setHeader(openmaxStandPort->pInternalBufferStorage[i], sizeof(OMX_BUFFERHEADERTYPE)); + /* allocate the buffer */ + openmaxStandPort->pInternalBufferStorage[i]->pBuffer = (OMX_U8*)calloc(1,nSizeBytes); + if(openmaxStandPort->pInternalBufferStorage[i]->pBuffer==NULL) { + return OMX_ErrorInsufficientResources; + } + openmaxStandPort->pInternalBufferStorage[i]->nAllocLen = nSizeBytes; + openmaxStandPort->pInternalBufferStorage[i]->pPlatformPrivate = openmaxStandPort; + openmaxStandPort->pInternalBufferStorage[i]->pAppPrivate = pAppPrivate; + *pBuffer = openmaxStandPort->pInternalBufferStorage[i]; + openmaxStandPort->bBufferStateAllocated[i] = BUFFER_ALLOCATED; + openmaxStandPort->bBufferStateAllocated[i] |= HEADER_ALLOCATED; + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + openmaxStandPort->pInternalBufferStorage[i]->nInputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + } else { + openmaxStandPort->pInternalBufferStorage[i]->nOutputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + } + openmaxStandPort->nNumAssignedBuffers++; + DEBUG(DEB_LEV_PARAMS, "openmaxStandPort->nNumAssignedBuffers %i\n", (int)openmaxStandPort->nNumAssignedBuffers); + + if (openmaxStandPort->sPortParam.nBufferCountActual == openmaxStandPort->nNumAssignedBuffers) { + openmaxStandPort->sPortParam.bPopulated = OMX_TRUE; + openmaxStandPort->bIsFullOfBuffers = OMX_TRUE; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s nPortIndex=%d\n",__func__,(int)nPortIndex); + omx_tsem_up(openmaxStandPort->pAllocSem); + } + return OMX_ErrorNone; + } + } + DEBUG(DEB_LEV_ERR, "In %s Error: no available buffers\n",__func__); + return OMX_ErrorInsufficientResources; +} + +/** @brief Called by the standard use buffer, it implements a base functionality. + * + * This function can be overriden if the use buffer implicate more complicated operations. + * The parameters are the same as the standard function, except for the handle of the port + * instead of the handler of the component. + * When the buffers needed by this port are all assigned or allocated, the variable + * bIsFullOfBuffers becomes equal to OMX_TRUE + */ +OMX_ERRORTYPE base_port_UseBuffer( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes, + OMX_U8* pBuffer) { + + unsigned int i; + OMX_BUFFERHEADERTYPE* returnBufferHeader; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + if (nPortIndex != openmaxStandPort->sPortParam.nPortIndex) { + return OMX_ErrorBadPortIndex; + } + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + return OMX_ErrorBadPortIndex; + } + + if (omx_base_component_Private->transientState != OMX_TransStateLoadedToIdle) { + if (!openmaxStandPort->bIsTransientToEnabled) { + DEBUG(DEB_LEV_ERR, "In %s: The port of Comp %s is not allowed to receive buffers\n", __func__,omx_base_component_Private->name); + return OMX_ErrorIncorrectStateTransition; + } + } + + /// AND + /* + if(nSizeBytes < openmaxStandPort->sPortParam.nBufferSize) { + DEBUG(DEB_LEV_ERR, "In %s: Given Buffer Size %lu is less than Minimum Buffer Size %lu\n", __func__, nSizeBytes, openmaxStandPort->sPortParam.nBufferSize); + return OMX_ErrorIncorrectStateTransition; + } + */ + /// AND + + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (openmaxStandPort->bBufferStateAllocated[i] == BUFFER_FREE) { + openmaxStandPort->pInternalBufferStorage[i] = (OMX_BUFFERHEADERTYPE*)calloc(1,sizeof(OMX_BUFFERHEADERTYPE)); + if (!openmaxStandPort->pInternalBufferStorage[i]) { + return OMX_ErrorInsufficientResources; + } + openmaxStandPort->bIsEmptyOfBuffers = OMX_FALSE; + setHeader(openmaxStandPort->pInternalBufferStorage[i], sizeof(OMX_BUFFERHEADERTYPE)); + + openmaxStandPort->pInternalBufferStorage[i]->pBuffer = pBuffer; + openmaxStandPort->pInternalBufferStorage[i]->nAllocLen = nSizeBytes; + openmaxStandPort->pInternalBufferStorage[i]->pPlatformPrivate = openmaxStandPort; + openmaxStandPort->pInternalBufferStorage[i]->pAppPrivate = pAppPrivate; + openmaxStandPort->bBufferStateAllocated[i] = BUFFER_ASSIGNED; + openmaxStandPort->bBufferStateAllocated[i] |= HEADER_ALLOCATED; + returnBufferHeader = (OMX_BUFFERHEADERTYPE*)calloc(1,sizeof(OMX_BUFFERHEADERTYPE)); + if (!returnBufferHeader) { + return OMX_ErrorInsufficientResources; + } + setHeader(returnBufferHeader, sizeof(OMX_BUFFERHEADERTYPE)); + returnBufferHeader->pBuffer = pBuffer; + returnBufferHeader->nAllocLen = nSizeBytes; + returnBufferHeader->pPlatformPrivate = openmaxStandPort; + returnBufferHeader->pAppPrivate = pAppPrivate; + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + openmaxStandPort->pInternalBufferStorage[i]->nInputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + returnBufferHeader->nInputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + } else { + openmaxStandPort->pInternalBufferStorage[i]->nOutputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + returnBufferHeader->nOutputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + } + *ppBufferHdr = returnBufferHeader; + openmaxStandPort->nNumAssignedBuffers++; + DEBUG(DEB_LEV_PARAMS, "openmaxStandPort->nNumAssignedBuffers %i\n", (int)openmaxStandPort->nNumAssignedBuffers); + + if (openmaxStandPort->sPortParam.nBufferCountActual == openmaxStandPort->nNumAssignedBuffers) { + openmaxStandPort->sPortParam.bPopulated = OMX_TRUE; + openmaxStandPort->bIsFullOfBuffers = OMX_TRUE; + omx_tsem_up(openmaxStandPort->pAllocSem); + } + return OMX_ErrorNone; + } + } + DEBUG(DEB_LEV_ERR, "In %s Error: no available buffers CompName=%s\n",__func__,omx_base_component_Private->name); + return OMX_ErrorInsufficientResources; +} + +/** @brief Called by the standard function. + * + * It frees the buffer header and in case also the buffer itself, if needed. + * When all the bufers are done, the variable bIsEmptyOfBuffers is set to OMX_TRUE + */ +OMX_ERRORTYPE base_port_FreeBuffer( + omx_base_PortType *openmaxStandPort, + OMX_U32 nPortIndex, + OMX_BUFFERHEADERTYPE* pBuffer) { + + unsigned int i; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (nPortIndex != openmaxStandPort->sPortParam.nPortIndex) { + return OMX_ErrorBadPortIndex; + } + if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + return OMX_ErrorBadPortIndex; + } + + if (omx_base_component_Private->transientState != OMX_TransStateIdleToLoaded) { + if (!openmaxStandPort->bIsTransientToDisabled) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s: The port is not allowed to free the buffers\n", __func__); + (*(omx_base_component_Private->callbacks->EventHandler)) + (omxComponent, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + OMX_ErrorPortUnpopulated, /* The commands was a OMX_CommandStateSet */ + nPortIndex, /* The state has been changed in message->messageParam2 */ + NULL); + } + } + + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (openmaxStandPort->bBufferStateAllocated[i] & (BUFFER_ASSIGNED | BUFFER_ALLOCATED)) { + + openmaxStandPort->bIsFullOfBuffers = OMX_FALSE; + if (openmaxStandPort->bBufferStateAllocated[i] & BUFFER_ALLOCATED) { + if(openmaxStandPort->pInternalBufferStorage[i]->pBuffer){ + DEBUG(DEB_LEV_PARAMS, "In %s freeing %i pBuffer=%x\n",__func__, (int)i, (int)openmaxStandPort->pInternalBufferStorage[i]->pBuffer); + free(openmaxStandPort->pInternalBufferStorage[i]->pBuffer); + openmaxStandPort->pInternalBufferStorage[i]->pBuffer=NULL; + } + } else if (openmaxStandPort->bBufferStateAllocated[i] & BUFFER_ASSIGNED) { + free(pBuffer); + } + if(openmaxStandPort->bBufferStateAllocated[i] & HEADER_ALLOCATED) { + free(openmaxStandPort->pInternalBufferStorage[i]); + openmaxStandPort->pInternalBufferStorage[i]=NULL; + } + + openmaxStandPort->bBufferStateAllocated[i] = BUFFER_FREE; + + openmaxStandPort->nNumAssignedBuffers--; + DEBUG(DEB_LEV_PARAMS, "openmaxStandPort->nNumAssignedBuffers %i\n", (int)openmaxStandPort->nNumAssignedBuffers); + + if (openmaxStandPort->nNumAssignedBuffers == 0) { + openmaxStandPort->sPortParam.bPopulated = OMX_FALSE; + openmaxStandPort->bIsEmptyOfBuffers = OMX_TRUE; + omx_tsem_up(openmaxStandPort->pAllocSem); + } + return OMX_ErrorNone; + } + } + return OMX_ErrorInsufficientResources; +} + +OMX_ERRORTYPE base_port_AllocateTunnelBuffer(omx_base_PortType *openmaxStandPort,OMX_IN OMX_U32 nPortIndex,OMX_IN OMX_U32 nSizeBytes) +{ + unsigned int i; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + OMX_U8* pBuffer=NULL; + OMX_ERRORTYPE eError=OMX_ErrorNone; + OMX_U32 numRetry=0; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s, nPortIndex=%d, nSizeBytes=%d, nBufferCountActual=%d\n", __func__, nPortIndex, nSizeBytes, openmaxStandPort->sPortParam.nBufferCountActual); + + if (nPortIndex != openmaxStandPort->sPortParam.nPortIndex) { + DEBUG(DEB_LEV_ERR, "In %s: Bad Port Index\n", __func__); + return OMX_ErrorBadPortIndex; + } + if (! PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + DEBUG(DEB_LEV_ERR, "In %s: Port is not tunneled Flag=%x\n", __func__, (int)openmaxStandPort->nTunnelFlags); + return OMX_ErrorBadPortIndex; + } + + if (omx_base_component_Private->transientState != OMX_TransStateLoadedToIdle) { + if (!openmaxStandPort->bIsTransientToEnabled) { + DEBUG(DEB_LEV_ERR, "In %s: The port is not allowed to receive buffers\n", __func__); + return OMX_ErrorIncorrectStateTransition; + } + } + + if( NULL == openmaxStandPort->bBufferStateAllocated ) + { + openmaxStandPort->bBufferStateAllocated = (BUFFER_STATUS_FLAG*)calloc(openmaxStandPort->sPortParam.nBufferCountActual, sizeof(openmaxStandPort->bBufferStateAllocated[0] )); + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++) + { + openmaxStandPort->bBufferStateAllocated[i] = BUFFER_FREE; + } + } + + if( NULL == openmaxStandPort->pInternalBufferStorage ) + { + openmaxStandPort->pInternalBufferStorage = (OMX_BUFFERHEADERTYPE**)calloc(openmaxStandPort->sPortParam.nBufferCountActual, sizeof(OMX_BUFFERHEADERTYPE*)); + /*for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++) + { + //memset(&openmaxStandPort->pInternalBufferStorage[i], 0, sizeof(OMX_BUFFERHEADERTYPE*)); + setHeader(&openmaxStandPort->pInternalBufferStorage[i], sizeof(OMX_BUFFERHEADERTYPE*)); + }*/ + } + + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (openmaxStandPort->bBufferStateAllocated[i] == BUFFER_FREE) { + pBuffer = (OMX_U8*)calloc(1,nSizeBytes); + if(pBuffer==NULL) { + return OMX_ErrorInsufficientResources; + } + /*Retry more than once, if the tunneled component is not in Loaded->Idle State*/ + while(numRetry hTunneledComponent,&openmaxStandPort->pInternalBufferStorage[i], + openmaxStandPort->nTunneledPort,NULL,nSizeBytes,pBuffer); + if (checkHeader(openmaxStandPort->pInternalBufferStorage[i], sizeof(OMX_BUFFERHEADERTYPE)) != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s: received wrong buffer header after OMX_UseBuffer\n", __func__); + return OMX_ErrorBadParameter; + } + if(eError!=OMX_ErrorNone) { + OMX_STATETYPE state; + OMX_GetState( openmaxStandPort->hTunneledComponent, &state ); + DEBUG(DEB_LEV_FULL_SEQ,"Tunneled Component Couldn't Use buffer %i From Comp=%s Retry=%d Other state=%d\n", + i,omx_base_component_Private->name,(int)numRetry, (int)state); + /// AND + // see 2.1.1 and 3.2 in http://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Application_Note_318.pdf + //if((eError == OMX_ErrorIncorrectStateTransition) && numRetryname,(int)numRetry); + break; + } + } + if(eError!=OMX_ErrorNone) { + free(pBuffer); + pBuffer = NULL; + DEBUG(DEB_LEV_ERR,"In %s Tunneled Component Couldn't Use Buffer %x \n",__func__,(int)eError); + return eError; + } + openmaxStandPort->bBufferStateAllocated[i] = BUFFER_ALLOCATED; + openmaxStandPort->nNumAssignedBuffers++; + DEBUG(DEB_LEV_PARAMS, "openmaxStandPort->nNumAssignedBuffers %i\n", (int)openmaxStandPort->nNumAssignedBuffers); + + if (openmaxStandPort->sPortParam.nBufferCountActual == openmaxStandPort->nNumAssignedBuffers) { + openmaxStandPort->sPortParam.bPopulated = OMX_TRUE; + openmaxStandPort->bIsFullOfBuffers = OMX_TRUE; + DEBUG(DEB_LEV_SIMPLE_SEQ, "In %s nPortIndex=%d\n",__func__, (int)nPortIndex); + } + omx_queue(openmaxStandPort->pBufferQueue, openmaxStandPort->pInternalBufferStorage[i]); + } + } + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s Allocated all buffers\n",__func__); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE base_port_FreeTunnelBuffer(omx_base_PortType *openmaxStandPort,OMX_U32 nPortIndex) +{ + unsigned int i; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + OMX_ERRORTYPE eError=OMX_ErrorNone; + OMX_U32 numRetry=0; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (nPortIndex != openmaxStandPort->sPortParam.nPortIndex) { + DEBUG(DEB_LEV_ERR, "In %s: Bad Port Index\n", __func__); + return OMX_ErrorBadPortIndex; + } + if (! PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) { + DEBUG(DEB_LEV_ERR, "In %s: Port is not tunneled\n", __func__); + return OMX_ErrorBadPortIndex; + } + + if (omx_base_component_Private->transientState != OMX_TransStateIdleToLoaded) { + if (!openmaxStandPort->bIsTransientToDisabled) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s: The port is not allowed to free the buffers\n", __func__); + (*(omx_base_component_Private->callbacks->EventHandler)) + (omxComponent, + omx_base_component_Private->callbackData, + OMX_EventError, /* The command was completed */ + OMX_ErrorPortUnpopulated, /* The commands was a OMX_CommandStateSet */ + nPortIndex, /* The state has been changed in message->messageParam2 */ + NULL); + } + } + + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (openmaxStandPort->bBufferStateAllocated[i] & (BUFFER_ASSIGNED | BUFFER_ALLOCATED)) { + + openmaxStandPort->bIsFullOfBuffers = OMX_FALSE; + if (openmaxStandPort->bBufferStateAllocated[i] & BUFFER_ALLOCATED) { + free(openmaxStandPort->pInternalBufferStorage[i]->pBuffer); + openmaxStandPort->pInternalBufferStorage[i]->pBuffer = NULL; + } + /*Retry more than once, if the tunneled component is not in Idle->Loaded State*/ + while(numRetry hTunneledComponent,openmaxStandPort->nTunneledPort,openmaxStandPort->pInternalBufferStorage[i]); + if(eError!=OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"Tunneled Component Couldn't free buffer %i \n",i); + // see 2.1.2 and 3.1 in http://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Application_Note_318.pdf + if((eError == OMX_ErrorIncorrectStateTransition) && numRetrybBufferStateAllocated[i] = BUFFER_FREE; + + openmaxStandPort->nNumAssignedBuffers--; + DEBUG(DEB_LEV_PARAMS, "openmaxStandPort->nNumAssignedBuffers %i\n", (int)openmaxStandPort->nNumAssignedBuffers); + + if (openmaxStandPort->nNumAssignedBuffers == 0) { + openmaxStandPort->sPortParam.bPopulated = OMX_FALSE; + openmaxStandPort->bIsEmptyOfBuffers = OMX_TRUE; + //omx_tsem_up(openmaxStandPort->pAllocSem); + } + } + } + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s Qelem=%d BSem=%d\n", __func__,openmaxStandPort->pBufferQueue->nelem,openmaxStandPort->pBufferSem->semval); + return OMX_ErrorNone; +} + +/** @brief the entry point for sending buffers to the port + * + * This function can be called by the EmptyThisBuffer or FillThisBuffer. It depends on + * the nature of the port, that can be an input or output port. + */ +OMX_ERRORTYPE base_port_SendBufferFunction( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer) { + + OMX_ERRORTYPE err; + OMX_U32 portIndex; + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; +#if NO_GST_OMX_PATCH + unsigned int i; +#endif + portIndex = (openmaxStandPort->sPortParam.eDir == OMX_DirInput)?pBuffer->nInputPortIndex:pBuffer->nOutputPortIndex; + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s portIndex %lu\n", __func__, (unsigned long)portIndex); + + if (portIndex != openmaxStandPort->sPortParam.nPortIndex) { + DEBUG(DEB_LEV_ERR, "In %s: wrong port for this operation portIndex=%d port->portIndex=%d\n", __func__, (int)portIndex, (int)openmaxStandPort->sPortParam.nPortIndex); + return OMX_ErrorBadPortIndex; + } + + if(omx_base_component_Private->state == OMX_StateInvalid) { + DEBUG(DEB_LEV_ERR, "In %s: we are in OMX_StateInvalid\n", __func__); + return OMX_ErrorInvalidState; + } + + if(omx_base_component_Private->state != OMX_StateExecuting && + omx_base_component_Private->state != OMX_StatePause && + omx_base_component_Private->state != OMX_StateIdle) { + DEBUG(DEB_LEV_ERR, "In %s: we are not in executing/paused/idle state, but in %d\n", __func__, omx_base_component_Private->state); + return OMX_ErrorIncorrectStateOperation; + } + if (!PORT_IS_ENABLED(openmaxStandPort) || (PORT_IS_BEING_DISABLED(openmaxStandPort) && !PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort)) || + (omx_base_component_Private->transientState == OMX_TransStateExecutingToIdle && + (PORT_IS_TUNNELED(openmaxStandPort) && !PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)))) { + DEBUG(DEB_LEV_ERR, "In %s: Port %d is disabled comp = %s \n", __func__, (int)portIndex,omx_base_component_Private->name); + return OMX_ErrorIncorrectStateOperation; + } + + /* Temporarily disable this check for gst-openmax */ +#if NO_GST_OMX_PATCH + { + OMX_BOOL foundBuffer = OMX_FALSE; + if(pBuffer!=NULL && pBuffer->pBuffer!=NULL) { + for(i=0; i < openmaxStandPort->sPortParam.nBufferCountActual; i++){ + if (pBuffer->pBuffer == openmaxStandPort->pInternalBufferStorage[i]->pBuffer) { + foundBuffer = OMX_TRUE; + break; + } + } + } + if (!foundBuffer) { + return OMX_ErrorBadParameter; + } + } +#endif + + if ((err = checkHeader(pBuffer, sizeof(OMX_BUFFERHEADERTYPE))) != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s: received wrong buffer header on input port\n", __func__); + return err; + } + + /* And notify the buffer management thread we have a fresh new buffer to manage */ + if(!PORT_IS_BEING_FLUSHED(openmaxStandPort) && !(PORT_IS_BEING_DISABLED(openmaxStandPort) && PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort))){ + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + DEBUG(DEB_LEV_PARAMS, "In %s Signalling bMgmtSem Port Index=%d\n",__func__, (int)portIndex); + omx_tsem_up(omx_base_component_Private->bMgmtSem); + }else if(PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)){ + DEBUG(DEB_LEV_FULL_SEQ, "In %s: Comp %s received io:%d buffer\n", + __func__,omx_base_component_Private->name,(int)openmaxStandPort->sPortParam.nPortIndex); + omx_queue(openmaxStandPort->pBufferQueue, pBuffer); + omx_tsem_up(openmaxStandPort->pBufferSem); + } + else { // If port being flushed and not tunneled then return error + DEBUG(DEB_LEV_FULL_SEQ, "In %s \n", __func__); + return OMX_ErrorIncorrectStateOperation; + } + return OMX_ErrorNone; +} + +/** + * Returns Input/Output Buffer to the IL client or Tunneled Component + */ +OMX_ERRORTYPE base_port_ReturnBufferFunction(omx_base_PortType* openmaxStandPort,OMX_BUFFERHEADERTYPE* pBuffer){ + omx_base_component_PrivateType* omx_base_component_Private=(omx_base_component_PrivateType*)openmaxStandPort->standCompContainer->pComponentPrivate; + omx_queue_t* pQueue = openmaxStandPort->pBufferQueue; + omx_tsem_t* pSem = openmaxStandPort->pBufferSem; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + if (PORT_IS_TUNNELED(openmaxStandPort) && + ! PORT_IS_BUFFER_SUPPLIER(openmaxStandPort)) { + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + pBuffer->nOutputPortIndex = openmaxStandPort->nTunneledPort; + pBuffer->nInputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + eError = ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->FillThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + if(eError != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s eError %08x in FillThis Buffer from Component %s Non-Supplier\n", + __func__, eError,omx_base_component_Private->name); + } + } else { + pBuffer->nInputPortIndex = openmaxStandPort->nTunneledPort; + pBuffer->nOutputPortIndex = openmaxStandPort->sPortParam.nPortIndex; + eError = ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->EmptyThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + if(eError != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR, "In %s eError %08x in EmptyThis Buffer from Component %s Non-Supplier\n", + __func__, eError,omx_base_component_Private->name); + } + } + } + else if (PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(openmaxStandPort) && + !PORT_IS_BEING_FLUSHED(openmaxStandPort)) { + if (!PORT_IS_ENABLED(openmaxStandPort) || PORT_IS_BEING_DISABLED(openmaxStandPort)) { + omx_queue(pQueue, pBuffer); + omx_tsem_up(pSem); + } else if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + eError = ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->FillThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + /// AND TODO: + /// see 2.2 of http://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Application_Note_318.pdf + if(eError != OMX_ErrorNone) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s eError %08x in FillThis Buffer from Component %s Supplier\n", + __func__, eError,omx_base_component_Private->name); + /*If Error Occured then queue the buffer*/ + omx_queue(pQueue, pBuffer); + omx_tsem_up(pSem); + } + } else { + eError = ((OMX_COMPONENTTYPE*)(openmaxStandPort->hTunneledComponent))->EmptyThisBuffer(openmaxStandPort->hTunneledComponent, pBuffer); + if(eError != OMX_ErrorNone) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s eError %08x in EmptyThis Buffer from Component %s Supplier\n", + __func__, eError,omx_base_component_Private->name); + /*If Error Occured then queue the buffer*/ + omx_queue(pQueue, pBuffer); + omx_tsem_up(pSem); + } + } + }else if (! PORT_IS_TUNNELED(openmaxStandPort)){ + (*(openmaxStandPort->BufferProcessedCallback))( + openmaxStandPort->standCompContainer, + omx_base_component_Private->callbackData, + pBuffer); + } + else { + omx_queue(pQueue,pBuffer); + openmaxStandPort->nNumBufferFlushed++; + } + + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE base_port_ComponentTunnelRequest(omx_base_PortType* openmaxStandPort,OMX_IN OMX_HANDLETYPE hTunneledComp,OMX_IN OMX_U32 nTunneledPort,OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup) { + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE param; + OMX_PARAM_BUFFERSUPPLIERTYPE pSupplier; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__); + + if (pTunnelSetup == NULL || hTunneledComp == 0) { + /* cancel previous tunnel */ + OMX_COMPONENTTYPE* omxComponent = openmaxStandPort->standCompContainer; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)omxComponent->pComponentPrivate; + if (PORT_IS_TUNNELED(openmaxStandPort) && (PORT_IS_BEING_DISABLED(openmaxStandPort) || (omx_base_component_Private->transientState == OMX_TransStateIdleToLoaded))) + { + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s Scheduled TearDown port=%d PORT_IS_BEING_DISABLED(%d) transientState=%d\n", + __func__, openmaxStandPort->sPortParam.nPortIndex, PORT_IS_BEING_DISABLED(openmaxStandPort), omx_base_component_Private->transientState); + openmaxStandPort->bTunnelTearDown = OMX_TRUE; + } + else { + openmaxStandPort->hTunneledComponent = 0; + openmaxStandPort->nTunneledPort = 0; + openmaxStandPort->nTunnelFlags = 0; + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyUnspecified; + } + return OMX_ErrorNone; + } + + if (openmaxStandPort->sPortParam.eDir == OMX_DirInput) { + /* Get Port Definition of the Tunnelled Component*/ + param.nPortIndex=nTunneledPort; + setHeader(¶m, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + err = OMX_GetParameter(hTunneledComp, OMX_IndexParamPortDefinition, ¶m); + if (err != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"In %s Get Tunneled Port Definition error=0x%08x Line=%d\n",__func__,err,__LINE__); + // compatibility not reached + return OMX_ErrorPortsNotCompatible; + } + + // Negotiate buffer params + param.nBufferCountActual = param.nBufferCountMin > openmaxStandPort->sPortParam.nBufferCountMin ? + param.nBufferCountMin : openmaxStandPort->sPortParam.nBufferCountMin; + openmaxStandPort->sPortParam.nBufferCountActual = param.nBufferCountActual; + + param.nBufferSize = param.nBufferSize > openmaxStandPort->sPortParam.nBufferSize ? + param.nBufferSize : openmaxStandPort->sPortParam.nBufferSize; + openmaxStandPort->sPortParam.nBufferSize = param.nBufferSize; + + err = OMX_SetParameter(hTunneledComp, OMX_IndexParamPortDefinition, ¶m); + if (err != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"In %s Set Tunneled Port Definition error=0x%08x Line=%d\n",__func__,err,__LINE__); + return OMX_ErrorPortsNotCompatible; + } + + openmaxStandPort->nNumTunnelBuffer=param.nBufferCountActual; //nBufferCountMin; + + if(param.eDomain!=openmaxStandPort->sPortParam.eDomain) { + return OMX_ErrorPortsNotCompatible; + } + if(param.eDomain==OMX_PortDomainAudio) { + if(param.format.audio.eEncoding == OMX_AUDIO_CodingMax) { + return OMX_ErrorPortsNotCompatible; + } + } else if(param.eDomain==OMX_PortDomainVideo) { + if(param.format.video.eCompressionFormat == OMX_VIDEO_CodingMax) { + return OMX_ErrorPortsNotCompatible; + } + } else if(param.eDomain==OMX_PortDomainOther) { + if(param.format.other.eFormat == OMX_OTHER_FormatMax) { + return OMX_ErrorPortsNotCompatible; + } + } + + /* Get Buffer Supplier type of the Tunnelled Component*/ + pSupplier.nPortIndex=nTunneledPort; + setHeader(&pSupplier, sizeof(OMX_PARAM_BUFFERSUPPLIERTYPE)); + err = OMX_GetParameter(hTunneledComp, OMX_IndexParamCompBufferSupplier, &pSupplier); + if (err != OMX_ErrorNone) { + // compatibility not reached + DEBUG(DEB_LEV_ERR,"In %s Tunneled Buffer Supplier error=0x%08x Line=%d\n",__func__,err,__LINE__); + return OMX_ErrorPortsNotCompatible; + } else { + DEBUG(DEB_LEV_FULL_SEQ,"Tunneled Port eBufferSupplier=%x\n",pSupplier.eBufferSupplier); + } + + // store the current callbacks, if defined + openmaxStandPort->hTunneledComponent = hTunneledComp; + openmaxStandPort->nTunneledPort = nTunneledPort; + + /*Check for and set proprietary communication flag. + In case a component support Deep Tunneling should set it's tunnel flag to PROPRIETARY_COMMUNICATION_ESTABLISHED */ + /// AND: No proprietary communication + /* + if(PORT_IS_DEEP_TUNNELED(openmaxStandPort)) { + OMX_VENDOR_PROP_TUNNELSETUPTYPE pPropTunnelSetup; + pPropTunnelSetup.nPortIndex = nTunneledPort; + + err = OMX_GetParameter(hTunneledComp, OMX_IndexVendorCompPropTunnelFlags, &pPropTunnelSetup); + if (err != OMX_ErrorNone) { + // compatibility not reached + DEBUG(DEB_LEV_ERR,"In %s Proprietary Tunneled Buffer Supplier nTunneledPort=%d error=0x%08x Line=%d \n", + __func__,(int)pPropTunnelSetup.nPortIndex,err,__LINE__); + openmaxStandPort->nTunnelFlags = 0; + } else { + openmaxStandPort->nTunnelFlags = PROPRIETARY_COMMUNICATION_ESTABLISHED; + } + } else { + openmaxStandPort->nTunnelFlags = 0; + } + */ + openmaxStandPort->nTunnelFlags = 0; + /// AND + + // Negotiation + if (pTunnelSetup->nTunnelFlags & OMX_PORTTUNNELFLAG_READONLY) { + // the buffer provider MUST be the output port provider + /// AND: WRONG!!!! + /* + pTunnelSetup->eSupplier = OMX_BufferSupplyInput; + openmaxStandPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyInput; + */ + DEBUG(DEB_LEV_ERR,"In %s --------------> OMX_PORTTUNNELFLAG_READONLY Line=%d\n",__func__,__LINE__); + pTunnelSetup->eSupplier = OMX_BufferSupplyOutput; + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyOutput; + /// AND + } else { + //if (pTunnelSetup->eSupplier == OMX_BufferSupplyInput) { + // DEBUG(DEB_LEV_ERR,"In %s --------------> OMX_BufferSupplyInput Line=%d\n",__func__,__LINE__); + // openmaxStandPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + // openmaxStandPort->eBufferSupplier=OMX_BufferSupplyInput; + //} else if (pTunnelSetup->eSupplier == OMX_BufferSupplyUnspecified) { + // /// AND TODO: Can be reversed???? + // DEBUG(DEB_LEV_ERR,"In %s --------------> OMX_BufferSupplyUnspecified Line=%d\n",__func__,__LINE__); + // pTunnelSetup->eSupplier = OMX_BufferSupplyInput; + // openmaxStandPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + // openmaxStandPort->eBufferSupplier=OMX_BufferSupplyInput; + // //pTunnelSetup->eSupplier = OMX_BufferSupplyOutput; + // //openmaxStandPort->eBufferSupplier=OMX_BufferSupplyOutput; + // /// AND + //} else if (pTunnelSetup->eSupplier == OMX_BufferSupplyOutput){ + // DEBUG(DEB_LEV_ERR,"In %s --------------> OMX_BufferSupplyOutput Line=%d\n",__func__,__LINE__); + // pTunnelSetup->eSupplier = OMX_BufferSupplyOutput; + // openmaxStandPort->eBufferSupplier=OMX_BufferSupplyOutput; + //} else { + // DEBUG(DEB_LEV_ERR,"In %s --------------> undefined pTunnelSetup->eSupplier = %d Line=%d\n",__func__,(int)pTunnelSetup->eSupplier,__LINE__); + //} + + // fixed to work only in this direction + DEBUG(DEB_LEV_ERR,"In %s --------------> OMX_BufferSupply Line=%d\n",__func__,__LINE__); + pTunnelSetup->eSupplier = OMX_BufferSupplyInput; + openmaxStandPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyInput; + /// AND + + } + openmaxStandPort->nTunnelFlags |= TUNNEL_ESTABLISHED; + + /* Set Buffer Supplier type of the Tunnelled Component after final negotiation*/ + pSupplier.nPortIndex=nTunneledPort; + pSupplier.eBufferSupplier=openmaxStandPort->eBufferSupplier; + err = OMX_SetParameter(hTunneledComp, OMX_IndexParamCompBufferSupplier, &pSupplier); + if (err != OMX_ErrorNone) { + // compatibility not reached + DEBUG(DEB_LEV_ERR,"In %s Tunneled Buffer Supplier error=0x%08x Line=%d\n",__func__,err,__LINE__); + openmaxStandPort->nTunnelFlags=0; + return OMX_ErrorPortsNotCompatible; + } + } else { + // output port + // all the consistency checks are under other component responsibility + + /* Get Port Definition of the Tunnelled Component*/ + param.nPortIndex=nTunneledPort; + setHeader(¶m, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + err = OMX_GetParameter(hTunneledComp, OMX_IndexParamPortDefinition, ¶m); + if (err != OMX_ErrorNone) { + DEBUG(DEB_LEV_ERR,"In %s Tunneled Port Definition error=0x%08x Line=%d\n",__func__,err,__LINE__); + // compatibility not reached + return OMX_ErrorPortsNotCompatible; + } + if(param.eDomain!=openmaxStandPort->sPortParam.eDomain) { + return OMX_ErrorPortsNotCompatible; + } + + if(param.eDomain==OMX_PortDomainAudio) { + if(param.format.audio.eEncoding == OMX_AUDIO_CodingMax) { + return OMX_ErrorPortsNotCompatible; + } + } else if(param.eDomain==OMX_PortDomainVideo) { + if(param.format.video.eCompressionFormat == OMX_VIDEO_CodingMax) { + return OMX_ErrorPortsNotCompatible; + } + } else if(param.eDomain==OMX_PortDomainOther) { + if(param.format.other.eFormat == OMX_OTHER_FormatMax) { + return OMX_ErrorPortsNotCompatible; + } + } + + /*Check for and set proprietary communication flag*/ + if(PORT_IS_DEEP_TUNNELED(openmaxStandPort)) { + OMX_VENDOR_PROP_TUNNELSETUPTYPE pPropTunnelSetup; + pPropTunnelSetup.nPortIndex = nTunneledPort; + + err = OMX_GetParameter(hTunneledComp, (OMX_INDEXTYPE)OMX_IndexVendorCompPropTunnelFlags, &pPropTunnelSetup); + if (err != OMX_ErrorNone) { + // compatibility not reached + DEBUG(DEB_LEV_ERR,"In %s Proprietary Tunneled Buffer Supplier nTunneledPort=%d error=0x%08x Line=%d \n", + __func__,(int)pPropTunnelSetup.nPortIndex,err,__LINE__); + openmaxStandPort->nTunnelFlags = 0; + } else { + openmaxStandPort->nTunnelFlags = PROPRIETARY_COMMUNICATION_ESTABLISHED; + } + } else { + openmaxStandPort->nTunnelFlags = 0; + } + + openmaxStandPort->nNumTunnelBuffer=param.nBufferCountMin; + + openmaxStandPort->hTunneledComponent = hTunneledComp; + openmaxStandPort->nTunneledPort = nTunneledPort; + pTunnelSetup->eSupplier = OMX_BufferSupplyOutput; + openmaxStandPort->nTunnelFlags |= TUNNEL_IS_SUPPLIER; + openmaxStandPort->nTunnelFlags |= TUNNEL_ESTABLISHED; + + openmaxStandPort->eBufferSupplier=OMX_BufferSupplyOutput; + } + + return OMX_ErrorNone; +} diff --git a/alsa/omx_base_port.h b/alsa/omx_base_port.h new file mode 100644 index 0000000..3159b92 --- /dev/null +++ b/alsa/omx_base_port.h @@ -0,0 +1,288 @@ +/** + @file src/base/omx_base_port.h + + Base class for OpenMAX ports to be used in derived components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-08-08 06:56:06 +0200 (Fri, 08 Aug 2008) $ + Revision $Rev: 581 $ + Author $Author: pankaj_sen $ + +*/ + +#include "omx_comp_debug_levels.h" + +#include "omx_semaphore.h" +#include "omx_queue.h" +#include "omx_classmagic.h" +#pragma pack(4) +//#include +#include +#include +#include +#pragma pack() + +#define OMX_ErrorIncorrectStateTransition OMX_ErrorIncorrectStateOperation + +#ifndef __OMX_BASE_PORT_H__ +#define __OMX_BASE_PORT_H__ + +#define TUNNEL_USE_BUFFER_RETRY 20 +#define TUNNEL_USE_BUFFER_RETRY_USLEEP_TIME 5000 +#define NO_GST_OMX_PATCH 1 + +/** + * Port Specific Macro's + */ +#define PORT_IS_BEING_FLUSHED(pPort) (pPort->bIsPortFlushed == OMX_TRUE) +#define PORT_IS_BEING_DISABLED(pPort) (pPort->bIsTransientToDisabled == OMX_TRUE) +#define PORT_IS_ENABLED(pPort) (pPort->sPortParam.bEnabled == OMX_TRUE) +#define PORT_IS_POPULATED(pPort) (pPort->sPortParam.bPopulated == OMX_TRUE) +#define PORT_IS_TUNNELED(pPort) (pPort->nTunnelFlags & TUNNEL_ESTABLISHED) +#define PORT_IS_DEEP_TUNNELED(pPort) (pPort->nTunnelFlags & PROPRIETARY_COMMUNICATION_ESTABLISHED) +#define PORT_IS_BUFFER_SUPPLIER(pPort) (pPort->nTunnelFlags & TUNNEL_IS_SUPPLIER) +#define PORT_IS_TUNNELED_N_BUFFER_SUPPLIER(pPort) ((pPort->nTunnelFlags & TUNNEL_ESTABLISHED) && (pPort->nTunnelFlags & TUNNEL_IS_SUPPLIER)) + +/** The following enum values are used to characterize each buffer + * allocated or assigned to the component. A buffer list is + * created for each port of the component. The buffer can be assigned + * to the port, or owned by the port. The buffer flag are applied for each buffer + * in each port buffer list. The following use cases are currently implemented: + * - When the IL Client asks the component to allocate a buffer + * for a given port, with the call to AllocateBuffer, the + * buffer created is characterizeed by the flag BUFFER_ALLOCATED + * - When the IL Client asks the component to use a buffer allocated + * by the client itself, the buffer flag is BUFFER_ASSIGNED + * - When the component is tunneled by another component, and the first + * is supplier of the buffer, the buffer is marked with the + * BUFFER_ALLOCATED flag. + * - When the component is tunneled by another component, and the second + * is supplier of the buffer, the buffer is marked with the + * BUFFER_ASSIGNED flag. + * - The case of a buffer supplied by the first component but allocated by another + * component or another port inside the same component, as in the case + * of shared buffers, is not yet implemented in these components + * - During hte deallocation phase each buffer is marked with the BUFFER_FREE + * flag, so that the component can check if all the buffers have been deallocated + * before switch the component state to Loaded, as specified by + * the OpenMAX specs + */ +typedef unsigned int BUFFER_STATUS_FLAG; + +#define BUFFER_FREE 0 +#define BUFFER_ALLOCATED 0x0001 /**< This flag is applied to a buffer when it is allocated + by the given port of the component */ +#define BUFFER_ASSIGNED 0x0002 /**< This flag is applied to a buffer when it is assigned + from another port or by the IL client */ +#define HEADER_ALLOCATED 0x0004 /**< This flag is applied to a buffer when buffer header is allocated + by the given port of the component */ + +/** @brief the status of a port related to the tunneling with another component + */ +typedef unsigned int TUNNEL_STATUS_FLAG; +#define NO_TUNNEL 0 /**< No tunnel established */ +#define TUNNEL_ESTABLISHED 0x0001 /**< the TUNNEL_ESTABLISHED specifies if a port is tunneled. + * It is assigned to a private field of the port if it is tunneled + */ +#define TUNNEL_IS_SUPPLIER 0x0002 /**< the TUNNEL_IS_SUPPLIER specifies if a tunneled port is the supplier. + * It is assigned to a private field of the port if it is tunneled and also it is the buffer supplier for the tunnel. + */ +#define PROPRIETARY_COMMUNICATION_ESTABLISHED 0x0004 /** The tunnel established is created between two components of the same + * vendor. These components can take advantage from a vendor specific + * communication + */ + +/** + * @brief the base structure that describes each port. + * + * The data structure that describes a port contains the basic elements used in the + * base component. Other elements can be added in the derived components structures. + */ +CLASS(omx_base_PortType) +#define omx_base_PortType_FIELDS \ + OMX_HANDLETYPE hTunneledComponent; /**< @param hTunneledComponent Handle to the tunnelled component */\ + OMX_U32 nTunnelFlags; /**< This field contains one or more tags that describe the tunnel status of the port */\ + OMX_U32 nTunneledPort; /**< @param nTunneledPort Tunneled port number */ \ + OMX_BOOL bTunnelTearDown; /**< @param nTunneledPort Helper for assinc TearDown */ \ + OMX_BUFFERSUPPLIERTYPE eBufferSupplier; /**< @param eBufferSupplier the type of supplier in case of tunneling */\ + OMX_U32 nNumTunnelBuffer; /**< @param nNumTunnelBuffer Number of buffer to be tunnelled */\ + omx_tsem_t* pAllocSem; /**< @param pFlushSem Semaphore that locks the execution until the buffers have been flushed, if needed */ \ + OMX_U32 nNumBufferFlushed; /**< @param nNumBufferFlushed Number of buffer Flushed */\ + OMX_BOOL bIsPortFlushed;/**< @param bIsPortFlushed Boolean variables indicate port is being flushed at the moment */ \ + omx_queue_t* pBufferQueue; /**< @param pBufferQueue queue for buffer to be processed by the port */\ + omx_tsem_t* pBufferSem; /**< @param pBufferSem Semaphore for buffer queue access synchronization */\ + OMX_U32 nNumAssignedBuffers; /**< @param nNumAssignedBuffers Number of buffer assigned on each port */\ + OMX_PARAM_PORTDEFINITIONTYPE sPortParam; /**< @param sPortParam General OpenMAX port parameter */\ + OMX_BUFFERHEADERTYPE **pInternalBufferStorage; /**< This array contains the reference to all the buffers hadled by this port and already registered*/\ + BUFFER_STATUS_FLAG *bBufferStateAllocated; /**< @param bBufferStateAllocated The State of the Buffer whether assigned or allocated */\ + OMX_COMPONENTTYPE *standCompContainer;/**< The OpenMAX component reference that contains this port */\ + OMX_BOOL bIsTransientToEnabled;/**< It indicates that the port is going from disabled to enabled */ \ + OMX_BOOL bIsTransientToDisabled;/**< It indicates that the port is going from enabled to disabled */ \ + OMX_BOOL bIsFullOfBuffers; /**< It indicates if the port has all the buffers needed */ \ + OMX_BOOL bIsEmptyOfBuffers;/**< It indicates if the port has no buffers*/ \ + OMX_ERRORTYPE (*PortConstructor)(OMX_COMPONENTTYPE *openmaxStandComp,omx_base_PortType **openmaxStandPort,OMX_U32 nPortIndex, OMX_BOOL isInput); /**< The contructor of the port. It fills all the other function pointers */ \ + OMX_ERRORTYPE (*PortDestructor)(omx_base_PortType *openmaxStandPort); /**< The destructor of the port*/ \ + OMX_ERRORTYPE (*Port_DisablePort)(omx_base_PortType *openmaxStandPort); /**< Disables the port */ \ + OMX_ERRORTYPE (*Port_EnablePort)(omx_base_PortType *openmaxStandPort); /**< Enables the port */ \ + OMX_ERRORTYPE (*Port_SendBufferFunction)(omx_base_PortType *openmaxStandPort, OMX_BUFFERHEADERTYPE* pBuffer); /**< Holds the EmptyThisBuffer of FillThisBuffer function, if the port is input or output */ \ + OMX_ERRORTYPE (*Port_AllocateBuffer)(omx_base_PortType *openmaxStandPort,OMX_INOUT OMX_BUFFERHEADERTYPE** pBuffer,OMX_IN OMX_U32 nPortIndex,OMX_IN OMX_PTR pAppPrivate,OMX_IN OMX_U32 nSizeBytes);/**< Replaces the AllocateBuffer call for the base port. */ \ + OMX_ERRORTYPE (*Port_UseBuffer)(omx_base_PortType *openmaxStandPort,OMX_BUFFERHEADERTYPE** ppBufferHdr,OMX_U32 nPortIndex,OMX_PTR pAppPrivate,OMX_U32 nSizeBytes,OMX_U8* pBuffer);/**< The standard use buffer function applied to the port class */ \ + OMX_ERRORTYPE (*Port_FreeBuffer)(omx_base_PortType *openmaxStandPort,OMX_U32 nPortIndex,OMX_BUFFERHEADERTYPE* pBuffer); /**< The standard free buffer function applied to the port class */ \ + OMX_ERRORTYPE (*Port_AllocateTunnelBuffer)(omx_base_PortType *openmaxStandPort,OMX_IN OMX_U32 nPortIndex,OMX_IN OMX_U32 nSizeBytes);/**< AllocateTunnelBuffer call for the base port. */ \ + OMX_ERRORTYPE (*Port_FreeTunnelBuffer)(omx_base_PortType *openmaxStandPort,OMX_U32 nPortIndex); /**< The free buffer function used to free tunnelled buffers */ \ + OMX_ERRORTYPE (*BufferProcessedCallback)(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);/**< Holds the EmptyBufferDone or FillBufferDone callback, if the port is input or output port */ \ + OMX_ERRORTYPE (*FlushProcessingBuffers)(omx_base_PortType *openmaxStandPort); /**< release all the buffers currently under processing */ \ + OMX_ERRORTYPE (*ReturnBufferFunction)(omx_base_PortType* openmaxStandPort,OMX_BUFFERHEADERTYPE* pBuffer); /**< Call appropriate function to return buffers to peer or IL Client*/ \ + OMX_ERRORTYPE (*ComponentTunnelRequest)(omx_base_PortType* openmaxStandPort,OMX_IN OMX_HANDLETYPE hTunneledComp,OMX_IN OMX_U32 nTunneledPort,OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup); /**< Setup tunnel with the port */ +ENDCLASS(omx_base_PortType) + +/** + * @brief The base contructor for the generic OpenMAX ST port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of constructing the instance of the port and + * every object needed by the base port. + * + * @param openmaxStandPort the ST port to be initialized + * + * @return OMX_ErrorInsufficientResources if a memory allocation fails + */ +OMX_ERRORTYPE base_port_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,omx_base_PortType **openmaxStandPort,OMX_U32 nPortIndex, OMX_BOOL isInput); + +/** @brief The base destructor for the generic OpenMAX ST port + * + * This function is executed by the component that uses a port. + * The parameter contains the info about the component. + * It takes care of destructing the instance of the port and + * every object used by the base port. + * + * @param openmaxStandPort the ST port to be disposed + */ +OMX_ERRORTYPE base_port_Destructor(omx_base_PortType *openmaxStandPort); + +/** @brief Disables the port. + * + * This function is called due to a request by the IL client + * + * @param openmaxStandPort the reference to the port + * + */ +OMX_ERRORTYPE base_port_DisablePort(omx_base_PortType *openmaxStandPort); + +/** @brief Enables the port. + * + * This function is called due to a request by the IL client + * + * @param openmaxStandPort the reference to the port + * + */ +OMX_ERRORTYPE base_port_EnablePort(omx_base_PortType *openmaxStandPort); + +/** @brief The entry point for sending buffers to the port + * + * This function can be called by the EmptyThisBuffer or FillThisBuffer. It depends on + * the nature of the port, that can be an input or output port. + */ +OMX_ERRORTYPE base_port_SendBufferFunction( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer); + +/** @brief Called by the standard allocate buffer, it implements a base functionality. + * + * This function can be overriden if the allocation of the buffer is not a simply malloc call. + * The parameters are the same as the standard function, except for the handle of the port + * instead of the handler of the component + * When the buffers needed by this port are all assigned or allocated, the variable + * bIsFullOfBuffers becomes equal to OMX_TRUE + */ +OMX_ERRORTYPE base_port_AllocateBuffer( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE** pBuffer, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes); + +/** @brief Called by the standard use buffer, it implements a base functionality. + * + * This function can be overriden if the use buffer implicate more complicated operations. + * The parameters are the same as the standard function, except for the handle of the port + * instead of the handler of the component + * When the buffers needed by this port are all assigned or allocated, the variable + * bIsFullOfBuffers becomes equal to OMX_TRUE + */ +OMX_ERRORTYPE base_port_UseBuffer( + omx_base_PortType *openmaxStandPort, + OMX_BUFFERHEADERTYPE** ppBufferHdr, + OMX_U32 nPortIndex, + OMX_PTR pAppPrivate, + OMX_U32 nSizeBytes, + OMX_U8* pBuffer); + +/** @brief Called by the standard function. + * + * It frees the buffer header and in case also the buffer itself, if needed. + * When all the bufers are done, the variable bIsEmptyOfBuffers is set to OMX_TRUE + */ +OMX_ERRORTYPE base_port_FreeBuffer( + omx_base_PortType *openmaxStandPort, + OMX_U32 nPortIndex, + OMX_BUFFERHEADERTYPE* pBuffer); + +/** @brief Releases buffers under processing. + * + * This function must be implemented in the derived classes, for the + * specific processing + */ +OMX_ERRORTYPE base_port_FlushProcessingBuffers(omx_base_PortType *openmaxStandPort); + +/** @brief Returns buffers when processed. + * + * Call appropriate function to return buffers to peer or IL Client + */ + +OMX_ERRORTYPE base_port_ReturnBufferFunction( + omx_base_PortType* openmaxStandPort, + OMX_BUFFERHEADERTYPE* pBuffer); + +/** @brief Setup Tunnel with the port + */ + +OMX_ERRORTYPE base_port_ComponentTunnelRequest( + omx_base_PortType* openmaxStandPort, + OMX_IN OMX_HANDLETYPE hTunneledComp, + OMX_IN OMX_U32 nTunneledPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup); + +/** @brief Allocate Buffers for tunneling use + */ +OMX_ERRORTYPE base_port_AllocateTunnelBuffer( + omx_base_PortType *openmaxStandPort, + OMX_IN OMX_U32 nPortIndex, + OMX_IN OMX_U32 nSizeBytes); + +/** @brief Free buffers used in tunnel + */ +OMX_ERRORTYPE base_port_FreeTunnelBuffer( + omx_base_PortType *openmaxStandPort, + OMX_U32 nPortIndex); + + +#endif diff --git a/alsa/omx_base_sink.cpp b/alsa/omx_base_sink.cpp new file mode 100644 index 0000000..ae8b3e3 --- /dev/null +++ b/alsa/omx_base_sink.cpp @@ -0,0 +1,189 @@ +/** + @file src/base/omx_base_sink.c + + OpenMAX base sink component. This component does not perform any multimedia + processing. It derives from base component and contains a single input port. + It can be used as base class for sink components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-09-12 08:12:11 +0200 (Fri, 12 Sep 2008) $ + Revision $Rev: 615 $ + Author $Author: pankaj_sen $ +*/ + +#include + +OMX_ERRORTYPE omx_base_sink_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName) { + OMX_ERRORTYPE err = OMX_ErrorNone; + omx_base_sink_PrivateType* omx_base_sink_Private; + + if (openmaxStandComp->pComponentPrivate) { + omx_base_sink_Private = (omx_base_sink_PrivateType*)openmaxStandComp->pComponentPrivate; + } else { + omx_base_sink_Private = (omx_base_sink_PrivateType*)calloc(1,sizeof(omx_base_sink_PrivateType)); + if (!omx_base_sink_Private) { + return OMX_ErrorInsufficientResources; + } + } + + // we could create our own port structures here + // fixme maybe the base class could use a "port factory" function pointer? + err = omx_base_component_Constructor(openmaxStandComp,cComponentName); + + /* here we can override whatever defaults the base_component constructor set + * e.g. we can override the function pointers in the private struct */ + omx_base_sink_Private = (omx_base_sink_PrivateType*)openmaxStandComp->pComponentPrivate; + + omx_base_sink_Private->BufferMgmtFunction = omx_base_sink_BufferMgmtFunction; + + return err; +} + +OMX_ERRORTYPE omx_base_sink_Destructor(OMX_COMPONENTTYPE *openmaxStandComp) +{ + return omx_base_component_Destructor(openmaxStandComp); +} + +/** This is the central function for component processing. It + * is executed in a separate thread, is synchronized with + * semaphores at each port, those are released each time a new buffer + * is available on the given port. + */ +void* omx_base_sink_BufferMgmtFunction (void* param) { + OMX_COMPONENTTYPE* openmaxStandComp = (OMX_COMPONENTTYPE*)param; + omx_base_component_PrivateType* omx_base_component_Private = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate; + omx_base_sink_PrivateType* omx_base_sink_Private = (omx_base_sink_PrivateType*)omx_base_component_Private; + omx_base_PortType *pInPort = (omx_base_PortType *)omx_base_sink_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; + omx_tsem_t* pInputSem = pInPort->pBufferSem; + omx_queue_t* pInputQueue = pInPort->pBufferQueue; + OMX_BUFFERHEADERTYPE* pInputBuffer = NULL; + OMX_COMPONENTTYPE* target_component; + OMX_BOOL isInputBufferNeeded = OMX_TRUE; + int inBufExchanged = 0; + + DEBUG(DEB_LEV_FUNCTION_NAME, "In %s \n", __func__); + while(omx_base_component_Private->state == OMX_StateIdle || + omx_base_component_Private->state == OMX_StateExecuting || + omx_base_component_Private->state == OMX_StatePause || + omx_base_component_Private->transientState == OMX_TransStateLoadedToIdle){ + + /*Wait till the ports are being flushed*/ + pthread_mutex_lock(&omx_base_sink_Private->flush_mutex); + while( PORT_IS_BEING_FLUSHED(pInPort)) { + pthread_mutex_unlock(&omx_base_sink_Private->flush_mutex); + + if(isInputBufferNeeded==OMX_FALSE) { + pInPort->ReturnBufferFunction(pInPort,pInputBuffer); + inBufExchanged--; + pInputBuffer=NULL; + isInputBufferNeeded=OMX_TRUE; + DEBUG(DEB_LEV_FULL_SEQ, "Ports are flushing,so returning input buffer\n"); + } + DEBUG(DEB_LEV_FULL_SEQ, "In %s signalling flush all condition \n", __func__); + + omx_tsem_up(omx_base_sink_Private->flush_all_condition); + omx_tsem_down(omx_base_sink_Private->flush_condition); + pthread_mutex_lock(&omx_base_sink_Private->flush_mutex); + } + pthread_mutex_unlock(&omx_base_sink_Private->flush_mutex); + + /*No buffer to process. So wait here*/ + if((pInputSem->semval==0 && isInputBufferNeeded==OMX_TRUE ) && + (omx_base_sink_Private->state != OMX_StateLoaded && omx_base_sink_Private->state != OMX_StateInvalid)) { + DEBUG(DEB_LEV_SIMPLE_SEQ, "Waiting for input buffer \n"); + omx_tsem_down(omx_base_sink_Private->bMgmtSem); + } + + if(omx_base_sink_Private->state == OMX_StateLoaded || omx_base_sink_Private->state == OMX_StateInvalid) { + DEBUG(DEB_LEV_FULL_SEQ, "In %s Buffer Management Thread is exiting\n",__func__); + break; + } + + DEBUG(DEB_LEV_SIMPLE_SEQ, "Waiting for input buffer semval=%d \n",pInputSem->semval); + if(pInputSem->semval>0 && isInputBufferNeeded==OMX_TRUE ) { + omx_tsem_down(pInputSem); + if(pInputQueue->nelem>0){ + inBufExchanged++; + isInputBufferNeeded=OMX_FALSE; + pInputBuffer = (OMX_BUFFERHEADERTYPE*)omx_dequeue(pInputQueue); + if(pInputBuffer == NULL){ + DEBUG(DEB_LEV_ERR, "Had NULL input buffer!!\n"); + break; + } + } + } + + if(isInputBufferNeeded==OMX_FALSE) { + if(pInputBuffer->nFlags==OMX_BUFFERFLAG_EOS) { + DEBUG(DEB_LEV_SIMPLE_SEQ, "Detected EOS flags in input buffer\n"); + + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventBufferFlag, /* The command was completed */ + 0, /* The commands was a OMX_CommandStateSet */ + pInputBuffer->nFlags, /* The state has been changed in message->messageParam2 */ + NULL); + pInputBuffer->nFlags=0; + } + + target_component=(OMX_COMPONENTTYPE*)pInputBuffer->hMarkTargetComponent; + if(target_component==(OMX_COMPONENTTYPE *)openmaxStandComp) { + /*Clear the mark and generate an event*/ + (*(omx_base_component_Private->callbacks->EventHandler)) + (openmaxStandComp, + omx_base_component_Private->callbackData, + OMX_EventMark, /* The command was completed */ + 1, /* The commands was a OMX_CommandStateSet */ + 0, /* The state has been changed in message->messageParam2 */ + pInputBuffer->pMarkData); + } else if(pInputBuffer->hMarkTargetComponent!=NULL){ + /*If this is not the target component then pass the mark*/ + DEBUG(DEB_LEV_FULL_SEQ, "Can't Pass Mark. This is a Sink!!\n"); + } + if (omx_base_sink_Private->BufferMgmtCallback && pInputBuffer->nFilledLen > 0) { + (*(omx_base_sink_Private->BufferMgmtCallback))(openmaxStandComp, pInputBuffer); + } + else { + /*If no buffer management call back the explicitly consume input buffer*/ + DEBUG(DEB_LEV_FULL_SEQ, "If no buffer management call back, explicitly consume input buffer. nInputPortIndex=%d BufferMgmtCallback=0x%p nFilledLen=%d\n", + (int)pInputBuffer->nInputPortIndex, omx_base_sink_Private->BufferMgmtCallback, (int)pInputBuffer->nFilledLen); + pInputBuffer->nFilledLen = 0; + } + /*Input Buffer has been completely consumed. So, get new input buffer*/ + + if(omx_base_sink_Private->state==OMX_StatePause && !PORT_IS_BEING_FLUSHED(pInPort)) { + /*Waiting at paused state*/ + omx_tsem_wait(omx_base_sink_Private->bStateSem); + } + + /*Input Buffer has been completely consumed. So, return input buffer*/ + if(pInputBuffer->nFilledLen==0) { + pInPort->ReturnBufferFunction(pInPort,pInputBuffer); + inBufExchanged--; + pInputBuffer=NULL; + isInputBufferNeeded = OMX_TRUE; + } + + } + } + DEBUG(DEB_LEV_SIMPLE_SEQ,"Exiting Buffer Management Thread\n"); + return NULL; +} diff --git a/alsa/omx_base_sink.h b/alsa/omx_base_sink.h new file mode 100644 index 0000000..dfe7e9c --- /dev/null +++ b/alsa/omx_base_sink.h @@ -0,0 +1,73 @@ +/** + @file src/base/omx_base_sink.h + + OpenMAX base sink component. This component does not perform any multimedia + processing. It derives from base component and contains a single port. It can be used + as base class for sink components. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-08-28 17:50:08 +0200 (Thu, 28 Aug 2008) $ + Revision $Rev: 583 $ + Author $Author: gsent $ + +*/ + +#ifndef _OMX_BASE_SINK_COMPONENT_H_ +#define _OMX_BASE_SINK_COMPONENT_H_ + +//#include +//#include +//#include +#include +#include "omx_base_component.h" +#include + + +#define OMX_BASE_SINK_INPUTPORT_INDEX 0 /* The index of the input port for the derived components */ +#define OMX_BASE_SINK_CLOCKPORT_INDEX 1 /* The index of the clock port for the dervied components */ + +/** OMX_BASE_SINK_ALLPORT_INDEX as the standard specifies, the -1 value for port index is used to point to all the ports + */ +#define OMX_BASE_SINK_ALLPORT_INDEX -1 + +/** base sink component private structure. + */ +DERIVEDCLASS(omx_base_sink_PrivateType, omx_base_component_PrivateType) +#define omx_base_sink_PrivateType_FIELDS omx_base_component_PrivateType_FIELDS \ + /** @param BufferMgmtCallback function pointer for algorithm callback */ \ + void (*BufferMgmtCallback)(OMX_COMPONENTTYPE* openmaxStandComp, OMX_BUFFERHEADERTYPE* inputbuffer); +ENDCLASS(omx_base_sink_PrivateType) + +/** Base sink contructor + */ +OMX_ERRORTYPE omx_base_sink_Constructor(OMX_COMPONENTTYPE *openmaxStandComp,OMX_STRING cComponentName); + +/** The base sink destructor. It simply calls the base destructor + */ +OMX_ERRORTYPE omx_base_sink_Destructor(OMX_COMPONENTTYPE *openmaxStandComp); + +/** This is the central function for component processing. It + * is executed in a separate thread, is synchronized with + * semaphores at each port, those are released each time a new buffer + * is available on the given port. + */ +void* omx_base_sink_BufferMgmtFunction(void* param); + +#endif diff --git a/alsa/omx_classmagic.h b/alsa/omx_classmagic.h new file mode 100644 index 0000000..2560041 --- /dev/null +++ b/alsa/omx_classmagic.h @@ -0,0 +1,100 @@ +/** + @file src/base/omx_classmagic.h + + This file contains class handling helper macros + It is left as an exercise to the reader how they do the magic (FIXME) + + Usage Rules: + 1) include this file + 2) if your don't inherit, start your class with CLASS(classname) + 3) if you inherit something, start your class with + DERIVEDCLASS(classname, inheritedclassname) + 4) end your class with ENDCLASS(classname) + 5) define your class variables with a #define classname_FIELDS inheritedclassname_FIELDS + inside your class and always add a backslash at the end of line (except last) + 6) if you want to use doxygen, use C-style comments inside the #define, and + enable macro expansion in doxyconf and predefine DOXYGEN_PREPROCESSING there, etc. + + See examples at the end of this file (in #if 0 block) + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $ + Revision $Rev: 554 $ + Author $Author: pankaj_sen $ + +*/ +#ifndef OMX_CLASSMAGIC_H_ +#define OMX_CLASSMAGIC_H_ + + +#ifdef DOXYGEN_PREPROCESSING +#define CLASS(a) class a { public: +#define DERIVEDCLASS(a, b) class a : public b { public: +#define ENDCLASS(a) a##_FIELDS }; +#else +#define CLASS(a) typedef struct a a; \ + struct a { +#define DERIVEDCLASS(a, b) typedef struct a a; \ + struct a { +#define ENDCLASS(a) a##_FIELDS }; +#endif + +#if 0 /*EXAMPLES*/ +/** + * Class A is a nice class + */ +CLASS(A) +#define A_FIELDS \ +/** @param a very nice parameter */ \ + int a; \ +/** @param ash another very nice parameter */ \ + int ash; +ENDCLASS(A) + +/** + * Class B is a nice derived class + */ +DERIVEDCLASS(B,A) +#define B_FIELDS A_FIELDS \ +/** @param b very nice parameter */ \ + int b; +ENDCLASS(B) + +/** + * Class B2 is a nice derived class + */ +DERIVEDCLASS(B2,A) +#define B2_FIELDS A_FIELDS \ +/** @param b2 very nice parameter */ \ + int b2; +ENDCLASS(B2) + +/** + * Class C is an even nicer derived class. + */ +DERIVEDCLASS(C,B) +#define C_FIELDS B_FIELDS \ +/** @param c very nice parameter */ \ + int c; +ENDCLASS(C) + +#endif /* 0 */ + +#endif diff --git a/alsa/omx_comp_debug_levels.h b/alsa/omx_comp_debug_levels.h new file mode 100644 index 0000000..dda6a79 --- /dev/null +++ b/alsa/omx_comp_debug_levels.h @@ -0,0 +1,77 @@ +/** + @file src/omx_comp_debug_levels.h + + Define the level of debug prints on standard err. The different levels can + be composed with binary OR. + The debug levels defined here belong to OpenMAX components and IL core + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-07-16 09:39:31 +0200 (Wed, 16 Jul 2008) $ + Revision $Rev: 577 $ + Author $Author: gsent $ + +*/ + +#ifndef __OMX_COMP_DEBUG_LEVELS_H__ +#define __OMX_COMP_DEBUG_LEVELS_H__ + +#include + +/** Remove all debug output lines + */ +#define DEB_LEV_NO_OUTPUT 0 + +/** Messages explaing the reason of critical errors + */ +#define DEB_LEV_ERR 1 + +/** Messages showing values related to the test and the component/s used + */ +#define DEB_LEV_PARAMS 2 + +/** Messages representing steps in the execution. These are the simple messages, because + * they avoid iterations + */ +#define DEB_LEV_SIMPLE_SEQ 4 + +/** Messages representing steps in the execution. All the steps are described, + * also with iterations. With this level of output the performances are + * seriously compromised + */ +#define DEB_LEV_FULL_SEQ 8 + +/** Messages that indicates the beginning and the end of a function. + * It can be used to trace the execution + */ +#define DEB_LEV_FUNCTION_NAME 16 + +/** All the messages - max value + */ +#define DEB_ALL_MESS 255 + +/** \def DEBUG_LEVEL is the current level do debug output on standard err */ +#define DEBUG_LEVEL (DEB_ALL_MESS) +#if DEBUG_LEVEL > 0 +#define DEBUG(n, fmt, args...) do { if (DEBUG_LEVEL & (n)){fprintf(stdout, "OMX-" fmt, ##args);} } while (0) +#else +#define DEBUG(n, fmt, args...) +#endif + +#endif diff --git a/alsa/omx_loader_XBMC.cpp b/alsa/omx_loader_XBMC.cpp new file mode 100644 index 0000000..5ea1855 --- /dev/null +++ b/alsa/omx_loader_XBMC.cpp @@ -0,0 +1,69 @@ + +#include "omx_loader_XBMC.h" +#include + +OMX_ERRORTYPE OMX_GetHandle_XBMC(OMX_OUT OMX_HANDLETYPE* pHandle, + OMX_IN OMX_STRING cComponentName, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_CALLBACKTYPE* pCallBacks) +{ + OMX_ERRORTYPE err = OMX_ErrorNone; + OMX_COMPONENTTYPE* openmaxStandComp; + omx_base_component_PrivateType* priv; + + if(!strcmp("OMX.XBMC.alsa.alsasink", cComponentName)) + { + openmaxStandComp = (OMX_COMPONENTTYPE*)calloc(1,sizeof(OMX_COMPONENTTYPE)); + if (!openmaxStandComp) { + return OMX_ErrorInsufficientResources; + } + + err = omx_alsasink_component_Constructor(openmaxStandComp,cComponentName); + if (err != OMX_ErrorNone) + { + if (err == OMX_ErrorInsufficientResources) + { + *pHandle = openmaxStandComp; + priv = (omx_base_component_PrivateType *) openmaxStandComp->pComponentPrivate; + return OMX_ErrorInsufficientResources; + } + DEBUG(DEB_LEV_ERR, "Error during component construction\n"); + openmaxStandComp->ComponentDeInit(openmaxStandComp); + free(openmaxStandComp); + openmaxStandComp = NULL; + return OMX_ErrorComponentNotFound; + } + priv = (omx_base_component_PrivateType *) openmaxStandComp->pComponentPrivate; + + *pHandle = openmaxStandComp; + ((OMX_COMPONENTTYPE*)*pHandle)->SetCallbacks(*pHandle, pCallBacks, pAppData); + } + else + { + err = OMX_ErrorComponentNotFound; + } + + return err; +} + + +OMX_ERRORTYPE OMX_FreeHandle_XBMC(OMX_IN OMX_HANDLETYPE hComponent) +{ + int i; + OMX_ERRORTYPE err = OMX_ErrorNone; + omx_base_component_PrivateType * priv = (omx_base_component_PrivateType *) ((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate; + + if(!strcmp("OMX.XBMC.alsa.alsasink", priv->name)) + { + err = ((OMX_COMPONENTTYPE*)hComponent)->ComponentDeInit(hComponent); + + free((OMX_COMPONENTTYPE*)hComponent); + hComponent = NULL; + } + else + { + err = OMX_ErrorComponentNotFound; + } + + return err; +} \ No newline at end of file diff --git a/alsa/omx_loader_XBMC.h b/alsa/omx_loader_XBMC.h new file mode 100644 index 0000000..c835043 --- /dev/null +++ b/alsa/omx_loader_XBMC.h @@ -0,0 +1,27 @@ +#pragma once + + +#ifndef __OMX_LOADER_XBMC__ +#define __OMX_LOADER_XBMC__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#pragma pack(4) +#include +#include +#pragma pack() + +OMX_ERRORTYPE OMX_GetHandle_XBMC(OMX_OUT OMX_HANDLETYPE* pHandle, + OMX_IN OMX_STRING cComponentName, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_CALLBACKTYPE* pCallBacks); + +OMX_ERRORTYPE OMX_FreeHandle_XBMC(OMX_IN OMX_HANDLETYPE hComponent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/alsa/omx_queue.cpp b/alsa/omx_queue.cpp new file mode 100644 index 0000000..e4ecd25 --- /dev/null +++ b/alsa/omx_queue.cpp @@ -0,0 +1,136 @@ +/** + @file src/queue.c + + Implements a simple LIFO structure used for queueing OMX buffers. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $ + Revision $Rev: 554 $ + Author $Author: pankaj_sen $ +*/ + +#include +#include +#include + +#include "omx_queue.h" +#include "omx_comp_debug_levels.h" + +/** Initialize a queue descriptor + * + * @param queue The queue descriptor to initialize. + * The user needs to allocate the queue + */ +void omx_queue_init(omx_queue_t* queue) { + int i; + omx_qelem_t* newelem; + omx_qelem_t* current; + queue->first = (omx_qelem_t*)malloc(sizeof(omx_qelem_t)); + memset(queue->first, 0, sizeof(omx_qelem_t)); + current = queue->last = queue->first; + queue->nelem = 0; + for (i = 0; iq_forw = newelem; + current = newelem; + } + current->q_forw = queue->first; + + pthread_mutex_init(&queue->mutex, NULL); +} + +/** Deinitialize a queue descriptor + * flushing all of its internal data + * + * @param queue the queue descriptor to dump + */ +void omx_queue_deinit(omx_queue_t* queue) { + int i; + omx_qelem_t* current; + current = queue->first; + for (i = 0; iq_forw; + free(queue->first); + queue->first = current; + } + } + if(queue->first) { + free(queue->first); + queue->first = NULL; + } + pthread_mutex_destroy(&queue->mutex); +} + +/** Enqueue an element to the given queue descriptor + * + * @param queue the queue descritpor where to queue data + * + * @param data the data to be enqueued + */ +void omx_queue(omx_queue_t* queue, void* data) { + if (queue->last->data != NULL) { + DEBUG(DEB_LEV_ERR, "In %s ERROR! Full queue\n",__func__); + return; + } + pthread_mutex_lock(&queue->mutex); + queue->last->data = data; + queue->last = queue->last->q_forw; + queue->nelem++; + pthread_mutex_unlock(&queue->mutex); +} + +/** Dequeue an element from the given queue descriptor + * + * @param queue the queue descriptor from which to dequeue the element + * + * @return the element that has bee dequeued. If the queue is empty + * a NULL value is returned + */ +void* omx_dequeue(omx_queue_t* queue) { + void* data; + if (queue->first->data == NULL) { + DEBUG(DEB_LEV_ERR, "In %s ERROR! Empty queue\n",__func__); + return NULL; + } + pthread_mutex_lock(&queue->mutex); + data = queue->first->data; + queue->first->data = NULL; + queue->first = queue->first->q_forw; + queue->nelem--; + pthread_mutex_unlock(&queue->mutex); + + return data; +} + +/** Returns the number of elements hold in the queue + * + * @param queue the requested queue + * + * @return the number of elements in the queue + */ +int omx_getquenelem(omx_queue_t* queue) { + int qelem; + pthread_mutex_lock(&queue->mutex); + qelem = queue->nelem; + pthread_mutex_unlock(&queue->mutex); + return qelem; +} diff --git a/alsa/omx_queue.h b/alsa/omx_queue.h new file mode 100644 index 0000000..bf80f90 --- /dev/null +++ b/alsa/omx_queue.h @@ -0,0 +1,94 @@ +/** + @file src/omx_queue.h + + Implements a simple LIFO structure used for queueing OMX buffers. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $ + Revision $Rev: 554 $ + Author $Author: pankaj_sen $ +*/ + +#pragma once + +#ifndef __OMX_QUEUE_H__ +#define __OMX_QUEUE_H__ + +#include +/** Maximum number of elements in a queue + */ +#define MAX_QUEUE_ELEMENTS 20 +/** Output port queue element. Contains an OMX buffer header type + */ +typedef struct omx_qelem_t omx_qelem_t; +struct omx_qelem_t{ + omx_qelem_t* q_forw; + void* data; +}; + +/** This structure contains the queue + */ +typedef struct omx_queue_t{ + omx_qelem_t* first; /**< Output buffer queue head */ + omx_qelem_t* last; /**< Output buffer queue tail */ + int nelem; /**< Number of elements in the queue */ + pthread_mutex_t mutex; +} omx_queue_t; + +/** Initialize a queue descriptor + * + * @param queue The queue descriptor to initialize. + * The user needs to allocate the queue + */ +void omx_queue_init(omx_queue_t* queue); + +/** Deinitialize a queue descriptor + * flushing all of its internal data + * + * @param queue the queue descriptor to dump + */ +void omx_queue_deinit(omx_queue_t* queue); + +/** Enqueue an element to the given queue descriptor + * + * @param queue the queue descritpor where to queue data + * + * @param data the data to be enqueued + */ +void omx_queue(omx_queue_t* queue, void* data); + +/** Dequeue an element from the given queue descriptor + * + * @param queue the queue descriptor from which to dequeue the element + * + * @return the element that has bee dequeued. If the queue is empty + * a NULL value is returned + */ +void* omx_dequeue(omx_queue_t* queue); + +/** Returns the number of elements hold in the queue + * + * @param queue the requested queue + * + * @return the number of elements in the queue + */ +int omx_getquenelem(omx_queue_t* queue); + +#endif diff --git a/alsa/omx_semaphore.cpp b/alsa/omx_semaphore.cpp new file mode 100644 index 0000000..eca3a0f --- /dev/null +++ b/alsa/omx_semaphore.cpp @@ -0,0 +1,111 @@ +/** + @file src/tsemaphore.c + + Implements a simple inter-thread semaphore so not to have to deal with IPC + creation and the like. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $ + Revision $Rev: 554 $ + Author $Author: pankaj_sen $ +*/ + +#include +#include +#include +#include "omx_semaphore.h" +//#include "omx_comp_debug_levels.h" + +/** Initializes the semaphore at a given value + * + * @param tsem the semaphore to initialize + * @param val the initial value of the semaphore + * + */ +void omx_tsem_init(omx_tsem_t* tsem, unsigned int val) { + pthread_cond_init(&tsem->condition, NULL); + pthread_mutex_init(&tsem->mutex, NULL); + tsem->semval = val; +} + +/** Destroy the semaphore + * + * @param tsem the semaphore to destroy + */ +void omx_tsem_deinit(omx_tsem_t* tsem) { + pthread_cond_destroy(&tsem->condition); + pthread_mutex_destroy(&tsem->mutex); +} + +/** Decreases the value of the semaphore. Blocks if the semaphore + * value is zero. + * + * @param tsem the semaphore to decrease + */ +void omx_tsem_down(omx_tsem_t* tsem) { + pthread_mutex_lock(&tsem->mutex); + while (tsem->semval == 0) { + pthread_cond_wait(&tsem->condition, &tsem->mutex); + } + tsem->semval--; + pthread_mutex_unlock(&tsem->mutex); +} + +/** Increases the value of the semaphore + * + * @param tsem the semaphore to increase + */ +void omx_tsem_up(omx_tsem_t* tsem) { + pthread_mutex_lock(&tsem->mutex); + tsem->semval++; + pthread_cond_signal(&tsem->condition); + pthread_mutex_unlock(&tsem->mutex); +} + +/** Reset the value of the semaphore + * + * @param tsem the semaphore to reset + */ +void omx_tsem_reset(omx_tsem_t* tsem) { + pthread_mutex_lock(&tsem->mutex); + tsem->semval=0; + pthread_mutex_unlock(&tsem->mutex); +} + +/** Wait on the condition. + * + * @param tsem the semaphore to wait + */ +void omx_tsem_wait(omx_tsem_t* tsem) { + pthread_mutex_lock(&tsem->mutex); + pthread_cond_wait(&tsem->condition, &tsem->mutex); + pthread_mutex_unlock(&tsem->mutex); +} + +/** Signal the condition,if waiting + * + * @param tsem the semaphore to signal + */ +void omx_tsem_signal(omx_tsem_t* tsem) { + pthread_mutex_lock(&tsem->mutex); + pthread_cond_signal(&tsem->condition); + pthread_mutex_unlock(&tsem->mutex); +} + diff --git a/alsa/omx_semaphore.h b/alsa/omx_semaphore.h new file mode 100644 index 0000000..1e3f3db --- /dev/null +++ b/alsa/omx_semaphore.h @@ -0,0 +1,92 @@ +/** + @file src/omx_semaphore.h + + Implements a simple inter-thread semaphore so not to have to deal with IPC + creation and the like. + + Copyright (C) 2007-2008 STMicroelectronics + Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). + + This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + + $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $ + Revision $Rev: 554 $ + Author $Author: pankaj_sen $ + +*/ + +#pragma once + +#ifndef __OMX_SEMAPHORE_H__ +#define __OMX_SEMAPHORE_H__ + +#include +#include + +/** The structure contains the semaphore value, mutex and green light flag + */ +typedef struct omx_tsem_t { + pthread_cond_t condition; + pthread_mutex_t mutex; + unsigned int semval; +} omx_tsem_t; + +/** Initializes the semaphore at a given value + * + * @param tsem the semaphore to initialize + * + * @param val the initial value of the semaphore + */ +void omx_tsem_init(omx_tsem_t* tsem, unsigned int val); + +/** Destroy the semaphore + * + * @param tsem the semaphore to destroy + */ +void omx_tsem_deinit(omx_tsem_t* tsem); + +/** Decreases the value of the semaphore. Blocks if the semaphore + * value is zero. + * + * @param tsem the semaphore to decrease + */ +void omx_tsem_down(omx_tsem_t* tsem); + +/** Increases the value of the semaphore + * + * @param tsem the semaphore to increase + */ +void omx_tsem_up(omx_tsem_t* tsem); + +/** Reset the value of the semaphore + * + * @param tsem the semaphore to reset + */ +void omx_tsem_reset(omx_tsem_t* tsem); + +/** Wait on the condition. + * + * @param tsem the semaphore to wait + */ +void omx_tsem_wait(omx_tsem_t* tsem); + +/** Signal the condition,if waiting + * + * @param tsem the semaphore to signal + */ +void omx_tsem_signal(omx_tsem_t* tsem); + +#endif diff --git a/omxplayer.cpp b/omxplayer.cpp index b554a58..3e5b99b 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -699,7 +699,7 @@ int main(int argc, char *argv[]) break; case 'o': m_config_audio.device = optarg; - if(m_config_audio.device != "local" && m_config_audio.device != "hdmi" && m_config_audio.device != "both") + if(m_config_audio.device != "local" && m_config_audio.device != "hdmi" && m_config_audio.device != "both" && m_config_audio.device != "alsa") { print_usage(); return 0;