/* * 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 #include #include #include #include #include #include //#define LOG_NDEBUG 0 #define LOG_TAG "portbase" #include /* * 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(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(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 */