| /* |
| * portbase.cpp, base port class |
| * |
| * Copyright (c) 2009-2010 Wind River Systems, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <OMX_Core.h> |
| #include <OMX_Component.h> |
| |
| #include <portbase.h> |
| #include <componentbase.h> |
| //#define LOG_NDEBUG 0 |
| |
| #define LOG_TAG "portbase" |
| #include <log.h> |
| |
| /* |
| * constructor & destructor |
| */ |
| void PortBase::__PortBase(void) |
| { |
| buffer_hdrs = NULL; |
| nr_buffer_hdrs = 0; |
| buffer_hdrs_completion = false; |
| |
| custom_mem_alloc = NULL; |
| custom_mem_free = NULL; |
| custom_mem_userdata = NULL; |
| |
| mem_alignment = 0; |
| |
| pthread_mutex_init(&hdrs_lock, NULL); |
| pthread_cond_init(&hdrs_wait, NULL); |
| |
| __queue_init(&bufferq); |
| pthread_mutex_init(&bufferq_lock, NULL); |
| |
| __queue_init(&retainedbufferq); |
| pthread_mutex_init(&retainedbufferq_lock, NULL); |
| |
| __queue_init(&markq); |
| pthread_mutex_init(&markq_lock, NULL); |
| |
| state = OMX_PortEnabled; |
| pthread_mutex_init(&state_lock, NULL); |
| |
| memset(&portdefinition, 0, sizeof(portdefinition)); |
| ComponentBase::SetTypeHeader(&portdefinition, sizeof(portdefinition)); |
| memset(definition_format_mimetype, 0, OMX_MAX_STRINGNAME_SIZE); |
| portdefinition.format.audio.cMIMEType = &definition_format_mimetype[0]; |
| portdefinition.format.video.cMIMEType = &definition_format_mimetype[0]; |
| portdefinition.format.image.cMIMEType = &definition_format_mimetype[0]; |
| |
| memset(&audioparam, 0, sizeof(audioparam)); |
| |
| owner = NULL; |
| appdata = NULL; |
| callbacks = NULL; |
| |
| cbase = NULL; |
| } |
| |
| PortBase::PortBase() |
| { |
| __PortBase(); |
| } |
| |
| PortBase::PortBase(const OMX_PARAM_PORTDEFINITIONTYPE *portdefinition) |
| { |
| __PortBase(); |
| SetPortDefinition(portdefinition, true); |
| } |
| |
| PortBase::~PortBase() |
| { |
| struct list *entry, *temp; |
| |
| /* should've been already freed at FreeBuffer() */ |
| list_foreach_safe(buffer_hdrs, entry, temp) { |
| free(entry->data); /* OMX_BUFFERHEADERTYPE */ |
| __list_delete(buffer_hdrs, entry); |
| } |
| |
| pthread_cond_destroy(&hdrs_wait); |
| pthread_mutex_destroy(&hdrs_lock); |
| |
| /* should've been already freed at buffer processing */ |
| queue_free_all(&bufferq); |
| pthread_mutex_destroy(&bufferq_lock); |
| |
| /* should've been already freed at buffer processing */ |
| queue_free_all(&retainedbufferq); |
| pthread_mutex_destroy(&retainedbufferq_lock); |
| |
| /* should've been already empty in PushThisBuffer () */ |
| queue_free_all(&markq); |
| pthread_mutex_destroy(&markq_lock); |
| |
| pthread_mutex_destroy(&state_lock); |
| } |
| |
| /* end of constructor & destructor */ |
| |
| /* |
| * accessor |
| */ |
| /* owner */ |
| void PortBase::SetOwner(OMX_COMPONENTTYPE *handle) |
| { |
| owner = handle; |
| cbase = static_cast<ComponentBase *>(handle->pComponentPrivate); |
| } |
| |
| OMX_COMPONENTTYPE *PortBase::GetOwner(void) |
| { |
| return owner; |
| } |
| |
| OMX_ERRORTYPE PortBase::SetCallbacks(OMX_HANDLETYPE hComponent, |
| OMX_CALLBACKTYPE *pCallbacks, |
| OMX_PTR pAppData) |
| { |
| if (owner != hComponent) |
| return OMX_ErrorBadParameter; |
| |
| appdata = pAppData; |
| callbacks = pCallbacks; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE PortBase::SetMemAllocator(CustomMemAlloc *pMemAlloc, CustomMemFree *pMemFree, OMX_PTR pUserData) |
| { |
| custom_mem_alloc = pMemAlloc; |
| custom_mem_free = pMemFree; |
| custom_mem_userdata = pUserData; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE PortBase::SetMemAlignment(OMX_U32 nAlignment) |
| { |
| mem_alignment = nAlignment; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_U32 PortBase::getFrameBufSize(OMX_COLOR_FORMATTYPE colorFormat, OMX_U32 width, OMX_U32 height) |
| { |
| switch (colorFormat) { |
| case OMX_COLOR_FormatYCbYCr: |
| case OMX_COLOR_FormatCbYCrY: |
| return width * height * 2; |
| case OMX_COLOR_FormatYUV420Planar: |
| case OMX_COLOR_FormatYUV420SemiPlanar: |
| return (width * height * 3) >> 1; |
| |
| default: |
| LOGV("unsupport color format !"); |
| return -1; |
| } |
| } |
| |
| /* end of accessor */ |
| |
| /* |
| * component methods & helpers |
| */ |
| /* Get/SetParameter */ |
| OMX_ERRORTYPE PortBase::SetPortDefinition( |
| const OMX_PARAM_PORTDEFINITIONTYPE *p, bool overwrite_readonly) |
| { |
| OMX_PARAM_PORTDEFINITIONTYPE temp; |
| |
| memcpy(&temp, &portdefinition, sizeof(temp)); |
| |
| if (!overwrite_readonly) { |
| if (temp.nPortIndex != p->nPortIndex) |
| return OMX_ErrorBadParameter; |
| if (temp.eDir != p->eDir) |
| return OMX_ErrorBadParameter; |
| if (temp.eDomain != p->eDomain) |
| return OMX_ErrorBadParameter; |
| if (temp.nBufferCountActual != p->nBufferCountActual) { |
| if (temp.nBufferCountMin > p->nBufferCountActual) |
| return OMX_ErrorBadParameter; |
| temp.nBufferCountActual = p->nBufferCountActual; |
| } |
| if ((p->nBufferSize > temp.nBufferSize) && (temp.eDir == OMX_DirInput)) { |
| if (p->nBufferSize <= MAX_INPUT_PORT_SIZE) { |
| LOGW("Input port size has been changed!"); |
| temp.nBufferSize = p->nBufferSize; |
| } else { |
| LOGE("Invalid input port size!"); |
| return OMX_ErrorBadParameter; |
| } |
| } |
| } |
| else { |
| temp.nPortIndex = p->nPortIndex; |
| temp.eDir = p->eDir; |
| temp.nBufferCountActual = p->nBufferCountActual; |
| temp.nBufferCountMin = p->nBufferCountMin; |
| temp.nBufferSize = p->nBufferSize; |
| temp.bEnabled = p->bEnabled; |
| temp.bPopulated = p->bPopulated; |
| temp.eDomain = p->eDomain; |
| temp.bBuffersContiguous = p->bBuffersContiguous; |
| temp.nBufferAlignment = p->nBufferAlignment; |
| } |
| |
| switch (p->eDomain) { |
| case OMX_PortDomainAudio: { |
| OMX_AUDIO_PORTDEFINITIONTYPE *format = &temp.format.audio; |
| const OMX_AUDIO_PORTDEFINITIONTYPE *pformat = &p->format.audio; |
| OMX_U32 mimetype_len = strlen(pformat->cMIMEType); |
| |
| mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ? |
| mimetype_len : OMX_MAX_STRINGNAME_SIZE-1; |
| |
| strncpy(format->cMIMEType, pformat->cMIMEType, |
| mimetype_len); |
| format->cMIMEType[mimetype_len+1] = '\0'; |
| format->pNativeRender = pformat->pNativeRender; |
| format->bFlagErrorConcealment = pformat->bFlagErrorConcealment; |
| format->eEncoding = pformat->eEncoding; |
| |
| break; |
| } |
| case OMX_PortDomainVideo: { |
| OMX_VIDEO_PORTDEFINITIONTYPE *format = &temp.format.video; |
| const OMX_VIDEO_PORTDEFINITIONTYPE *pformat = &p->format.video; |
| OMX_U32 mimetype_len = strlen(pformat->cMIMEType); |
| |
| mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ? |
| mimetype_len : OMX_MAX_STRINGNAME_SIZE-1; |
| |
| strncpy(format->cMIMEType, pformat->cMIMEType, |
| mimetype_len); |
| format->cMIMEType[mimetype_len+1] = '\0'; |
| format->pNativeRender = pformat->pNativeRender; |
| format->nFrameWidth = pformat->nFrameWidth; |
| format->nFrameHeight = pformat->nFrameHeight; |
| format->nBitrate = pformat->nBitrate; |
| format->xFramerate = pformat->xFramerate; |
| format->bFlagErrorConcealment = pformat->bFlagErrorConcealment; |
| format->eCompressionFormat = pformat->eCompressionFormat; |
| format->eColorFormat = pformat->eColorFormat; |
| format->pNativeWindow = pformat->pNativeWindow; |
| OMX_S32 nFrameSize = getFrameBufSize(format->eColorFormat,format->nFrameWidth,format->nFrameHeight); |
| if(nFrameSize!=-1) |
| temp.nBufferSize = nFrameSize; |
| if (overwrite_readonly) { |
| format->nStride = pformat->nStride; |
| format->nSliceHeight = pformat->nSliceHeight; |
| } else { |
| format->nStride = pformat->nFrameWidth; |
| format->nSliceHeight = pformat->nFrameHeight; |
| } |
| |
| break; |
| } |
| case OMX_PortDomainImage: { |
| OMX_IMAGE_PORTDEFINITIONTYPE *format = &temp.format.image; |
| const OMX_IMAGE_PORTDEFINITIONTYPE *pformat = &p->format.image; |
| OMX_U32 mimetype_len = strlen(pformat->cMIMEType); |
| |
| mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ? |
| mimetype_len : OMX_MAX_STRINGNAME_SIZE-1; |
| |
| strncpy(format->cMIMEType, pformat->cMIMEType, |
| mimetype_len+1); |
| format->cMIMEType[mimetype_len+1] = '\0'; |
| format->nFrameWidth = pformat->nFrameWidth; |
| format->nFrameHeight = pformat->nFrameHeight; |
| format->nStride = pformat->nStride; |
| format->bFlagErrorConcealment = pformat->bFlagErrorConcealment; |
| format->eCompressionFormat = pformat->eCompressionFormat; |
| format->eColorFormat = pformat->eColorFormat; |
| format->pNativeWindow = pformat->pNativeWindow; |
| |
| if (overwrite_readonly) |
| format->nSliceHeight = pformat->nSliceHeight; |
| |
| break; |
| } |
| case OMX_PortDomainOther: { |
| OMX_OTHER_PORTDEFINITIONTYPE *format = &temp.format.other; |
| const OMX_OTHER_PORTDEFINITIONTYPE *pformat = &p->format.other; |
| |
| format->eFormat = pformat->eFormat; |
| break; |
| } |
| default: |
| LOGE("cannot find 0x%08x port domain\n", p->eDomain); |
| return OMX_ErrorBadParameter; |
| } |
| |
| memcpy(&portdefinition, &temp, sizeof(temp)); |
| return OMX_ErrorNone; |
| } |
| |
| const OMX_PARAM_PORTDEFINITIONTYPE *PortBase::GetPortDefinition(void) |
| { |
| return &portdefinition; |
| } |
| |
| /* Use/Allocate/FreeBuffer */ |
| OMX_ERRORTYPE PortBase::UseBuffer(OMX_BUFFERHEADERTYPE **ppBufferHdr, |
| OMX_U32 nPortIndex, |
| OMX_PTR pAppPrivate, |
| OMX_U32 nSizeBytes, |
| OMX_U8 *pBuffer) |
| { |
| OMX_BUFFERHEADERTYPE *buffer_hdr; |
| struct list *entry; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: enter, nSizeBytes=%u\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes); |
| |
| pthread_mutex_lock(&hdrs_lock); |
| |
| if (portdefinition.bPopulated == OMX_TRUE) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGV("%s(): %s:%s:PortIndex %u: exit done, already populated\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| nPortIndex); |
| return OMX_ErrorNone; |
| } |
| |
| buffer_hdr = (OMX_BUFFERHEADERTYPE *)calloc(1, sizeof(*buffer_hdr)); |
| if (!buffer_hdr) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, " |
| "connot allocate buffer header\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| entry = list_alloc(buffer_hdr); |
| if (!entry) { |
| free(buffer_hdr); |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, " |
| "cannot allocate list entry\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr)); |
| buffer_hdr->pBuffer = pBuffer; |
| buffer_hdr->nAllocLen = nSizeBytes; |
| buffer_hdr->pAppPrivate = pAppPrivate; |
| buffer_hdr->pInputPortPrivate = NULL; |
| buffer_hdr->pOutputPortPrivate = NULL; |
| if (portdefinition.eDir == OMX_DirInput) { |
| buffer_hdr->nInputPortIndex = nPortIndex; |
| buffer_hdr->nOutputPortIndex = 0x7fffffff; |
| } |
| else { |
| buffer_hdr->nOutputPortIndex = nPortIndex; |
| buffer_hdr->nInputPortIndex = 0x7fffffff; |
| } |
| |
| buffer_hdrs = __list_add_tail(buffer_hdrs, entry); |
| nr_buffer_hdrs++; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: a buffer allocated (%p:%u/%u)\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, |
| buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual); |
| |
| if (nr_buffer_hdrs >= portdefinition.nBufferCountActual) { |
| portdefinition.bPopulated = OMX_TRUE; |
| buffer_hdrs_completion = true; |
| pthread_cond_signal(&hdrs_wait); |
| LOGV("%s(): %s:%s:PortIndex %u: allocate all buffers (%u)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| nPortIndex, portdefinition.nBufferCountActual); |
| } |
| |
| *ppBufferHdr = buffer_hdr; |
| |
| pthread_mutex_unlock(&hdrs_lock); |
| |
| LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE PortBase:: AllocateBuffer(OMX_BUFFERHEADERTYPE **ppBuffer, |
| OMX_U32 nPortIndex, |
| OMX_PTR pAppPrivate, |
| OMX_U32 nSizeBytes) |
| { |
| OMX_BUFFERHEADERTYPE *buffer_hdr; |
| struct list *entry; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: enter, nSizeBytes=%u\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes); |
| |
| pthread_mutex_lock(&hdrs_lock); |
| if (portdefinition.bPopulated == OMX_TRUE) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGV("%s(): %s:%s:PortIndex %u: exit done, already populated\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| nPortIndex); |
| return OMX_ErrorNone; |
| } |
| |
| if (custom_mem_alloc) { |
| buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr)); |
| } else { |
| if (mem_alignment > 0) |
| buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr) + nSizeBytes + mem_alignment); |
| else |
| buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr) + nSizeBytes); |
| } |
| |
| if (!buffer_hdr) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, " |
| "connot allocate buffer header\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| entry = list_alloc(buffer_hdr); |
| if (!entry) { |
| free(buffer_hdr); |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, " |
| "connot allocate list entry\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr)); |
| if (custom_mem_alloc) { |
| buffer_hdr->pBuffer = (*custom_mem_alloc)(nSizeBytes, custom_mem_userdata); |
| } else { |
| if (mem_alignment > 0) |
| buffer_hdr->pBuffer = (OMX_U8 *)(((OMX_U32)((OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr)) / mem_alignment + 1) * mem_alignment); |
| else |
| buffer_hdr->pBuffer = (OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr); |
| } |
| if (buffer_hdr->pBuffer == NULL) { |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| buffer_hdr->nAllocLen = nSizeBytes; |
| buffer_hdr->pAppPrivate = pAppPrivate; |
| buffer_hdr->pInputPortPrivate = NULL; |
| buffer_hdr->pOutputPortPrivate = NULL; |
| if (portdefinition.eDir == OMX_DirInput) { |
| buffer_hdr->nInputPortIndex = nPortIndex; |
| buffer_hdr->nOutputPortIndex = (OMX_U32)-1; |
| } |
| else { |
| buffer_hdr->nOutputPortIndex = nPortIndex; |
| buffer_hdr->nInputPortIndex = (OMX_U32)-1; |
| } |
| |
| buffer_hdrs = __list_add_tail(buffer_hdrs, entry); |
| nr_buffer_hdrs++; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: a buffer allocated (%p:%u/%u)\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, |
| buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual); |
| |
| if (nr_buffer_hdrs == portdefinition.nBufferCountActual) { |
| portdefinition.bPopulated = OMX_TRUE; |
| buffer_hdrs_completion = true; |
| pthread_cond_signal(&hdrs_wait); |
| LOGV("%s(): %s:%s:PortIndex %u: allocate all buffers (%u)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| nPortIndex, portdefinition.nBufferCountActual); |
| } |
| |
| *ppBuffer = buffer_hdr; |
| |
| pthread_mutex_unlock(&hdrs_lock); |
| |
| LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE PortBase::FreeBuffer(OMX_U32 nPortIndex, |
| OMX_BUFFERHEADERTYPE *pBuffer) |
| { |
| struct list *entry; |
| OMX_ERRORTYPE ret; |
| |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer); |
| |
| pthread_mutex_lock(&hdrs_lock); |
| entry = list_find(buffer_hdrs, pBuffer); |
| |
| if (!entry) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "cannot find list entry for pBuffer\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (entry->data != pBuffer) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure," |
| "mismatch list entry\n" , __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer); |
| return OMX_ErrorBadParameter; |
| } |
| |
| ret = ComponentBase::CheckTypeHeader(pBuffer, sizeof(*pBuffer)); |
| if (ret != OMX_ErrorNone) { |
| pthread_mutex_unlock(&hdrs_lock); |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure," |
| "invalid type header\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer); |
| return ret; |
| } |
| |
| buffer_hdrs = __list_delete(buffer_hdrs, entry); |
| nr_buffer_hdrs--; |
| |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: free a buffer (%u/%u)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, |
| pBuffer, nr_buffer_hdrs, portdefinition.nBufferCountActual); |
| if (custom_mem_free) { |
| (*custom_mem_free)(pBuffer->pBuffer, custom_mem_userdata); |
| pBuffer->pBuffer = NULL; |
| } |
| free(pBuffer); |
| |
| portdefinition.bPopulated = OMX_FALSE; |
| if (!nr_buffer_hdrs) { |
| buffer_hdrs_completion = true; |
| pthread_cond_signal(&hdrs_wait); |
| LOGV("%s(): %s:%s:PortIndex %u: free all allocated buffers (%u)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| nPortIndex, portdefinition.nBufferCountActual); |
| } |
| |
| pthread_mutex_unlock(&hdrs_lock); |
| |
| LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), nPortIndex); |
| return OMX_ErrorNone; |
| } |
| |
| void PortBase::WaitPortBufferCompletion(void) |
| { |
| pthread_mutex_lock(&hdrs_lock); |
| if (!buffer_hdrs_completion) { |
| LOGV("%s(): %s:%s:PortIndex %u: wait for buffer header completion\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| pthread_cond_wait(&hdrs_wait, &hdrs_lock); |
| LOGV("%s(): %s:%s:PortIndex %u: wokeup (buffer header completion)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| } |
| buffer_hdrs_completion = !buffer_hdrs_completion; |
| pthread_mutex_unlock(&hdrs_lock); |
| } |
| |
| OMX_ERRORTYPE PortBase::WaitPortBufferCompletionTimeout(int64_t milliseconds) |
| { |
| int rc = 0; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| pthread_mutex_lock(&hdrs_lock); |
| if (!buffer_hdrs_completion) { |
| LOGV("%s(): %s:%s:PortIndex %u: wait for buffer header completion\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| struct timespec tv; |
| clock_gettime(CLOCK_REALTIME, &tv); |
| tv.tv_sec += milliseconds/1000; |
| tv.tv_nsec+= (milliseconds%1000) * 1000000; |
| if (tv.tv_nsec >= 1000000000) { |
| tv.tv_sec += 1; |
| tv.tv_nsec -= 1000000000; |
| } |
| |
| rc = pthread_cond_timedwait(&hdrs_wait, &hdrs_lock, &tv); |
| } |
| if (rc == ETIMEDOUT) { |
| LOGE("%s(): %s:%s:PortIndex %u: wokeup (buffer header timeout)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| ret = OMX_ErrorTimeout; |
| } |
| buffer_hdrs_completion = !buffer_hdrs_completion; |
| pthread_mutex_unlock(&hdrs_lock); |
| return ret; |
| } |
| |
| /* Empty/FillThisBuffer */ |
| OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer) |
| { |
| int ret; |
| LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %u:pBuffer %p:\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| pthread_mutex_lock(&bufferq_lock); |
| ret = queue_push_tail(&bufferq, pBuffer); |
| pthread_mutex_unlock(&bufferq_lock); |
| |
| if (ret) |
| return OMX_ErrorInsufficientResources; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void) |
| { |
| OMX_BUFFERHEADERTYPE *buffer; |
| |
| pthread_mutex_lock(&bufferq_lock); |
| buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq); |
| pthread_mutex_unlock(&bufferq_lock); |
| LOGV_IF((buffer != NULL || RetainedBufferQueueLength() > 0), "%s(): %s:%s:PortIndex %u:pBuffer %p:\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, buffer); |
| return buffer; |
| } |
| |
| OMX_U32 PortBase::BufferQueueLength(void) |
| { |
| OMX_U32 length; |
| |
| pthread_mutex_lock(&bufferq_lock); |
| length = queue_length(&bufferq); |
| pthread_mutex_unlock(&bufferq_lock); |
| |
| return length; |
| } |
| |
| OMX_U32 PortBase::RetainedBufferQueueLength(void) |
| { |
| OMX_U32 length; |
| |
| pthread_mutex_lock(&retainedbufferq_lock); |
| length = queue_length(&retainedbufferq); |
| pthread_mutex_unlock(&retainedbufferq_lock); |
| |
| return length; |
| } |
| |
| OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer) |
| { |
| OMX_DIRTYPE direction = portdefinition.eDir; |
| OMX_U32 port_index; |
| OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE, |
| OMX_PTR, |
| OMX_BUFFERHEADERTYPE *); |
| OMX_ERRORTYPE ret; |
| |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| pBuffer); |
| |
| if (!pBuffer) { |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "invalid buffer pointer\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (direction == OMX_DirInput) { |
| port_index = pBuffer->nInputPortIndex; |
| bufferdone_callback = callbacks->EmptyBufferDone; |
| } |
| else if (direction == OMX_DirOutput) { |
| port_index = pBuffer->nOutputPortIndex; |
| bufferdone_callback = callbacks->FillBufferDone; |
| } |
| else { |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "invalid direction (%d)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer, |
| direction); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (port_index != portdefinition.nPortIndex) { |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "invalid port index (%u)\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer, port_index); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) { |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: " |
| "Report OMX_EventBufferFlag (OMX_BUFFERFLAG_EOS)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| |
| callbacks->EventHandler(owner, appdata, |
| OMX_EventBufferFlag, |
| port_index, pBuffer->nFlags, NULL); |
| } |
| |
| if (pBuffer->hMarkTargetComponent == owner) { |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: " |
| "Report OMX_EventMark\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| |
| callbacks->EventHandler(owner, appdata, OMX_EventMark, |
| 0, 0, pBuffer->pMarkData); |
| pBuffer->hMarkTargetComponent = NULL; |
| pBuffer->pMarkData = NULL; |
| } |
| |
| ret = bufferdone_callback(owner, appdata, pBuffer); |
| |
| LOGV("%s(): %s:%s:PortIndex %u: exit done, " |
| "callback returned (0x%08x)\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| ret); |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE PortBase::RetainAndReturnBuffer( OMX_BUFFERHEADERTYPE *pRetain, OMX_BUFFERHEADERTYPE *pReturn) |
| { |
| OMX_ERRORTYPE ret; |
| OMX_U32 length; |
| if (pReturn == pRetain) { |
| return ReturnThisBuffer(pReturn); |
| } |
| ret = RetainThisBuffer(pRetain, false); |
| if (ret != OMX_ErrorNone) { |
| return ret; |
| } |
| |
| pthread_mutex_lock(&bufferq_lock); |
| length = queue_length(&bufferq); |
| OMX_BUFFERHEADERTYPE *p; |
| /* remove returned buffer from the queue */ |
| OMX_U32 i = 0; |
| for (i = 0; i < length; i++) { |
| p = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq); |
| if (p == pReturn) { |
| break; |
| } |
| queue_push_tail(&bufferq, p); |
| } |
| pthread_mutex_unlock(&bufferq_lock); |
| |
| if (i == length) { |
| return OMX_ErrorNone; |
| } |
| |
| return ReturnThisBuffer(pReturn); |
| } |
| |
| /* retain buffer */ |
| OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer, |
| bool accumulate) |
| { |
| int ret; |
| |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter, %s\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| pBuffer, (accumulate == true) ? "accumulate" : "getagain"); |
| |
| /* push at tail of retainedbufferq */ |
| if (accumulate == true) { |
| |
| if (cbase->GetWorkingRole() == NULL || (strncmp((char*)cbase->GetWorkingRole(), "video_encoder", 13) != 0)) { |
| /* do not accumulate a buffer set EOS flag if not video encoder*/ |
| if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) { |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "cannot accumulate EOS buffer\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| return OMX_ErrorBadParameter; |
| } |
| } |
| |
| pthread_mutex_lock(&retainedbufferq_lock); |
| if ((OMX_U32)queue_length(&retainedbufferq) < |
| portdefinition.nBufferCountActual) |
| ret = queue_push_tail(&retainedbufferq, pBuffer); |
| else { |
| ret = OMX_ErrorInsufficientResources; |
| LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, " |
| "retained bufferq length (%d) exceeds port's actual count " |
| "(%u)\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer, |
| queue_length(&retainedbufferq), |
| portdefinition.nBufferCountActual); |
| } |
| pthread_mutex_unlock(&retainedbufferq_lock); |
| } |
| /* |
| * just push at head of bufferq to get this buffer again in |
| * ComponentBase::ProcessorProcess() |
| */ |
| else { |
| pthread_mutex_lock(&bufferq_lock); |
| ret = queue_push_head(&bufferq, pBuffer); |
| pthread_mutex_unlock(&bufferq_lock); |
| } |
| |
| if (ret) |
| return OMX_ErrorInsufficientResources; |
| |
| LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: exit done\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, pBuffer); |
| return OMX_ErrorNone; |
| } |
| |
| void PortBase::ReturnAllRetainedBuffers(void) |
| { |
| OMX_BUFFERHEADERTYPE *buffer; |
| OMX_ERRORTYPE ret; |
| int i = 0; |
| |
| pthread_mutex_lock(&retainedbufferq_lock); |
| |
| do { |
| buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq); |
| |
| if (buffer) { |
| LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer " |
| "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(), |
| cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| buffer, i++, queue_length(&retainedbufferq)); |
| |
| ret = ReturnThisBuffer(buffer); |
| if (ret != OMX_ErrorNone) |
| LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, ret); |
| } |
| } while (buffer); |
| |
| pthread_mutex_unlock(&retainedbufferq_lock); |
| LOGV_IF(i != 0, |
| "%s(): %s:%s:PortIndex %u: returned all retained buffers (%d)\n", |
| __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, i); |
| } |
| |
| void PortBase::ReturnOneRetainedBuffer(void) |
| { |
| OMX_BUFFERHEADERTYPE *buffer; |
| OMX_ERRORTYPE ret; |
| int i =0; |
| |
| pthread_mutex_lock(&retainedbufferq_lock); |
| |
| buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq); |
| |
| if (buffer) { |
| LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer " |
| "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(), |
| cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| buffer, i++, queue_length(&retainedbufferq)); |
| |
| ret = ReturnThisBuffer(buffer); |
| if (ret != OMX_ErrorNone) |
| LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, ret); |
| } |
| |
| pthread_mutex_unlock(&retainedbufferq_lock); |
| |
| } |
| |
| /* SendCommand:Flush/PortEnable/Disable */ |
| /* must be held ComponentBase::ports_block */ |
| OMX_ERRORTYPE PortBase::FlushPort(void) |
| { |
| OMX_BUFFERHEADERTYPE *buffer; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: enter\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| |
| ReturnAllRetainedBuffers(); |
| |
| while ((buffer = PopBuffer())) |
| ReturnThisBuffer(buffer); |
| |
| LOGV("%s(): %s:%s:PortIndex %u: exit\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex); |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_STATETYPE PortBase::GetOwnerState(void) |
| { |
| OMX_STATETYPE state = OMX_StateInvalid; |
| |
| if (owner) { |
| ComponentBase *cbase; |
| cbase = static_cast<ComponentBase *>(owner->pComponentPrivate); |
| if (!cbase) |
| return state; |
| |
| cbase->CBaseGetState((void *)owner, &state); |
| } |
| |
| return state; |
| } |
| |
| bool PortBase::IsEnabled(void) |
| { |
| bool enabled; |
| bool unlock = true; |
| |
| if (pthread_mutex_trylock(&state_lock)) |
| unlock = false; |
| |
| enabled = (state == OMX_PortEnabled) ? true : false; |
| |
| if (unlock) |
| pthread_mutex_unlock(&state_lock); |
| |
| return enabled; |
| } |
| |
| OMX_DIRTYPE PortBase::GetPortDirection(void) |
| { |
| return portdefinition.eDir; |
| } |
| |
| OMX_U32 PortBase::GetPortBufferCount(void) |
| { |
| return nr_buffer_hdrs; |
| } |
| |
| OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark) |
| { |
| int ret; |
| |
| pthread_mutex_lock(&markq_lock); |
| ret = queue_push_tail(&markq, mark); |
| pthread_mutex_unlock(&markq_lock); |
| |
| if (ret) |
| return OMX_ErrorInsufficientResources; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_MARKTYPE *PortBase::PopMark(void) |
| { |
| OMX_MARKTYPE *mark; |
| |
| pthread_mutex_lock(&markq_lock); |
| mark = (OMX_MARKTYPE *)queue_pop_head(&markq); |
| pthread_mutex_unlock(&markq_lock); |
| |
| return mark; |
| } |
| |
| static const char *state_name[PortBase::OMX_PortEnabled+2] = { |
| "OMX_PortDisabled", |
| "OMX_PortEnabled", |
| "UnKnown Port State", |
| }; |
| |
| const char *GetPortStateName(OMX_U8 state) |
| { |
| if (state > PortBase::OMX_PortEnabled) |
| state = PortBase::OMX_PortEnabled+1; |
| |
| return state_name[state]; |
| } |
| |
| OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition) |
| { |
| OMX_U8 current; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: enter, transition from %s to %s\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| GetPortStateName(state), GetPortStateName(transition)); |
| |
| pthread_mutex_lock(&state_lock); |
| |
| current = state; |
| |
| if (current == transition) { |
| ret = OMX_ErrorSameState; |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, same state (%s)\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, GetPortStateName(current)); |
| goto unlock; |
| } |
| |
| if (transition == OMX_PortEnabled) { |
| if (cbase->GetWorkingRole() != NULL && |
| !strncmp (cbase->GetWorkingRole(),"video_decoder", 13 )) { |
| ret = WaitPortBufferCompletionTimeout(800); //0.8s timeout |
| if (!nr_buffer_hdrs) { |
| // event is trigger by freeing buffer instead of allocating buffer |
| ret = OMX_ErrorBadParameter; |
| } |
| if (ret != OMX_ErrorNone) { |
| goto unlock; |
| } |
| } else { |
| WaitPortBufferCompletion(); |
| } |
| portdefinition.bEnabled = OMX_TRUE; |
| } |
| else if(transition == OMX_PortDisabled) { |
| /*need to flush only if port is not empty*/ |
| if (nr_buffer_hdrs) |
| { |
| FlushPort(); |
| WaitPortBufferCompletion(); |
| } |
| portdefinition.bEnabled = OMX_FALSE; |
| } |
| else { |
| ret = OMX_ErrorBadParameter; |
| LOGE("%s(): %s:%s:PortIndex %u: exit failure, invalid transition " |
| "(%s)\n", __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), |
| portdefinition.nPortIndex, GetPortStateName(transition)); |
| goto unlock; |
| } |
| |
| state = transition; |
| |
| LOGV("%s(): %s:%s:PortIndex %u: transition from %s to %s complete\n", |
| __FUNCTION__, |
| cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex, |
| GetPortStateName(current), GetPortStateName(state)); |
| |
| unlock: |
| pthread_mutex_unlock(&state_lock); |
| return ret; |
| } |
| |
| OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void) |
| { |
| OMX_ERRORTYPE ret; |
| |
| ret = callbacks->EventHandler(owner, appdata, |
| OMX_EventPortSettingsChanged, |
| portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL); |
| |
| FlushPort(); |
| |
| return ret; |
| } |
| |
| OMX_ERRORTYPE PortBase::ReportOutputCrop(void) |
| { |
| OMX_ERRORTYPE ret; |
| |
| ret = callbacks->EventHandler(owner, appdata, |
| OMX_EventPortSettingsChanged, |
| portdefinition.nPortIndex,OMX_IndexConfigCommonOutputCrop, NULL); |
| |
| return ret; |
| } |
| |
| |
| /* end of component methods & helpers */ |
| |
| /* end of PortBase */ |