Home | History | Annotate | Download | only in src
      1 /*
      2  * portbase.cpp, base port class
      3  *
      4  * Copyright (c) 2009-2010 Wind River Systems, Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  * http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include <OMX_Core.h>
     23 #include <OMX_Component.h>
     24 
     25 #include <portbase.h>
     26 #include <componentbase.h>
     27 //#define LOG_NDEBUG 0
     28 
     29 #define LOG_TAG "portbase"
     30 #include <log.h>
     31 
     32 /*
     33  * constructor & destructor
     34  */
     35 void PortBase::__PortBase(void)
     36 {
     37     buffer_hdrs = NULL;
     38     nr_buffer_hdrs = 0;
     39     buffer_hdrs_completion = false;
     40 
     41     custom_mem_alloc = NULL;
     42     custom_mem_free = NULL;
     43     custom_mem_userdata = NULL;
     44 
     45     mem_alignment = 0;
     46 
     47     pthread_mutex_init(&hdrs_lock, NULL);
     48     pthread_cond_init(&hdrs_wait, NULL);
     49 
     50     __queue_init(&bufferq);
     51     pthread_mutex_init(&bufferq_lock, NULL);
     52 
     53     __queue_init(&retainedbufferq);
     54     pthread_mutex_init(&retainedbufferq_lock, NULL);
     55 
     56     __queue_init(&markq);
     57     pthread_mutex_init(&markq_lock, NULL);
     58 
     59     state = OMX_PortEnabled;
     60     pthread_mutex_init(&state_lock, NULL);
     61 
     62     memset(&portdefinition, 0, sizeof(portdefinition));
     63     ComponentBase::SetTypeHeader(&portdefinition, sizeof(portdefinition));
     64     memset(definition_format_mimetype, 0, OMX_MAX_STRINGNAME_SIZE);
     65     portdefinition.format.audio.cMIMEType = &definition_format_mimetype[0];
     66     portdefinition.format.video.cMIMEType = &definition_format_mimetype[0];
     67     portdefinition.format.image.cMIMEType = &definition_format_mimetype[0];
     68 
     69     memset(&audioparam, 0, sizeof(audioparam));
     70 
     71     owner = NULL;
     72     appdata = NULL;
     73     callbacks = NULL;
     74 
     75     cbase = NULL;
     76 }
     77 
     78 PortBase::PortBase()
     79 {
     80     __PortBase();
     81 }
     82 
     83 PortBase::PortBase(const OMX_PARAM_PORTDEFINITIONTYPE *portdefinition)
     84 {
     85     __PortBase();
     86     SetPortDefinition(portdefinition, true);
     87 }
     88 
     89 PortBase::~PortBase()
     90 {
     91     struct list *entry, *temp;
     92 
     93     /* should've been already freed at FreeBuffer() */
     94     list_foreach_safe(buffer_hdrs, entry, temp) {
     95         free(entry->data); /* OMX_BUFFERHEADERTYPE */
     96         __list_delete(buffer_hdrs, entry);
     97     }
     98 
     99     pthread_cond_destroy(&hdrs_wait);
    100     pthread_mutex_destroy(&hdrs_lock);
    101 
    102     /* should've been already freed at buffer processing */
    103     queue_free_all(&bufferq);
    104     pthread_mutex_destroy(&bufferq_lock);
    105 
    106     /* should've been already freed at buffer processing */
    107     queue_free_all(&retainedbufferq);
    108     pthread_mutex_destroy(&retainedbufferq_lock);
    109 
    110     /* should've been already empty in PushThisBuffer () */
    111     queue_free_all(&markq);
    112     pthread_mutex_destroy(&markq_lock);
    113 
    114     pthread_mutex_destroy(&state_lock);
    115 }
    116 
    117 /* end of constructor & destructor */
    118 
    119 /*
    120  * accessor
    121  */
    122 /* owner */
    123 void PortBase::SetOwner(OMX_COMPONENTTYPE *handle)
    124 {
    125     owner = handle;
    126     cbase = static_cast<ComponentBase *>(handle->pComponentPrivate);
    127 }
    128 
    129 OMX_COMPONENTTYPE *PortBase::GetOwner(void)
    130 {
    131     return owner;
    132 }
    133 
    134 OMX_ERRORTYPE PortBase::SetCallbacks(OMX_HANDLETYPE hComponent,
    135                                      OMX_CALLBACKTYPE *pCallbacks,
    136                                      OMX_PTR pAppData)
    137 {
    138     if (owner != hComponent)
    139         return OMX_ErrorBadParameter;
    140 
    141     appdata = pAppData;
    142     callbacks = pCallbacks;
    143 
    144     return OMX_ErrorNone;
    145 }
    146 
    147 OMX_ERRORTYPE PortBase::SetMemAllocator(CustomMemAlloc *pMemAlloc, CustomMemFree *pMemFree, OMX_PTR pUserData)
    148 {
    149     custom_mem_alloc = pMemAlloc;
    150     custom_mem_free = pMemFree;
    151     custom_mem_userdata = pUserData;
    152     return OMX_ErrorNone;
    153 }
    154 
    155 OMX_ERRORTYPE PortBase::SetMemAlignment(OMX_U32 nAlignment)
    156 {
    157     mem_alignment = nAlignment;
    158     return OMX_ErrorNone;
    159 }
    160 
    161 OMX_U32 PortBase::getFrameBufSize(OMX_COLOR_FORMATTYPE colorFormat, OMX_U32 width, OMX_U32 height)
    162 {
    163     switch (colorFormat) {
    164     case OMX_COLOR_FormatYCbYCr:
    165     case OMX_COLOR_FormatCbYCrY:
    166         return width * height * 2;
    167     case OMX_COLOR_FormatYUV420Planar:
    168     case OMX_COLOR_FormatYUV420SemiPlanar:
    169         return (width * height * 3) >> 1;
    170 
    171     default:
    172         LOGV("unsupport color format !");
    173         return -1;
    174     }
    175 }
    176 
    177 /* end of accessor */
    178 
    179 /*
    180  * component methods & helpers
    181  */
    182 /* Get/SetParameter */
    183 OMX_ERRORTYPE PortBase::SetPortDefinition(
    184     const OMX_PARAM_PORTDEFINITIONTYPE *p, bool overwrite_readonly)
    185 {
    186     OMX_PARAM_PORTDEFINITIONTYPE temp;
    187 
    188     memcpy(&temp, &portdefinition, sizeof(temp));
    189 
    190     if (!overwrite_readonly) {
    191         if (temp.nPortIndex != p->nPortIndex)
    192             return OMX_ErrorBadParameter;
    193         if (temp.eDir != p->eDir)
    194             return OMX_ErrorBadParameter;
    195         if (temp.eDomain != p->eDomain)
    196             return OMX_ErrorBadParameter;
    197         if (temp.nBufferCountActual != p->nBufferCountActual) {
    198             if (temp.nBufferCountMin > p->nBufferCountActual)
    199                 return OMX_ErrorBadParameter;
    200             temp.nBufferCountActual = p->nBufferCountActual;
    201         }
    202         if ((p->nBufferSize > temp.nBufferSize) && (temp.eDir == OMX_DirInput)) {
    203             if (p->nBufferSize <= MAX_INPUT_PORT_SIZE) {
    204                 LOGW("Input port size has been changed!");
    205                 temp.nBufferSize = p->nBufferSize;
    206             } else {
    207                 LOGE("Invalid input port size!");
    208                 return OMX_ErrorBadParameter;
    209             }
    210         }
    211     }
    212     else {
    213         temp.nPortIndex = p->nPortIndex;
    214         temp.eDir = p->eDir;
    215         temp.nBufferCountActual = p->nBufferCountActual;
    216         temp.nBufferCountMin = p->nBufferCountMin;
    217         temp.nBufferSize = p->nBufferSize;
    218         temp.bEnabled = p->bEnabled;
    219         temp.bPopulated = p->bPopulated;
    220         temp.eDomain = p->eDomain;
    221         temp.bBuffersContiguous = p->bBuffersContiguous;
    222         temp.nBufferAlignment = p->nBufferAlignment;
    223     }
    224 
    225     switch (p->eDomain) {
    226     case OMX_PortDomainAudio: {
    227         OMX_AUDIO_PORTDEFINITIONTYPE *format = &temp.format.audio;
    228         const OMX_AUDIO_PORTDEFINITIONTYPE *pformat = &p->format.audio;
    229         OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
    230 
    231         mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
    232                        mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
    233 
    234         strncpy(format->cMIMEType, pformat->cMIMEType,
    235                 mimetype_len);
    236         format->cMIMEType[mimetype_len+1] = '\0';
    237         format->pNativeRender = pformat->pNativeRender;
    238         format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
    239         format->eEncoding = pformat->eEncoding;
    240 
    241         break;
    242     }
    243     case OMX_PortDomainVideo: {
    244         OMX_VIDEO_PORTDEFINITIONTYPE *format = &temp.format.video;
    245         const OMX_VIDEO_PORTDEFINITIONTYPE *pformat = &p->format.video;
    246         OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
    247 
    248         mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
    249                        mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
    250 
    251         strncpy(format->cMIMEType, pformat->cMIMEType,
    252                 mimetype_len);
    253         format->cMIMEType[mimetype_len+1] = '\0';
    254         format->pNativeRender = pformat->pNativeRender;
    255         format->nFrameWidth = pformat->nFrameWidth;
    256         format->nFrameHeight = pformat->nFrameHeight;
    257         format->nBitrate = pformat->nBitrate;
    258         format->xFramerate = pformat->xFramerate;
    259         format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
    260         format->eCompressionFormat = pformat->eCompressionFormat;
    261         format->eColorFormat = pformat->eColorFormat;
    262         format->pNativeWindow = pformat->pNativeWindow;
    263         OMX_S32 nFrameSize = getFrameBufSize(format->eColorFormat,format->nFrameWidth,format->nFrameHeight);
    264         if(nFrameSize!=-1)
    265             temp.nBufferSize = nFrameSize;
    266         if (overwrite_readonly) {
    267             format->nStride = pformat->nStride;
    268             format->nSliceHeight = pformat->nSliceHeight;
    269         } else {
    270             format->nStride = pformat->nFrameWidth;
    271             format->nSliceHeight = pformat->nFrameHeight;
    272         }
    273 
    274         break;
    275     }
    276     case OMX_PortDomainImage: {
    277         OMX_IMAGE_PORTDEFINITIONTYPE *format = &temp.format.image;
    278         const OMX_IMAGE_PORTDEFINITIONTYPE *pformat = &p->format.image;
    279         OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
    280 
    281         mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
    282                        mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
    283 
    284         strncpy(format->cMIMEType, pformat->cMIMEType,
    285                 mimetype_len+1);
    286         format->cMIMEType[mimetype_len+1] = '\0';
    287         format->nFrameWidth = pformat->nFrameWidth;
    288         format->nFrameHeight = pformat->nFrameHeight;
    289         format->nStride = pformat->nStride;
    290         format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
    291         format->eCompressionFormat = pformat->eCompressionFormat;
    292         format->eColorFormat = pformat->eColorFormat;
    293         format->pNativeWindow = pformat->pNativeWindow;
    294 
    295         if (overwrite_readonly)
    296             format->nSliceHeight = pformat->nSliceHeight;
    297 
    298         break;
    299     }
    300     case OMX_PortDomainOther: {
    301         OMX_OTHER_PORTDEFINITIONTYPE *format = &temp.format.other;
    302         const OMX_OTHER_PORTDEFINITIONTYPE *pformat = &p->format.other;
    303 
    304         format->eFormat = pformat->eFormat;
    305         break;
    306     }
    307     default:
    308         LOGE("cannot find 0x%08x port domain\n", p->eDomain);
    309         return OMX_ErrorBadParameter;
    310     }
    311 
    312     memcpy(&portdefinition, &temp, sizeof(temp));
    313     return OMX_ErrorNone;
    314 }
    315 
    316 const OMX_PARAM_PORTDEFINITIONTYPE *PortBase::GetPortDefinition(void)
    317 {
    318     return &portdefinition;
    319 }
    320 
    321 /* Use/Allocate/FreeBuffer */
    322 OMX_ERRORTYPE PortBase::UseBuffer(OMX_BUFFERHEADERTYPE **ppBufferHdr,
    323                                   OMX_U32 nPortIndex,
    324                                   OMX_PTR pAppPrivate,
    325                                   OMX_U32 nSizeBytes,
    326                                   OMX_U8 *pBuffer)
    327 {
    328     OMX_BUFFERHEADERTYPE *buffer_hdr;
    329     struct list *entry;
    330 
    331     LOGV("%s(): %s:%s:PortIndex %u: enter, nSizeBytes=%u\n", __FUNCTION__,
    332          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes);
    333 
    334     pthread_mutex_lock(&hdrs_lock);
    335 
    336     if (portdefinition.bPopulated == OMX_TRUE) {
    337         pthread_mutex_unlock(&hdrs_lock);
    338         LOGV("%s(): %s:%s:PortIndex %u: exit done, already populated\n",
    339              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    340              nPortIndex);
    341         return OMX_ErrorNone;
    342     }
    343 
    344     buffer_hdr = (OMX_BUFFERHEADERTYPE *)calloc(1, sizeof(*buffer_hdr));
    345     if (!buffer_hdr) {
    346         pthread_mutex_unlock(&hdrs_lock);
    347         LOGE("%s(): %s:%s:PortIndex %u: exit failure, "
    348              "connot allocate buffer header\n", __FUNCTION__,
    349              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    350         return OMX_ErrorInsufficientResources;
    351     }
    352 
    353     entry = list_alloc(buffer_hdr);
    354     if (!entry) {
    355         free(buffer_hdr);
    356         pthread_mutex_unlock(&hdrs_lock);
    357         LOGE("%s(): %s:%s:PortIndex %u: exit failure, "
    358              "cannot allocate list entry\n", __FUNCTION__,
    359              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    360         return OMX_ErrorInsufficientResources;
    361     }
    362 
    363     ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
    364     buffer_hdr->pBuffer = pBuffer;
    365     buffer_hdr->nAllocLen = nSizeBytes;
    366     buffer_hdr->pAppPrivate = pAppPrivate;
    367     buffer_hdr->pInputPortPrivate = NULL;
    368     buffer_hdr->pOutputPortPrivate = NULL;
    369     if (portdefinition.eDir == OMX_DirInput) {
    370         buffer_hdr->nInputPortIndex = nPortIndex;
    371         buffer_hdr->nOutputPortIndex = 0x7fffffff;
    372     }
    373     else {
    374         buffer_hdr->nOutputPortIndex = nPortIndex;
    375         buffer_hdr->nInputPortIndex = 0x7fffffff;
    376     }
    377 
    378     buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
    379     nr_buffer_hdrs++;
    380 
    381     LOGV("%s(): %s:%s:PortIndex %u: a buffer allocated (%p:%u/%u)\n",
    382          __FUNCTION__,
    383          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
    384          buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual);
    385 
    386     if (nr_buffer_hdrs >= portdefinition.nBufferCountActual) {
    387         portdefinition.bPopulated = OMX_TRUE;
    388         buffer_hdrs_completion = true;
    389         pthread_cond_signal(&hdrs_wait);
    390         LOGV("%s(): %s:%s:PortIndex %u: allocate all buffers (%u)\n",
    391              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    392              nPortIndex, portdefinition.nBufferCountActual);
    393     }
    394 
    395     *ppBufferHdr = buffer_hdr;
    396 
    397     pthread_mutex_unlock(&hdrs_lock);
    398 
    399     LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__,
    400          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    401     return OMX_ErrorNone;
    402 }
    403 
    404 OMX_ERRORTYPE PortBase:: AllocateBuffer(OMX_BUFFERHEADERTYPE **ppBuffer,
    405                                        OMX_U32 nPortIndex,
    406                                        OMX_PTR pAppPrivate,
    407                                        OMX_U32 nSizeBytes)
    408 {
    409     OMX_BUFFERHEADERTYPE *buffer_hdr;
    410     struct list *entry;
    411 
    412     LOGV("%s(): %s:%s:PortIndex %u: enter, nSizeBytes=%u\n", __FUNCTION__,
    413          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes);
    414 
    415     pthread_mutex_lock(&hdrs_lock);
    416     if (portdefinition.bPopulated == OMX_TRUE) {
    417         pthread_mutex_unlock(&hdrs_lock);
    418         LOGV("%s(): %s:%s:PortIndex %u: exit done, already populated\n",
    419              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    420              nPortIndex);
    421         return OMX_ErrorNone;
    422     }
    423 
    424     if (custom_mem_alloc) {
    425         buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr));
    426     } else {
    427         if (mem_alignment > 0)
    428             buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr) + nSizeBytes + mem_alignment);
    429         else
    430             buffer_hdr = (OMX_BUFFERHEADERTYPE *) calloc(1, sizeof(*buffer_hdr) + nSizeBytes);
    431     }
    432 
    433     if (!buffer_hdr) {
    434         pthread_mutex_unlock(&hdrs_lock);
    435         LOGE("%s(): %s:%s:PortIndex %u: exit failure, "
    436              "connot allocate buffer header\n", __FUNCTION__,
    437              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    438         return OMX_ErrorInsufficientResources;
    439     }
    440 
    441     entry = list_alloc(buffer_hdr);
    442     if (!entry) {
    443         free(buffer_hdr);
    444         pthread_mutex_unlock(&hdrs_lock);
    445         LOGE("%s(): %s:%s:PortIndex %u: exit failure, "
    446              "connot allocate list entry\n", __FUNCTION__,
    447              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    448         return OMX_ErrorInsufficientResources;
    449     }
    450 
    451     ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
    452     if (custom_mem_alloc) {
    453         buffer_hdr->pBuffer = (*custom_mem_alloc)(nSizeBytes, custom_mem_userdata);
    454     } else {
    455         if (mem_alignment > 0)
    456             buffer_hdr->pBuffer = (OMX_U8 *)(((OMX_U32)((OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr)) / mem_alignment + 1) * mem_alignment);
    457         else
    458             buffer_hdr->pBuffer = (OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr);
    459     }
    460     if (buffer_hdr->pBuffer == NULL) {
    461         return OMX_ErrorInsufficientResources;
    462     }
    463 
    464     buffer_hdr->nAllocLen = nSizeBytes;
    465     buffer_hdr->pAppPrivate = pAppPrivate;
    466     buffer_hdr->pInputPortPrivate = NULL;
    467     buffer_hdr->pOutputPortPrivate = NULL;
    468     if (portdefinition.eDir == OMX_DirInput) {
    469         buffer_hdr->nInputPortIndex = nPortIndex;
    470         buffer_hdr->nOutputPortIndex = (OMX_U32)-1;
    471     }
    472     else {
    473         buffer_hdr->nOutputPortIndex = nPortIndex;
    474         buffer_hdr->nInputPortIndex = (OMX_U32)-1;
    475     }
    476 
    477     buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
    478     nr_buffer_hdrs++;
    479 
    480     LOGV("%s(): %s:%s:PortIndex %u: a buffer allocated (%p:%u/%u)\n",
    481          __FUNCTION__,
    482          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
    483          buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual);
    484 
    485     if (nr_buffer_hdrs == portdefinition.nBufferCountActual) {
    486         portdefinition.bPopulated = OMX_TRUE;
    487         buffer_hdrs_completion = true;
    488         pthread_cond_signal(&hdrs_wait);
    489         LOGV("%s(): %s:%s:PortIndex %u: allocate all buffers (%u)\n",
    490              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    491              nPortIndex, portdefinition.nBufferCountActual);
    492     }
    493 
    494     *ppBuffer = buffer_hdr;
    495 
    496     pthread_mutex_unlock(&hdrs_lock);
    497 
    498     LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__,
    499          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    500     return OMX_ErrorNone;
    501 }
    502 
    503 OMX_ERRORTYPE PortBase::FreeBuffer(OMX_U32 nPortIndex,
    504                                    OMX_BUFFERHEADERTYPE *pBuffer)
    505 {
    506     struct list *entry;
    507     OMX_ERRORTYPE ret;
    508 
    509     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter\n", __FUNCTION__,
    510          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
    511 
    512     pthread_mutex_lock(&hdrs_lock);
    513     entry = list_find(buffer_hdrs, pBuffer);
    514 
    515     if (!entry) {
    516         pthread_mutex_unlock(&hdrs_lock);
    517         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    518              "cannot find list entry for pBuffer\n", __FUNCTION__,
    519              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
    520         return OMX_ErrorBadParameter;
    521     }
    522 
    523     if (entry->data != pBuffer) {
    524         pthread_mutex_unlock(&hdrs_lock);
    525         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure,"
    526              "mismatch list entry\n" , __FUNCTION__,
    527              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
    528         return OMX_ErrorBadParameter;
    529     }
    530 
    531     ret = ComponentBase::CheckTypeHeader(pBuffer, sizeof(*pBuffer));
    532     if (ret != OMX_ErrorNone) {
    533         pthread_mutex_unlock(&hdrs_lock);
    534         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure,"
    535              "invalid type header\n", __FUNCTION__,
    536              cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
    537         return ret;
    538     }
    539 
    540     buffer_hdrs = __list_delete(buffer_hdrs, entry);
    541     nr_buffer_hdrs--;
    542 
    543     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: free a buffer (%u/%u)\n",
    544          __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
    545          pBuffer, nr_buffer_hdrs, portdefinition.nBufferCountActual);
    546     if (custom_mem_free) {
    547         (*custom_mem_free)(pBuffer->pBuffer, custom_mem_userdata);
    548         pBuffer->pBuffer = NULL;
    549     }
    550     free(pBuffer);
    551 
    552     portdefinition.bPopulated = OMX_FALSE;
    553     if (!nr_buffer_hdrs) {
    554         buffer_hdrs_completion = true;
    555         pthread_cond_signal(&hdrs_wait);
    556         LOGV("%s(): %s:%s:PortIndex %u: free all allocated buffers (%u)\n",
    557              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    558              nPortIndex, portdefinition.nBufferCountActual);
    559     }
    560 
    561     pthread_mutex_unlock(&hdrs_lock);
    562 
    563     LOGV("%s(): %s:%s:PortIndex %u: exit done\n", __FUNCTION__,
    564          cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
    565     return OMX_ErrorNone;
    566 }
    567 
    568 void PortBase::WaitPortBufferCompletion(void)
    569 {
    570     pthread_mutex_lock(&hdrs_lock);
    571     if (!buffer_hdrs_completion) {
    572         LOGV("%s(): %s:%s:PortIndex %u: wait for buffer header completion\n",
    573              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    574              portdefinition.nPortIndex);
    575         pthread_cond_wait(&hdrs_wait, &hdrs_lock);
    576         LOGV("%s(): %s:%s:PortIndex %u: wokeup (buffer header completion)\n",
    577              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    578              portdefinition.nPortIndex);
    579     }
    580     buffer_hdrs_completion = !buffer_hdrs_completion;
    581     pthread_mutex_unlock(&hdrs_lock);
    582 }
    583 
    584 OMX_ERRORTYPE PortBase::WaitPortBufferCompletionTimeout(int64_t milliseconds)
    585 {
    586     int rc = 0;
    587     OMX_ERRORTYPE ret = OMX_ErrorNone;
    588     pthread_mutex_lock(&hdrs_lock);
    589     if (!buffer_hdrs_completion) {
    590         LOGV("%s(): %s:%s:PortIndex %u: wait for buffer header completion\n",
    591              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    592              portdefinition.nPortIndex);
    593         struct timespec tv;
    594         clock_gettime(CLOCK_REALTIME, &tv);
    595         tv.tv_sec += milliseconds/1000;
    596         tv.tv_nsec+= (milliseconds%1000) * 1000000;
    597         rc = pthread_cond_timedwait(&hdrs_wait, &hdrs_lock, &tv);
    598     }
    599     if (rc == ETIMEDOUT) {
    600         LOGE("%s(): %s:%s:PortIndex %u: wokeup (buffer header timeout)\n",
    601              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    602              portdefinition.nPortIndex);
    603         ret = OMX_ErrorTimeout;
    604     }
    605     buffer_hdrs_completion = !buffer_hdrs_completion;
    606     pthread_mutex_unlock(&hdrs_lock);
    607     return ret;
    608 }
    609 
    610 /* Empty/FillThisBuffer */
    611 OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
    612 {
    613     int ret;
    614     LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %u:pBuffer %p:\n",
    615             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    616            portdefinition.nPortIndex, pBuffer);
    617     pthread_mutex_lock(&bufferq_lock);
    618     ret = queue_push_tail(&bufferq, pBuffer);
    619     pthread_mutex_unlock(&bufferq_lock);
    620 
    621     if (ret)
    622         return OMX_ErrorInsufficientResources;
    623 
    624     return OMX_ErrorNone;
    625 }
    626 
    627 OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void)
    628 {
    629     OMX_BUFFERHEADERTYPE *buffer;
    630 
    631     pthread_mutex_lock(&bufferq_lock);
    632     buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
    633     pthread_mutex_unlock(&bufferq_lock);
    634     LOGV_IF((buffer != NULL || RetainedBufferQueueLength() > 0), "%s(): %s:%s:PortIndex %u:pBuffer %p:\n",
    635             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    636             portdefinition.nPortIndex, buffer);
    637     return buffer;
    638 }
    639 
    640 OMX_U32 PortBase::BufferQueueLength(void)
    641 {
    642     OMX_U32 length;
    643 
    644     pthread_mutex_lock(&bufferq_lock);
    645     length = queue_length(&bufferq);
    646     pthread_mutex_unlock(&bufferq_lock);
    647 
    648     return length;
    649 }
    650 
    651 OMX_U32 PortBase::RetainedBufferQueueLength(void)
    652 {
    653     OMX_U32 length;
    654 
    655     pthread_mutex_lock(&retainedbufferq_lock);
    656     length = queue_length(&retainedbufferq);
    657     pthread_mutex_unlock(&retainedbufferq_lock);
    658 
    659     return length;
    660 }
    661 
    662 OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
    663 {
    664     OMX_DIRTYPE direction = portdefinition.eDir;
    665     OMX_U32 port_index;
    666     OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE,
    667                                          OMX_PTR,
    668                                          OMX_BUFFERHEADERTYPE *);
    669     OMX_ERRORTYPE ret;
    670 
    671     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter\n", __FUNCTION__,
    672          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
    673          pBuffer);
    674 
    675     if (!pBuffer) {
    676         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    677              "invalid buffer pointer\n",
    678              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    679              portdefinition.nPortIndex, pBuffer);
    680         return OMX_ErrorBadParameter;
    681     }
    682 
    683     if (direction == OMX_DirInput) {
    684         port_index = pBuffer->nInputPortIndex;
    685         bufferdone_callback = callbacks->EmptyBufferDone;
    686     }
    687     else if (direction == OMX_DirOutput) {
    688         port_index = pBuffer->nOutputPortIndex;
    689         bufferdone_callback = callbacks->FillBufferDone;
    690     }
    691     else {
    692         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    693              "invalid direction (%d)\n",
    694              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    695              portdefinition.nPortIndex, pBuffer,
    696              direction);
    697         return OMX_ErrorBadParameter;
    698     }
    699 
    700     if (port_index != portdefinition.nPortIndex) {
    701         LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    702              "invalid port index (%u)\n", __FUNCTION__,
    703              cbase->GetName(), cbase->GetWorkingRole(),
    704              portdefinition.nPortIndex, pBuffer, port_index);
    705         return OMX_ErrorBadParameter;
    706     }
    707 
    708     if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
    709         LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: "
    710              "Report OMX_EventBufferFlag (OMX_BUFFERFLAG_EOS)\n",
    711              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    712              portdefinition.nPortIndex, pBuffer);
    713 
    714         callbacks->EventHandler(owner, appdata,
    715                                 OMX_EventBufferFlag,
    716                                 port_index, pBuffer->nFlags, NULL);
    717     }
    718 
    719     if (pBuffer->hMarkTargetComponent == owner) {
    720         LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: "
    721              "Report OMX_EventMark\n",
    722              __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    723              portdefinition.nPortIndex, pBuffer);
    724 
    725         callbacks->EventHandler(owner, appdata, OMX_EventMark,
    726                                 0, 0, pBuffer->pMarkData);
    727         pBuffer->hMarkTargetComponent = NULL;
    728         pBuffer->pMarkData = NULL;
    729     }
    730 
    731     ret = bufferdone_callback(owner, appdata, pBuffer);
    732 
    733     LOGV("%s(): %s:%s:PortIndex %u: exit done, "
    734          "callback returned (0x%08x)\n", __FUNCTION__,
    735          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
    736          ret);
    737 
    738     return OMX_ErrorNone;
    739 }
    740 
    741 OMX_ERRORTYPE PortBase::RetainAndReturnBuffer( OMX_BUFFERHEADERTYPE *pRetain, OMX_BUFFERHEADERTYPE *pReturn)
    742 {
    743     OMX_ERRORTYPE ret;
    744     OMX_U32 length;
    745     if (pReturn == pRetain) {
    746         return ReturnThisBuffer(pReturn);
    747     }
    748     ret = RetainThisBuffer(pRetain, false);
    749     if (ret != OMX_ErrorNone) {
    750         return ret;
    751     }
    752 
    753     pthread_mutex_lock(&bufferq_lock);
    754     length = queue_length(&bufferq);
    755     OMX_BUFFERHEADERTYPE *p;
    756     /* remove returned buffer from the queue */
    757     OMX_U32 i = 0;
    758     for (i = 0; i < length; i++) {
    759         p = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
    760         if (p == pReturn) {
    761             break;
    762         }
    763         queue_push_tail(&bufferq, p);
    764     }
    765     pthread_mutex_unlock(&bufferq_lock);
    766 
    767     if (i == length) {
    768         return OMX_ErrorNone;
    769     }
    770 
    771     return ReturnThisBuffer(pReturn);
    772 }
    773 
    774 /* retain buffer */
    775 OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer,
    776         bool accumulate)
    777 {
    778     int ret;
    779 
    780     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter, %s\n", __FUNCTION__,
    781          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
    782          pBuffer, (accumulate == true) ? "accumulate" : "getagain");
    783 
    784     /* push at tail of retainedbufferq */
    785     if (accumulate == true) {
    786 
    787         if (cbase->GetWorkingRole() == NULL || (strncmp((char*)cbase->GetWorkingRole(), "video_encoder", 13) != 0)) {
    788             /* do not accumulate a buffer set EOS flag if not video encoder*/
    789             if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
    790                 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    791                      "cannot accumulate EOS buffer\n", __FUNCTION__,
    792                      cbase->GetName(), cbase->GetWorkingRole(),
    793                      portdefinition.nPortIndex, pBuffer);
    794                 return OMX_ErrorBadParameter;
    795             }
    796         }
    797 
    798         pthread_mutex_lock(&retainedbufferq_lock);
    799         if ((OMX_U32)queue_length(&retainedbufferq) <
    800                 portdefinition.nBufferCountActual)
    801             ret = queue_push_tail(&retainedbufferq, pBuffer);
    802         else {
    803             ret = OMX_ErrorInsufficientResources;
    804             LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    805                  "retained bufferq length (%d) exceeds port's actual count "
    806                  "(%u)\n", __FUNCTION__,
    807                  cbase->GetName(), cbase->GetWorkingRole(),
    808                  portdefinition.nPortIndex, pBuffer,
    809                  queue_length(&retainedbufferq),
    810                  portdefinition.nBufferCountActual);
    811         }
    812         pthread_mutex_unlock(&retainedbufferq_lock);
    813     }
    814     /*
    815      * just push at head of bufferq to get this buffer again in
    816      * ComponentBase::ProcessorProcess()
    817      */
    818     else {
    819         pthread_mutex_lock(&bufferq_lock);
    820         ret = queue_push_head(&bufferq, pBuffer);
    821         pthread_mutex_unlock(&bufferq_lock);
    822     }
    823 
    824     if (ret)
    825         return OMX_ErrorInsufficientResources;
    826 
    827     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: exit done\n", __FUNCTION__,
    828          cbase->GetName(), cbase->GetWorkingRole(),
    829          portdefinition.nPortIndex, pBuffer);
    830     return OMX_ErrorNone;
    831 }
    832 
    833 void PortBase::ReturnAllRetainedBuffers(void)
    834 {
    835     OMX_BUFFERHEADERTYPE *buffer;
    836     OMX_ERRORTYPE ret;
    837     int i = 0;
    838 
    839     pthread_mutex_lock(&retainedbufferq_lock);
    840 
    841     do {
    842         buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
    843 
    844         if (buffer) {
    845             LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
    846                  "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
    847                  cbase->GetWorkingRole(), portdefinition.nPortIndex,
    848                  buffer, i++, queue_length(&retainedbufferq));
    849 
    850             ret = ReturnThisBuffer(buffer);
    851             if (ret != OMX_ErrorNone)
    852                 LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
    853                      __FUNCTION__,
    854                      cbase->GetName(), cbase->GetWorkingRole(),
    855                      portdefinition.nPortIndex, ret);
    856         }
    857     } while (buffer);
    858 
    859     pthread_mutex_unlock(&retainedbufferq_lock);
    860     LOGV_IF(i != 0,
    861             "%s(): %s:%s:PortIndex %u: returned all retained buffers (%d)\n",
    862             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    863             portdefinition.nPortIndex, i);
    864 }
    865 
    866 void PortBase::ReturnOneRetainedBuffer(void)
    867 {
    868     OMX_BUFFERHEADERTYPE *buffer;
    869     OMX_ERRORTYPE ret;
    870     int i =0;
    871 
    872     pthread_mutex_lock(&retainedbufferq_lock);
    873 
    874     buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
    875 
    876     if (buffer) {
    877         LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
    878              "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
    879              cbase->GetWorkingRole(), portdefinition.nPortIndex,
    880              buffer, i++, queue_length(&retainedbufferq));
    881 
    882         ret = ReturnThisBuffer(buffer);
    883         if (ret != OMX_ErrorNone)
    884             LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
    885                  __FUNCTION__,
    886                  cbase->GetName(), cbase->GetWorkingRole(),
    887                  portdefinition.nPortIndex, ret);
    888     }
    889 
    890     pthread_mutex_unlock(&retainedbufferq_lock);
    891 
    892 }
    893 
    894 /* SendCommand:Flush/PortEnable/Disable */
    895 /* must be held ComponentBase::ports_block */
    896 OMX_ERRORTYPE PortBase::FlushPort(void)
    897 {
    898     OMX_BUFFERHEADERTYPE *buffer;
    899 
    900     LOGV("%s(): %s:%s:PortIndex %u: enter\n", __FUNCTION__,
    901          cbase->GetName(), cbase->GetWorkingRole(),
    902          portdefinition.nPortIndex);
    903 
    904     ReturnAllRetainedBuffers();
    905 
    906     while ((buffer = PopBuffer()))
    907         ReturnThisBuffer(buffer);
    908 
    909     LOGV("%s(): %s:%s:PortIndex %u: exit\n", __FUNCTION__,
    910          cbase->GetName(), cbase->GetWorkingRole(),
    911          portdefinition.nPortIndex);
    912 
    913     return OMX_ErrorNone;
    914 }
    915 
    916 OMX_STATETYPE PortBase::GetOwnerState(void)
    917 {
    918     OMX_STATETYPE state = OMX_StateInvalid;
    919 
    920     if (owner) {
    921         ComponentBase *cbase;
    922         cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
    923         if (!cbase)
    924             return state;
    925 
    926         cbase->CBaseGetState((void *)owner, &state);
    927     }
    928 
    929     return state;
    930 }
    931 
    932 bool PortBase::IsEnabled(void)
    933 {
    934     bool enabled;
    935     bool unlock = true;
    936 
    937     if (pthread_mutex_trylock(&state_lock))
    938         unlock = false;
    939 
    940     enabled = (state == OMX_PortEnabled) ? true : false;
    941 
    942     if (unlock)
    943         pthread_mutex_unlock(&state_lock);
    944 
    945     return enabled;
    946 }
    947 
    948 OMX_DIRTYPE PortBase::GetPortDirection(void)
    949 {
    950     return portdefinition.eDir;
    951 }
    952 
    953 OMX_U32 PortBase::GetPortBufferCount(void)
    954 {
    955     return nr_buffer_hdrs;
    956 }
    957 
    958 OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
    959 {
    960     int ret;
    961 
    962     pthread_mutex_lock(&markq_lock);
    963     ret = queue_push_tail(&markq, mark);
    964     pthread_mutex_unlock(&markq_lock);
    965 
    966     if (ret)
    967         return OMX_ErrorInsufficientResources;
    968 
    969     return OMX_ErrorNone;
    970 }
    971 
    972 OMX_MARKTYPE *PortBase::PopMark(void)
    973 {
    974     OMX_MARKTYPE *mark;
    975 
    976     pthread_mutex_lock(&markq_lock);
    977     mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
    978     pthread_mutex_unlock(&markq_lock);
    979 
    980     return mark;
    981 }
    982 
    983 static const char *state_name[PortBase::OMX_PortEnabled+2] = {
    984     "OMX_PortDisabled",
    985     "OMX_PortEnabled",
    986     "UnKnown Port State",
    987 };
    988 
    989 const char *GetPortStateName(OMX_U8 state)
    990 {
    991     if (state > PortBase::OMX_PortEnabled)
    992         state = PortBase::OMX_PortEnabled+1;
    993 
    994     return state_name[state];
    995 }
    996 
    997 OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
    998 {
    999     OMX_U8 current;
   1000     OMX_ERRORTYPE ret = OMX_ErrorNone;
   1001 
   1002     LOGV("%s(): %s:%s:PortIndex %u: enter, transition from %s to %s\n",
   1003          __FUNCTION__,
   1004          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
   1005          GetPortStateName(state), GetPortStateName(transition));
   1006 
   1007     pthread_mutex_lock(&state_lock);
   1008 
   1009     current = state;
   1010 
   1011     if (current == transition) {
   1012         ret = OMX_ErrorSameState;
   1013         LOGE("%s(): %s:%s:PortIndex %u: exit failure, same state (%s)\n",
   1014              __FUNCTION__,
   1015              cbase->GetName(), cbase->GetWorkingRole(),
   1016              portdefinition.nPortIndex, GetPortStateName(current));
   1017         goto unlock;
   1018     }
   1019 
   1020     if (transition == OMX_PortEnabled) {
   1021         if (cbase->GetWorkingRole() != NULL &&
   1022                 !strncmp (cbase->GetWorkingRole(),"video_decoder", 13 )) {
   1023             ret = WaitPortBufferCompletionTimeout(800); //0.8s timeout
   1024             if (!nr_buffer_hdrs) {
   1025                 // event is trigger by freeing buffer instead of allocating buffer
   1026                 ret = OMX_ErrorBadParameter;
   1027             }
   1028             if (ret != OMX_ErrorNone) {
   1029                 goto unlock;
   1030             }
   1031         } else {
   1032             WaitPortBufferCompletion();
   1033         }
   1034         portdefinition.bEnabled = OMX_TRUE;
   1035     }
   1036     else if(transition == OMX_PortDisabled) {
   1037         /*need to flush only if port is not empty*/
   1038         if (nr_buffer_hdrs)
   1039         {
   1040             FlushPort();
   1041             WaitPortBufferCompletion();
   1042         }
   1043         portdefinition.bEnabled = OMX_FALSE;
   1044     }
   1045     else {
   1046         ret = OMX_ErrorBadParameter;
   1047         LOGE("%s(): %s:%s:PortIndex %u: exit failure, invalid transition "
   1048              "(%s)\n", __FUNCTION__,
   1049              cbase->GetName(), cbase->GetWorkingRole(),
   1050              portdefinition.nPortIndex, GetPortStateName(transition));
   1051         goto unlock;
   1052     }
   1053 
   1054     state = transition;
   1055 
   1056     LOGV("%s(): %s:%s:PortIndex %u: transition from %s to %s complete\n",
   1057          __FUNCTION__,
   1058          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
   1059          GetPortStateName(current), GetPortStateName(state));
   1060 
   1061 unlock:
   1062     pthread_mutex_unlock(&state_lock);
   1063     return ret;
   1064 }
   1065 
   1066 OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void)
   1067 {
   1068     OMX_ERRORTYPE ret;
   1069 
   1070     ret = callbacks->EventHandler(owner, appdata,
   1071                                   OMX_EventPortSettingsChanged,
   1072                                   portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL);
   1073 
   1074     FlushPort();
   1075 
   1076     return ret;
   1077 }
   1078 
   1079 OMX_ERRORTYPE PortBase::ReportOutputCrop(void)
   1080 {
   1081     OMX_ERRORTYPE ret;
   1082 
   1083     ret = callbacks->EventHandler(owner, appdata,
   1084                                   OMX_EventPortSettingsChanged,
   1085                                   portdefinition.nPortIndex,OMX_IndexConfigCommonOutputCrop, NULL);
   1086 
   1087     return ret;
   1088 }
   1089 
   1090 
   1091 /* end of component methods & helpers */
   1092 
   1093 /* end of PortBase */
   1094