portbase.cpp revision 78c1837ebe200a58aebed8bad480064da909d6ff
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#include <OMX_VideoExt.h>
28//#define LOG_NDEBUG 0
29
30#define LOG_TAG "portbase"
31#include <log.h>
32
33/*
34 * constructor & destructor
35 */
36void PortBase::__PortBase(void)
37{
38    buffer_hdrs = NULL;
39    nr_buffer_hdrs = 0;
40    buffer_hdrs_completion = false;
41
42    custom_mem_alloc = NULL;
43    custom_mem_free = NULL;
44    custom_mem_userdata = NULL;
45
46    mem_alignment = 0;
47
48    pthread_mutex_init(&hdrs_lock, NULL);
49    pthread_cond_init(&hdrs_wait, NULL);
50
51    __queue_init(&bufferq);
52    pthread_mutex_init(&bufferq_lock, NULL);
53
54    __queue_init(&retainedbufferq);
55    pthread_mutex_init(&retainedbufferq_lock, NULL);
56
57    __queue_init(&markq);
58    pthread_mutex_init(&markq_lock, NULL);
59
60    state = OMX_PortEnabled;
61    pthread_mutex_init(&state_lock, NULL);
62
63    memset(&portdefinition, 0, sizeof(portdefinition));
64    ComponentBase::SetTypeHeader(&portdefinition, sizeof(portdefinition));
65    memset(definition_format_mimetype, 0, OMX_MAX_STRINGNAME_SIZE);
66    portdefinition.format.audio.cMIMEType = &definition_format_mimetype[0];
67    portdefinition.format.video.cMIMEType = &definition_format_mimetype[0];
68    portdefinition.format.image.cMIMEType = &definition_format_mimetype[0];
69
70    memset(&audioparam, 0, sizeof(audioparam));
71
72    owner = NULL;
73    appdata = NULL;
74    callbacks = NULL;
75
76    cbase = NULL;
77}
78
79PortBase::PortBase()
80{
81    __PortBase();
82}
83
84PortBase::PortBase(const OMX_PARAM_PORTDEFINITIONTYPE *portdefinition)
85{
86    __PortBase();
87    SetPortDefinition(portdefinition, true);
88}
89
90PortBase::~PortBase()
91{
92    struct list *entry, *temp;
93
94    /* should've been already freed at FreeBuffer() */
95    list_foreach_safe(buffer_hdrs, entry, temp) {
96        free(entry->data); /* OMX_BUFFERHEADERTYPE */
97        __list_delete(buffer_hdrs, entry);
98    }
99
100    pthread_cond_destroy(&hdrs_wait);
101    pthread_mutex_destroy(&hdrs_lock);
102
103    /* should've been already freed at buffer processing */
104    queue_free_all(&bufferq);
105    pthread_mutex_destroy(&bufferq_lock);
106
107    /* should've been already freed at buffer processing */
108    queue_free_all(&retainedbufferq);
109    pthread_mutex_destroy(&retainedbufferq_lock);
110
111    /* should've been already empty in PushThisBuffer () */
112    queue_free_all(&markq);
113    pthread_mutex_destroy(&markq_lock);
114
115    pthread_mutex_destroy(&state_lock);
116}
117
118/* end of constructor & destructor */
119
120/*
121 * accessor
122 */
123/* owner */
124void PortBase::SetOwner(OMX_COMPONENTTYPE *handle)
125{
126    owner = handle;
127    cbase = static_cast<ComponentBase *>(handle->pComponentPrivate);
128}
129
130OMX_COMPONENTTYPE *PortBase::GetOwner(void)
131{
132    return owner;
133}
134
135OMX_ERRORTYPE PortBase::SetCallbacks(OMX_HANDLETYPE hComponent,
136                                     OMX_CALLBACKTYPE *pCallbacks,
137                                     OMX_PTR pAppData)
138{
139    if (owner != hComponent)
140        return OMX_ErrorBadParameter;
141
142    appdata = pAppData;
143    callbacks = pCallbacks;
144
145    return OMX_ErrorNone;
146}
147
148OMX_ERRORTYPE PortBase::SetMemAllocator(CustomMemAlloc *pMemAlloc, CustomMemFree *pMemFree, OMX_PTR pUserData)
149{
150    custom_mem_alloc = pMemAlloc;
151    custom_mem_free = pMemFree;
152    custom_mem_userdata = pUserData;
153    return OMX_ErrorNone;
154}
155
156OMX_ERRORTYPE PortBase::SetMemAlignment(OMX_U32 nAlignment)
157{
158    mem_alignment = nAlignment;
159    return OMX_ErrorNone;
160}
161
162OMX_U32 PortBase::getFrameBufSize(OMX_COLOR_FORMATTYPE colorFormat, OMX_U32 width, OMX_U32 height)
163{
164    switch (colorFormat) {
165    case OMX_COLOR_FormatYCbYCr:
166    case OMX_COLOR_FormatCbYCrY:
167        return width * height * 2;
168    case OMX_COLOR_FormatYUV420Planar:
169    case OMX_COLOR_FormatYUV420SemiPlanar:
170        return (width * height * 3) >> 1;
171    case OMX_COLOR_FormatUnused:
172        return (width * height * 3) >> 1;
173
174    default:
175        LOGV("unsupport color format !");
176        return -1;
177    }
178}
179
180/* end of accessor */
181
182/*
183 * component methods & helpers
184 */
185/* Get/SetParameter */
186OMX_ERRORTYPE PortBase::SetPortDefinition(
187    const OMX_PARAM_PORTDEFINITIONTYPE *p, bool overwrite_readonly)
188{
189    OMX_PARAM_PORTDEFINITIONTYPE temp;
190
191    memcpy(&temp, &portdefinition, sizeof(temp));
192
193    if (!overwrite_readonly) {
194        if (temp.nPortIndex != p->nPortIndex)
195            return OMX_ErrorBadParameter;
196        if (temp.eDir != p->eDir)
197            return OMX_ErrorBadParameter;
198        if (temp.eDomain != p->eDomain)
199            return OMX_ErrorBadParameter;
200        if (temp.nBufferCountActual != p->nBufferCountActual) {
201            if (temp.nBufferCountMin > p->nBufferCountActual)
202                return OMX_ErrorBadParameter;
203            temp.nBufferCountActual = p->nBufferCountActual;
204        }
205        if ((p->nBufferSize > temp.nBufferSize) && (temp.eDir == OMX_DirInput)) {
206            if (p->nBufferSize <= MAX_INPUT_PORT_SIZE) {
207                LOGW("Input port size has been changed!");
208                temp.nBufferSize = p->nBufferSize;
209            } else {
210                LOGE("Invalid input port size!");
211                return OMX_ErrorBadParameter;
212            }
213        }
214    }
215    else {
216        temp.nPortIndex = p->nPortIndex;
217        temp.eDir = p->eDir;
218        temp.nBufferCountActual = p->nBufferCountActual;
219        temp.nBufferCountMin = p->nBufferCountMin;
220        temp.nBufferSize = p->nBufferSize;
221        temp.bEnabled = p->bEnabled;
222        temp.bPopulated = p->bPopulated;
223        temp.eDomain = p->eDomain;
224        temp.bBuffersContiguous = p->bBuffersContiguous;
225        temp.nBufferAlignment = p->nBufferAlignment;
226    }
227
228    switch (p->eDomain) {
229    case OMX_PortDomainAudio: {
230        OMX_AUDIO_PORTDEFINITIONTYPE *format = &temp.format.audio;
231        const OMX_AUDIO_PORTDEFINITIONTYPE *pformat = &p->format.audio;
232        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
233
234        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
235                       mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
236
237        strncpy(format->cMIMEType, pformat->cMIMEType,
238                mimetype_len);
239        format->cMIMEType[mimetype_len+1] = '\0';
240        format->pNativeRender = pformat->pNativeRender;
241        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
242        format->eEncoding = pformat->eEncoding;
243
244        break;
245    }
246    case OMX_PortDomainVideo: {
247        OMX_VIDEO_PORTDEFINITIONTYPE *format = &temp.format.video;
248        const OMX_VIDEO_PORTDEFINITIONTYPE *pformat = &p->format.video;
249        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
250
251        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
252                       mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
253
254        strncpy(format->cMIMEType, pformat->cMIMEType,
255                mimetype_len);
256        format->cMIMEType[mimetype_len+1] = '\0';
257        format->pNativeRender = pformat->pNativeRender;
258        format->nFrameWidth = pformat->nFrameWidth;
259        format->nFrameHeight = pformat->nFrameHeight;
260        format->nBitrate = pformat->nBitrate;
261        format->xFramerate = pformat->xFramerate;
262        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
263        format->eCompressionFormat = pformat->eCompressionFormat;
264        format->eColorFormat = pformat->eColorFormat;
265        format->pNativeWindow = pformat->pNativeWindow;
266        OMX_U32 nFrameSize = getFrameBufSize(format->eColorFormat,format->nFrameWidth,format->nFrameHeight);
267        if(nFrameSize!=-1)
268            temp.nBufferSize = nFrameSize;
269        if (overwrite_readonly) {
270            format->nStride = pformat->nStride;
271            format->nSliceHeight = pformat->nSliceHeight;
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
316const OMX_PARAM_PORTDEFINITIONTYPE *PortBase::GetPortDefinition(void)
317{
318    return &portdefinition;
319}
320
321/* Use/Allocate/FreeBuffer */
322OMX_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 %lu: enter, nSizeBytes=%lu\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 %lu: 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 %lu: 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 %lu: 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 %lu: a buffer allocated (%p:%lu/%lu)\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 %lu: allocate all buffers (%lu)\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 %lu: exit done\n", __FUNCTION__,
400         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
401    return OMX_ErrorNone;
402}
403
404OMX_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 %lu: enter, nSizeBytes=%lu\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 %lu: 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 %lu: 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 %lu: 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 %lu: a buffer allocated (%p:%lu/%lu)\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 %lu: allocate all buffers (%lu)\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 %lu: exit done\n", __FUNCTION__,
499         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
500    return OMX_ErrorNone;
501}
502
503OMX_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 %lu: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 %lu: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 %lu: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 %lu: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 %lu:pBuffer %p: free a buffer (%lu/%lu)\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 %lu: free all allocated buffers (%lu)\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 %lu: exit done\n", __FUNCTION__,
564         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
565    return OMX_ErrorNone;
566}
567
568void PortBase::WaitPortBufferCompletion(void)
569{
570    pthread_mutex_lock(&hdrs_lock);
571    if (!buffer_hdrs_completion) {
572        LOGV("%s(): %s:%s:PortIndex %lu: 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 %lu: 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/* Empty/FillThisBuffer */
585OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
586{
587    int ret;
588
589    LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
590            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
591            portdefinition.nPortIndex, pBuffer);
592
593    pthread_mutex_lock(&bufferq_lock);
594    ret = queue_push_tail(&bufferq, pBuffer);
595    pthread_mutex_unlock(&bufferq_lock);
596
597    if (ret)
598        return OMX_ErrorInsufficientResources;
599
600    return OMX_ErrorNone;
601}
602
603OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void)
604{
605    OMX_BUFFERHEADERTYPE *buffer;
606
607    pthread_mutex_lock(&bufferq_lock);
608    buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
609    pthread_mutex_unlock(&bufferq_lock);
610
611    LOGV_IF(buffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
612            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
613            portdefinition.nPortIndex, buffer);
614
615    return buffer;
616}
617
618OMX_U32 PortBase::BufferQueueLength(void)
619{
620    OMX_U32 length;
621
622    pthread_mutex_lock(&bufferq_lock);
623    length = queue_length(&bufferq);
624    pthread_mutex_unlock(&bufferq_lock);
625
626    return length;
627}
628
629OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
630{
631    OMX_DIRTYPE direction = portdefinition.eDir;
632    OMX_U32 port_index;
633    OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE,
634                                         OMX_PTR,
635                                         OMX_BUFFERHEADERTYPE *);
636    OMX_ERRORTYPE ret;
637
638    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: enter\n", __FUNCTION__,
639         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
640         pBuffer);
641
642    if (!pBuffer) {
643        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
644             "invalid buffer pointer\n",
645             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
646             portdefinition.nPortIndex, pBuffer);
647        return OMX_ErrorBadParameter;
648    }
649
650    if (direction == OMX_DirInput) {
651        port_index = pBuffer->nInputPortIndex;
652        bufferdone_callback = callbacks->EmptyBufferDone;
653    }
654    else if (direction == OMX_DirOutput) {
655        port_index = pBuffer->nOutputPortIndex;
656        bufferdone_callback = callbacks->FillBufferDone;
657    }
658    else {
659        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
660             "invalid direction (%d)\n",
661             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
662             portdefinition.nPortIndex, pBuffer,
663             direction);
664        return OMX_ErrorBadParameter;
665    }
666
667    if (port_index != portdefinition.nPortIndex) {
668        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
669             "invalid port index (%lu)\n", __FUNCTION__,
670             cbase->GetName(), cbase->GetWorkingRole(),
671             portdefinition.nPortIndex, pBuffer, port_index);
672        return OMX_ErrorBadParameter;
673    }
674
675    if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
676        LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: "
677             "Report OMX_EventBufferFlag (OMX_BUFFERFLAG_EOS)\n",
678             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
679             portdefinition.nPortIndex, pBuffer);
680
681        callbacks->EventHandler(owner, appdata,
682                                OMX_EventBufferFlag,
683                                port_index, pBuffer->nFlags, NULL);
684    }
685
686    if (pBuffer->hMarkTargetComponent == owner) {
687        LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: "
688             "Report OMX_EventMark\n",
689             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
690             portdefinition.nPortIndex, pBuffer);
691
692        callbacks->EventHandler(owner, appdata, OMX_EventMark,
693                                0, 0, pBuffer->pMarkData);
694        pBuffer->hMarkTargetComponent = NULL;
695        pBuffer->pMarkData = NULL;
696    }
697
698    ret = bufferdone_callback(owner, appdata, pBuffer);
699
700    LOGV("%s(): %s:%s:PortIndex %lu: exit done, "
701         "callback returned (0x%08x)\n", __FUNCTION__,
702         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
703         ret);
704
705    return OMX_ErrorNone;
706}
707
708OMX_ERRORTYPE PortBase::RetainAndReturnBuffer( OMX_BUFFERHEADERTYPE *pRetain, OMX_BUFFERHEADERTYPE *pReturn)
709{
710    OMX_ERRORTYPE ret;
711    OMX_U32 length;
712    if (pReturn == pRetain) {
713        return ReturnThisBuffer(pReturn);
714    }
715    ret = RetainThisBuffer(pRetain, false);
716    if (ret != OMX_ErrorNone) {
717        return ret;
718    }
719
720    pthread_mutex_lock(&bufferq_lock);
721    length = queue_length(&bufferq);
722    OMX_BUFFERHEADERTYPE *p;
723    /* remove returned buffer from the queue */
724    for (OMX_U32 i = 0; i < length; i++) {
725        p = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
726        if (p == pReturn) {
727            break;
728        }
729        queue_push_tail(&bufferq, p);
730    }
731
732    pthread_mutex_unlock(&bufferq_lock);
733
734    return ReturnThisBuffer(pReturn);
735}
736
737/* retain buffer */
738OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer,
739        bool accumulate)
740{
741    int ret;
742
743    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: enter, %s\n", __FUNCTION__,
744         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
745         pBuffer, (accumulate == true) ? "accumulate" : "getagain");
746
747    /* push at tail of retainedbufferq */
748    if (accumulate == true) {
749        /* do not accumulate a buffer set EOS flag */
750        if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
751            LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
752                 "cannot accumulate EOS buffer\n", __FUNCTION__,
753                 cbase->GetName(), cbase->GetWorkingRole(),
754                 portdefinition.nPortIndex, pBuffer);
755            return OMX_ErrorBadParameter;
756        }
757
758        pthread_mutex_lock(&retainedbufferq_lock);
759        if ((OMX_U32)queue_length(&retainedbufferq) <
760                portdefinition.nBufferCountActual)
761            ret = queue_push_tail(&retainedbufferq, pBuffer);
762        else {
763            ret = OMX_ErrorInsufficientResources;
764            LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
765                 "retained bufferq length (%d) exceeds port's actual count "
766                 "(%lu)\n", __FUNCTION__,
767                 cbase->GetName(), cbase->GetWorkingRole(),
768                 portdefinition.nPortIndex, pBuffer,
769                 queue_length(&retainedbufferq),
770                 portdefinition.nBufferCountActual);
771        }
772        pthread_mutex_unlock(&retainedbufferq_lock);
773    }
774    /*
775     * just push at head of bufferq to get this buffer again in
776     * ComponentBase::ProcessorProcess()
777     */
778    else {
779        pthread_mutex_lock(&bufferq_lock);
780        ret = queue_push_head(&bufferq, pBuffer);
781        pthread_mutex_unlock(&bufferq_lock);
782    }
783
784    if (ret)
785        return OMX_ErrorInsufficientResources;
786
787    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit done\n", __FUNCTION__,
788         cbase->GetName(), cbase->GetWorkingRole(),
789         portdefinition.nPortIndex, pBuffer);
790    return OMX_ErrorNone;
791}
792
793void PortBase::ReturnAllRetainedBuffers(void)
794{
795    OMX_BUFFERHEADERTYPE *buffer;
796    OMX_ERRORTYPE ret;
797    int i = 0;
798
799    pthread_mutex_lock(&retainedbufferq_lock);
800
801    do {
802        buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
803
804        if (buffer) {
805            LOGV("%s(): %s:%s:PortIndex %lu: returns a retained buffer "
806                 "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
807                 cbase->GetWorkingRole(), portdefinition.nPortIndex,
808                 buffer, i++, queue_length(&retainedbufferq));
809
810            ret = ReturnThisBuffer(buffer);
811            if (ret != OMX_ErrorNone)
812                LOGE("%s(): %s:%s:PortIndex %lu: failed (ret : 0x%x08x)\n",
813                     __FUNCTION__,
814                     cbase->GetName(), cbase->GetWorkingRole(),
815                     portdefinition.nPortIndex, ret);
816        }
817    } while (buffer);
818
819    pthread_mutex_unlock(&retainedbufferq_lock);
820
821    LOGV_IF(i != 0,
822            "%s(): %s:%s:PortIndex %lu: returned all retained buffers (%d)\n",
823            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
824            portdefinition.nPortIndex, i);
825}
826
827/* SendCommand:Flush/PortEnable/Disable */
828/* must be held ComponentBase::ports_block */
829OMX_ERRORTYPE PortBase::FlushPort(void)
830{
831    OMX_BUFFERHEADERTYPE *buffer;
832
833    LOGV("%s(): %s:%s:PortIndex %lu: enter\n", __FUNCTION__,
834         cbase->GetName(), cbase->GetWorkingRole(),
835         portdefinition.nPortIndex);
836
837    ReturnAllRetainedBuffers();
838
839    while ((buffer = PopBuffer()))
840        ReturnThisBuffer(buffer);
841
842    LOGV("%s(): %s:%s:PortIndex %lu: exit\n", __FUNCTION__,
843         cbase->GetName(), cbase->GetWorkingRole(),
844         portdefinition.nPortIndex);
845
846    return OMX_ErrorNone;
847}
848
849OMX_STATETYPE PortBase::GetOwnerState(void)
850{
851    OMX_STATETYPE state = OMX_StateInvalid;
852
853    if (owner) {
854        ComponentBase *cbase;
855        cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
856        if (!cbase)
857            return state;
858
859        cbase->CBaseGetState((void *)owner, &state);
860    }
861
862    return state;
863}
864
865bool PortBase::IsEnabled(void)
866{
867    bool enabled;
868    bool unlock = true;
869
870    if (pthread_mutex_trylock(&state_lock))
871        unlock = false;
872
873    enabled = (state == OMX_PortEnabled) ? true : false;
874
875    if (unlock)
876        pthread_mutex_unlock(&state_lock);
877
878    return enabled;
879}
880
881OMX_DIRTYPE PortBase::GetPortDirection(void)
882{
883    return portdefinition.eDir;
884}
885
886OMX_U32 PortBase::GetPortBufferCount(void)
887{
888    return nr_buffer_hdrs;
889}
890
891OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
892{
893    int ret;
894
895    pthread_mutex_lock(&markq_lock);
896    ret = queue_push_tail(&markq, mark);
897    pthread_mutex_unlock(&markq_lock);
898
899    if (ret)
900        return OMX_ErrorInsufficientResources;
901
902    return OMX_ErrorNone;
903}
904
905OMX_MARKTYPE *PortBase::PopMark(void)
906{
907    OMX_MARKTYPE *mark;
908
909    pthread_mutex_lock(&markq_lock);
910    mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
911    pthread_mutex_unlock(&markq_lock);
912
913    return mark;
914}
915
916static const char *state_name[PortBase::OMX_PortEnabled+2] = {
917    "OMX_PortDisabled",
918    "OMX_PortEnabled",
919    "UnKnown Port State",
920};
921
922const char *GetPortStateName(OMX_U8 state)
923{
924    if (state > PortBase::OMX_PortEnabled)
925        state = PortBase::OMX_PortEnabled+1;
926
927    return state_name[state];
928}
929
930OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
931{
932    OMX_U8 current;
933    OMX_ERRORTYPE ret = OMX_ErrorNone;
934
935    LOGV("%s(): %s:%s:PortIndex %lu: enter, transition from %s to %s\n",
936         __FUNCTION__,
937         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
938         GetPortStateName(state), GetPortStateName(transition));
939
940    pthread_mutex_lock(&state_lock);
941
942    current = state;
943
944    if (current == transition) {
945        ret = OMX_ErrorSameState;
946        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, same state (%s)\n",
947             __FUNCTION__,
948             cbase->GetName(), cbase->GetWorkingRole(),
949             portdefinition.nPortIndex, GetPortStateName(current));
950        goto unlock;
951    }
952
953    if (transition == OMX_PortEnabled) {
954        WaitPortBufferCompletion();
955        portdefinition.bEnabled = OMX_TRUE;
956    }
957    else if(transition == OMX_PortDisabled) {
958        /*need to flush only if port is not empty*/
959        if (nr_buffer_hdrs)
960        {
961            FlushPort();
962            WaitPortBufferCompletion();
963        }
964        portdefinition.bEnabled = OMX_FALSE;
965    }
966    else {
967        ret = OMX_ErrorBadParameter;
968        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, invalid transition "
969             "(%s)\n", __FUNCTION__,
970             cbase->GetName(), cbase->GetWorkingRole(),
971             portdefinition.nPortIndex, GetPortStateName(transition));
972        goto unlock;
973    }
974
975    state = transition;
976
977    LOGV("%s(): %s:%s:PortIndex %lu: transition from %s to %s complete\n",
978         __FUNCTION__,
979         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
980         GetPortStateName(current), GetPortStateName(state));
981
982unlock:
983    pthread_mutex_unlock(&state_lock);
984    return ret;
985}
986
987OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void)
988{
989    OMX_ERRORTYPE ret;
990
991    ret = callbacks->EventHandler(owner, appdata,
992                                  OMX_EventPortSettingsChanged,
993                                  portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL);
994
995    FlushPort();
996
997    return ret;
998}
999
1000OMX_ERRORTYPE PortBase::ReportOutputCrop(void)
1001{
1002    OMX_ERRORTYPE ret;
1003
1004    ret = callbacks->EventHandler(owner, appdata,
1005                                  OMX_EventPortSettingsChanged,
1006                                  portdefinition.nPortIndex,OMX_IndexConfigCommonOutputCrop, NULL);
1007
1008    return ret;
1009}
1010
1011
1012/* end of component methods & helpers */
1013
1014/* end of PortBase */
1015