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     for (OMX_U32 i = 0; i < length; i++) {
    758         p = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
    759         if (p == pReturn) {
    760             break;
    761         }
    762         queue_push_tail(&bufferq, p);
    763     }
    764 
    765     pthread_mutex_unlock(&bufferq_lock);
    766 
    767     return ReturnThisBuffer(pReturn);
    768 }
    769 
    770 /* retain buffer */
    771 OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer,
    772         bool accumulate)
    773 {
    774     int ret;
    775 
    776     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter, %s\n", __FUNCTION__,
    777          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
    778          pBuffer, (accumulate == true) ? "accumulate" : "getagain");
    779 
    780     /* push at tail of retainedbufferq */
    781     if (accumulate == true) {
    782 
    783         if (cbase->GetWorkingRole() == NULL || (strncmp((char*)cbase->GetWorkingRole(), "video_encoder", 13) != 0)) {
    784             /* do not accumulate a buffer set EOS flag if not video encoder*/
    785             if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
    786                 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    787                      "cannot accumulate EOS buffer\n", __FUNCTION__,
    788                      cbase->GetName(), cbase->GetWorkingRole(),
    789                      portdefinition.nPortIndex, pBuffer);
    790                 return OMX_ErrorBadParameter;
    791             }
    792         }
    793 
    794         pthread_mutex_lock(&retainedbufferq_lock);
    795         if ((OMX_U32)queue_length(&retainedbufferq) <
    796                 portdefinition.nBufferCountActual)
    797             ret = queue_push_tail(&retainedbufferq, pBuffer);
    798         else {
    799             ret = OMX_ErrorInsufficientResources;
    800             LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
    801                  "retained bufferq length (%d) exceeds port's actual count "
    802                  "(%u)\n", __FUNCTION__,
    803                  cbase->GetName(), cbase->GetWorkingRole(),
    804                  portdefinition.nPortIndex, pBuffer,
    805                  queue_length(&retainedbufferq),
    806                  portdefinition.nBufferCountActual);
    807         }
    808         pthread_mutex_unlock(&retainedbufferq_lock);
    809     }
    810     /*
    811      * just push at head of bufferq to get this buffer again in
    812      * ComponentBase::ProcessorProcess()
    813      */
    814     else {
    815         pthread_mutex_lock(&bufferq_lock);
    816         ret = queue_push_head(&bufferq, pBuffer);
    817         pthread_mutex_unlock(&bufferq_lock);
    818     }
    819 
    820     if (ret)
    821         return OMX_ErrorInsufficientResources;
    822 
    823     LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: exit done\n", __FUNCTION__,
    824          cbase->GetName(), cbase->GetWorkingRole(),
    825          portdefinition.nPortIndex, pBuffer);
    826     return OMX_ErrorNone;
    827 }
    828 
    829 void PortBase::ReturnAllRetainedBuffers(void)
    830 {
    831     OMX_BUFFERHEADERTYPE *buffer;
    832     OMX_ERRORTYPE ret;
    833     int i = 0;
    834 
    835     pthread_mutex_lock(&retainedbufferq_lock);
    836 
    837     do {
    838         buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
    839 
    840         if (buffer) {
    841             LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
    842                  "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
    843                  cbase->GetWorkingRole(), portdefinition.nPortIndex,
    844                  buffer, i++, queue_length(&retainedbufferq));
    845 
    846             ret = ReturnThisBuffer(buffer);
    847             if (ret != OMX_ErrorNone)
    848                 LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
    849                      __FUNCTION__,
    850                      cbase->GetName(), cbase->GetWorkingRole(),
    851                      portdefinition.nPortIndex, ret);
    852         }
    853     } while (buffer);
    854 
    855     pthread_mutex_unlock(&retainedbufferq_lock);
    856     LOGV_IF(i != 0,
    857             "%s(): %s:%s:PortIndex %u: returned all retained buffers (%d)\n",
    858             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
    859             portdefinition.nPortIndex, i);
    860 }
    861 
    862 void PortBase::ReturnOneRetainedBuffer(void)
    863 {
    864     OMX_BUFFERHEADERTYPE *buffer;
    865     OMX_ERRORTYPE ret;
    866     int i =0;
    867 
    868     pthread_mutex_lock(&retainedbufferq_lock);
    869 
    870     buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
    871 
    872     if (buffer) {
    873         LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
    874              "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
    875              cbase->GetWorkingRole(), portdefinition.nPortIndex,
    876              buffer, i++, queue_length(&retainedbufferq));
    877 
    878         ret = ReturnThisBuffer(buffer);
    879         if (ret != OMX_ErrorNone)
    880             LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
    881                  __FUNCTION__,
    882                  cbase->GetName(), cbase->GetWorkingRole(),
    883                  portdefinition.nPortIndex, ret);
    884     }
    885 
    886     pthread_mutex_unlock(&retainedbufferq_lock);
    887 
    888 }
    889 
    890 /* SendCommand:Flush/PortEnable/Disable */
    891 /* must be held ComponentBase::ports_block */
    892 OMX_ERRORTYPE PortBase::FlushPort(void)
    893 {
    894     OMX_BUFFERHEADERTYPE *buffer;
    895 
    896     LOGV("%s(): %s:%s:PortIndex %u: enter\n", __FUNCTION__,
    897          cbase->GetName(), cbase->GetWorkingRole(),
    898          portdefinition.nPortIndex);
    899 
    900     ReturnAllRetainedBuffers();
    901 
    902     while ((buffer = PopBuffer()))
    903         ReturnThisBuffer(buffer);
    904 
    905     LOGV("%s(): %s:%s:PortIndex %u: exit\n", __FUNCTION__,
    906          cbase->GetName(), cbase->GetWorkingRole(),
    907          portdefinition.nPortIndex);
    908 
    909     return OMX_ErrorNone;
    910 }
    911 
    912 OMX_STATETYPE PortBase::GetOwnerState(void)
    913 {
    914     OMX_STATETYPE state = OMX_StateInvalid;
    915 
    916     if (owner) {
    917         ComponentBase *cbase;
    918         cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
    919         if (!cbase)
    920             return state;
    921 
    922         cbase->CBaseGetState((void *)owner, &state);
    923     }
    924 
    925     return state;
    926 }
    927 
    928 bool PortBase::IsEnabled(void)
    929 {
    930     bool enabled;
    931     bool unlock = true;
    932 
    933     if (pthread_mutex_trylock(&state_lock))
    934         unlock = false;
    935 
    936     enabled = (state == OMX_PortEnabled) ? true : false;
    937 
    938     if (unlock)
    939         pthread_mutex_unlock(&state_lock);
    940 
    941     return enabled;
    942 }
    943 
    944 OMX_DIRTYPE PortBase::GetPortDirection(void)
    945 {
    946     return portdefinition.eDir;
    947 }
    948 
    949 OMX_U32 PortBase::GetPortBufferCount(void)
    950 {
    951     return nr_buffer_hdrs;
    952 }
    953 
    954 OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
    955 {
    956     int ret;
    957 
    958     pthread_mutex_lock(&markq_lock);
    959     ret = queue_push_tail(&markq, mark);
    960     pthread_mutex_unlock(&markq_lock);
    961 
    962     if (ret)
    963         return OMX_ErrorInsufficientResources;
    964 
    965     return OMX_ErrorNone;
    966 }
    967 
    968 OMX_MARKTYPE *PortBase::PopMark(void)
    969 {
    970     OMX_MARKTYPE *mark;
    971 
    972     pthread_mutex_lock(&markq_lock);
    973     mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
    974     pthread_mutex_unlock(&markq_lock);
    975 
    976     return mark;
    977 }
    978 
    979 static const char *state_name[PortBase::OMX_PortEnabled+2] = {
    980     "OMX_PortDisabled",
    981     "OMX_PortEnabled",
    982     "UnKnown Port State",
    983 };
    984 
    985 const char *GetPortStateName(OMX_U8 state)
    986 {
    987     if (state > PortBase::OMX_PortEnabled)
    988         state = PortBase::OMX_PortEnabled+1;
    989 
    990     return state_name[state];
    991 }
    992 
    993 OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
    994 {
    995     OMX_U8 current;
    996     OMX_ERRORTYPE ret = OMX_ErrorNone;
    997 
    998     LOGV("%s(): %s:%s:PortIndex %u: enter, transition from %s to %s\n",
    999          __FUNCTION__,
   1000          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
   1001          GetPortStateName(state), GetPortStateName(transition));
   1002 
   1003     pthread_mutex_lock(&state_lock);
   1004 
   1005     current = state;
   1006 
   1007     if (current == transition) {
   1008         ret = OMX_ErrorSameState;
   1009         LOGE("%s(): %s:%s:PortIndex %u: exit failure, same state (%s)\n",
   1010              __FUNCTION__,
   1011              cbase->GetName(), cbase->GetWorkingRole(),
   1012              portdefinition.nPortIndex, GetPortStateName(current));
   1013         goto unlock;
   1014     }
   1015 
   1016     if (transition == OMX_PortEnabled) {
   1017         if (cbase->GetWorkingRole() != NULL &&
   1018                 !strncmp (cbase->GetWorkingRole(),"video_decoder", 13 )) {
   1019             ret = WaitPortBufferCompletionTimeout(800); //0.8s timeout
   1020             if (!nr_buffer_hdrs) {
   1021                 // event is trigger by freeing buffer instead of allocating buffer
   1022                 ret = OMX_ErrorBadParameter;
   1023             }
   1024             if (ret != OMX_ErrorNone) {
   1025                 goto unlock;
   1026             }
   1027         } else {
   1028             WaitPortBufferCompletion();
   1029         }
   1030         portdefinition.bEnabled = OMX_TRUE;
   1031     }
   1032     else if(transition == OMX_PortDisabled) {
   1033         /*need to flush only if port is not empty*/
   1034         if (nr_buffer_hdrs)
   1035         {
   1036             FlushPort();
   1037             WaitPortBufferCompletion();
   1038         }
   1039         portdefinition.bEnabled = OMX_FALSE;
   1040     }
   1041     else {
   1042         ret = OMX_ErrorBadParameter;
   1043         LOGE("%s(): %s:%s:PortIndex %u: exit failure, invalid transition "
   1044              "(%s)\n", __FUNCTION__,
   1045              cbase->GetName(), cbase->GetWorkingRole(),
   1046              portdefinition.nPortIndex, GetPortStateName(transition));
   1047         goto unlock;
   1048     }
   1049 
   1050     state = transition;
   1051 
   1052     LOGV("%s(): %s:%s:PortIndex %u: transition from %s to %s complete\n",
   1053          __FUNCTION__,
   1054          cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
   1055          GetPortStateName(current), GetPortStateName(state));
   1056 
   1057 unlock:
   1058     pthread_mutex_unlock(&state_lock);
   1059     return ret;
   1060 }
   1061 
   1062 OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void)
   1063 {
   1064     OMX_ERRORTYPE ret;
   1065 
   1066     ret = callbacks->EventHandler(owner, appdata,
   1067                                   OMX_EventPortSettingsChanged,
   1068                                   portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL);
   1069 
   1070     FlushPort();
   1071 
   1072     return ret;
   1073 }
   1074 
   1075 OMX_ERRORTYPE PortBase::ReportOutputCrop(void)
   1076 {
   1077     OMX_ERRORTYPE ret;
   1078 
   1079     ret = callbacks->EventHandler(owner, appdata,
   1080                                   OMX_EventPortSettingsChanged,
   1081                                   portdefinition.nPortIndex,OMX_IndexConfigCommonOutputCrop, NULL);
   1082 
   1083     return ret;
   1084 }
   1085 
   1086 
   1087 /* end of component methods & helpers */
   1088 
   1089 /* end of PortBase */
   1090