portbase.cpp revision 34277d8b1ca48a932e7b17ba331c29f040ba0838
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
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    pthread_mutex_init(&hdrs_lock, NULL);
43    pthread_cond_init(&hdrs_wait, NULL);
44
45    __queue_init(&bufferq);
46    pthread_mutex_init(&bufferq_lock, NULL);
47
48    __queue_init(&mixbufferq);
49    pthread_mutex_init(&mixbufferq_lock, NULL);
50
51    __queue_init(&retainedbufferq);
52    pthread_mutex_init(&retainedbufferq_lock, NULL);
53
54    __queue_init(&markq);
55    pthread_mutex_init(&markq_lock, NULL);
56
57    state = OMX_PortEnabled;
58    pthread_mutex_init(&state_lock, NULL);
59
60    memset(&portdefinition, 0, sizeof(portdefinition));
61    ComponentBase::SetTypeHeader(&portdefinition, sizeof(portdefinition));
62    memset(definition_format_mimetype, 0, OMX_MAX_STRINGNAME_SIZE);
63    portdefinition.format.audio.cMIMEType = &definition_format_mimetype[0];
64    portdefinition.format.video.cMIMEType = &definition_format_mimetype[0];
65    portdefinition.format.image.cMIMEType = &definition_format_mimetype[0];
66
67    memset(&audioparam, 0, sizeof(audioparam));
68
69    owner = NULL;
70    appdata = NULL;
71    callbacks = NULL;
72
73    cbase = NULL;
74}
75
76PortBase::PortBase()
77{
78    __PortBase();
79}
80
81PortBase::PortBase(const OMX_PARAM_PORTDEFINITIONTYPE *portdefinition)
82{
83    __PortBase();
84    SetPortDefinition(portdefinition, true);
85}
86
87PortBase::~PortBase()
88{
89    struct list *entry, *temp;
90
91    /* should've been already freed at FreeBuffer() */
92    list_foreach_safe(buffer_hdrs, entry, temp) {
93        free(entry->data); /* OMX_BUFFERHEADERTYPE */
94        __list_delete(buffer_hdrs, entry);
95    }
96
97    pthread_cond_destroy(&hdrs_wait);
98    pthread_mutex_destroy(&hdrs_lock);
99
100    /* should've been already freed at buffer processing */
101    queue_free_all(&bufferq);
102    pthread_mutex_destroy(&bufferq_lock);
103
104    queue_free_all(&mixbufferq);
105    pthread_mutex_destroy(&mixbufferq_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
148
149OMX_U32 PortBase::getFrameBufSize(OMX_COLOR_FORMATTYPE colorFormat, OMX_U32 width, OMX_U32 height)
150{
151    switch (colorFormat) {
152    case OMX_COLOR_FormatYCbYCr:
153    case OMX_COLOR_FormatCbYCrY:
154        return width * height * 2;
155    case OMX_COLOR_FormatYUV420Planar:
156    case OMX_COLOR_FormatYUV420SemiPlanar:
157        return (width * height * 3) >> 1;
158    default:
159        LOGV("unsupport color format !");
160        return -1;
161    }
162}
163
164/* end of accessor */
165
166/*
167 * component methods & helpers
168 */
169/* Get/SetParameter */
170OMX_ERRORTYPE PortBase::SetPortDefinition(
171    const OMX_PARAM_PORTDEFINITIONTYPE *p, bool overwrite_readonly)
172{
173    OMX_PARAM_PORTDEFINITIONTYPE temp;
174
175    memcpy(&temp, &portdefinition, sizeof(temp));
176
177    if (!overwrite_readonly) {
178        if (temp.nPortIndex != p->nPortIndex)
179            return OMX_ErrorBadParameter;
180        if (temp.eDir != p->eDir)
181            return OMX_ErrorBadParameter;
182        if (temp.eDomain != p->eDomain)
183            return OMX_ErrorBadParameter;
184        if (temp.nBufferCountActual != p->nBufferCountActual) {
185            if (temp.nBufferCountMin > p->nBufferCountActual)
186                return OMX_ErrorBadParameter;
187            temp.nBufferCountActual = p->nBufferCountActual;
188        }
189    }
190    else {
191        temp.nPortIndex = p->nPortIndex;
192        temp.eDir = p->eDir;
193        temp.nBufferCountActual = p->nBufferCountActual;
194        temp.nBufferCountMin = p->nBufferCountMin;
195        temp.nBufferSize = p->nBufferSize;
196        temp.bEnabled = p->bEnabled;
197        temp.bPopulated = p->bPopulated;
198        temp.eDomain = p->eDomain;
199        temp.bBuffersContiguous = p->bBuffersContiguous;
200        temp.nBufferAlignment = p->nBufferAlignment;
201    }
202
203    switch (p->eDomain) {
204    case OMX_PortDomainAudio: {
205        OMX_AUDIO_PORTDEFINITIONTYPE *format = &temp.format.audio;
206        const OMX_AUDIO_PORTDEFINITIONTYPE *pformat = &p->format.audio;
207        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
208
209        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
210                       mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
211
212        strncpy(format->cMIMEType, pformat->cMIMEType,
213                mimetype_len);
214        format->cMIMEType[mimetype_len+1] = '\0';
215        format->pNativeRender = pformat->pNativeRender;
216        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
217        format->eEncoding = pformat->eEncoding;
218
219        break;
220    }
221    case OMX_PortDomainVideo: {
222        OMX_VIDEO_PORTDEFINITIONTYPE *format = &temp.format.video;
223        const OMX_VIDEO_PORTDEFINITIONTYPE *pformat = &p->format.video;
224        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
225
226        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
227                       mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
228
229        strncpy(format->cMIMEType, pformat->cMIMEType,
230                mimetype_len);
231        format->cMIMEType[mimetype_len+1] = '\0';
232        format->pNativeRender = pformat->pNativeRender;
233        format->nFrameWidth = pformat->nFrameWidth;
234        format->nFrameHeight = pformat->nFrameHeight;
235        format->nBitrate = pformat->nBitrate;
236        format->xFramerate = pformat->xFramerate;
237        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
238        format->eCompressionFormat = pformat->eCompressionFormat;
239        format->eColorFormat = pformat->eColorFormat;
240        format->pNativeWindow = pformat->pNativeWindow;
241        OMX_U32 nFrameSize = getFrameBufSize(format->eColorFormat,format->nFrameWidth,format->nFrameHeight);
242        if(nFrameSize!=-1)
243            temp.nBufferSize = nFrameSize;
244        if (overwrite_readonly) {
245            format->nStride = pformat->nStride;
246            format->nSliceHeight = pformat->nSliceHeight;
247        }
248
249        break;
250    }
251    case OMX_PortDomainImage: {
252        OMX_IMAGE_PORTDEFINITIONTYPE *format = &temp.format.image;
253        const OMX_IMAGE_PORTDEFINITIONTYPE *pformat = &p->format.image;
254        OMX_U32 mimetype_len = strlen(pformat->cMIMEType);
255
256        mimetype_len = OMX_MAX_STRINGNAME_SIZE-1 > mimetype_len ?
257                       mimetype_len : OMX_MAX_STRINGNAME_SIZE-1;
258
259        strncpy(format->cMIMEType, pformat->cMIMEType,
260                mimetype_len+1);
261        format->cMIMEType[mimetype_len+1] = '\0';
262        format->nFrameWidth = pformat->nFrameWidth;
263        format->nFrameHeight = pformat->nFrameHeight;
264        format->nStride = pformat->nStride;
265        format->bFlagErrorConcealment = pformat->bFlagErrorConcealment;
266        format->eCompressionFormat = pformat->eCompressionFormat;
267        format->eColorFormat = pformat->eColorFormat;
268        format->pNativeWindow = pformat->pNativeWindow;
269
270        if (overwrite_readonly)
271            format->nSliceHeight = pformat->nSliceHeight;
272
273        break;
274    }
275    case OMX_PortDomainOther: {
276        OMX_OTHER_PORTDEFINITIONTYPE *format = &temp.format.other;
277        const OMX_OTHER_PORTDEFINITIONTYPE *pformat = &p->format.other;
278
279        format->eFormat = pformat->eFormat;
280        break;
281    }
282    default:
283        LOGE("cannot find 0x%08x port domain\n", p->eDomain);
284        return OMX_ErrorBadParameter;
285    }
286
287    memcpy(&portdefinition, &temp, sizeof(temp));
288    return OMX_ErrorNone;
289}
290
291const OMX_PARAM_PORTDEFINITIONTYPE *PortBase::GetPortDefinition(void)
292{
293    return &portdefinition;
294}
295
296/* Use/Allocate/FreeBuffer */
297OMX_ERRORTYPE PortBase::UseBuffer(OMX_BUFFERHEADERTYPE **ppBufferHdr,
298                                  OMX_U32 nPortIndex,
299                                  OMX_PTR pAppPrivate,
300                                  OMX_U32 nSizeBytes,
301                                  OMX_U8 *pBuffer)
302{
303    OMX_BUFFERHEADERTYPE *buffer_hdr;
304    struct list *entry;
305
306    LOGV("%s(): %s:%s:PortIndex %lu: enter, nSizeBytes=%lu\n", __FUNCTION__,
307         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes);
308
309    pthread_mutex_lock(&hdrs_lock);
310
311    if (portdefinition.bPopulated == OMX_TRUE) {
312        pthread_mutex_unlock(&hdrs_lock);
313        LOGV("%s(): %s:%s:PortIndex %lu: exit done, already populated\n",
314             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
315             nPortIndex);
316        return OMX_ErrorNone;
317    }
318
319    buffer_hdr = (OMX_BUFFERHEADERTYPE *)calloc(1, sizeof(*buffer_hdr));
320    if (!buffer_hdr) {
321        pthread_mutex_unlock(&hdrs_lock);
322        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, "
323             "connot allocate buffer header\n", __FUNCTION__,
324             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
325        return OMX_ErrorInsufficientResources;
326    }
327
328    entry = list_alloc(buffer_hdr);
329    if (!entry) {
330        free(buffer_hdr);
331        pthread_mutex_unlock(&hdrs_lock);
332        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, "
333             "cannot allocate list entry\n", __FUNCTION__,
334             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
335        return OMX_ErrorInsufficientResources;
336    }
337
338    ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
339    buffer_hdr->pBuffer = pBuffer;
340    buffer_hdr->nAllocLen = nSizeBytes;
341    buffer_hdr->pAppPrivate = pAppPrivate;
342    if (portdefinition.eDir == OMX_DirInput) {
343        buffer_hdr->nInputPortIndex = nPortIndex;
344        buffer_hdr->nOutputPortIndex = 0x7fffffff;
345        buffer_hdr->pInputPortPrivate = this;
346        buffer_hdr->pOutputPortPrivate = NULL;
347    }
348    else {
349        buffer_hdr->nOutputPortIndex = nPortIndex;
350        buffer_hdr->nInputPortIndex = 0x7fffffff;
351        buffer_hdr->pOutputPortPrivate = this;
352        buffer_hdr->pInputPortPrivate = NULL;
353    }
354
355    buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
356    nr_buffer_hdrs++;
357
358    LOGV("%s(): %s:%s:PortIndex %lu: a buffer allocated (%p:%lu/%lu)\n",
359         __FUNCTION__,
360         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
361         buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual);
362
363    if (nr_buffer_hdrs >= portdefinition.nBufferCountActual) {
364        portdefinition.bPopulated = OMX_TRUE;
365        buffer_hdrs_completion = true;
366        pthread_cond_signal(&hdrs_wait);
367        LOGV("%s(): %s:%s:PortIndex %lu: allocate all buffers (%lu)\n",
368             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
369             nPortIndex, portdefinition.nBufferCountActual);
370    }
371
372    *ppBufferHdr = buffer_hdr;
373
374    pthread_mutex_unlock(&hdrs_lock);
375
376    LOGV("%s(): %s:%s:PortIndex %lu: exit done\n", __FUNCTION__,
377         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
378    return OMX_ErrorNone;
379}
380
381OMX_ERRORTYPE PortBase::AllocateBuffer(OMX_BUFFERHEADERTYPE **ppBuffer,
382                                       OMX_U32 nPortIndex,
383                                       OMX_PTR pAppPrivate,
384                                       OMX_U32 nSizeBytes)
385{
386    OMX_BUFFERHEADERTYPE *buffer_hdr;
387    struct list *entry;
388
389    LOGV("%s(): %s:%s:PortIndex %lu: enter, nSizeBytes=%lu\n", __FUNCTION__,
390         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, nSizeBytes);
391
392    pthread_mutex_lock(&hdrs_lock);
393    if (portdefinition.bPopulated == OMX_TRUE) {
394        pthread_mutex_unlock(&hdrs_lock);
395        LOGV("%s(): %s:%s:PortIndex %lu: exit done, already populated\n",
396             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
397             nPortIndex);
398        return OMX_ErrorNone;
399    }
400
401    buffer_hdr = (OMX_BUFFERHEADERTYPE *)
402                 calloc(1, sizeof(*buffer_hdr) + nSizeBytes);
403    if (!buffer_hdr) {
404        pthread_mutex_unlock(&hdrs_lock);
405        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, "
406             "connot allocate buffer header\n", __FUNCTION__,
407             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
408        return OMX_ErrorInsufficientResources;
409    }
410
411    entry = list_alloc(buffer_hdr);
412    if (!entry) {
413        free(buffer_hdr);
414        pthread_mutex_unlock(&hdrs_lock);
415        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, "
416             "connot allocate list entry\n", __FUNCTION__,
417             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
418        return OMX_ErrorInsufficientResources;
419    }
420
421    ComponentBase::SetTypeHeader(buffer_hdr, sizeof(*buffer_hdr));
422    buffer_hdr->pBuffer = (OMX_U8 *)buffer_hdr + sizeof(*buffer_hdr);
423    buffer_hdr->nAllocLen = nSizeBytes;
424    buffer_hdr->pAppPrivate = pAppPrivate;
425    if (portdefinition.eDir == OMX_DirInput) {
426        buffer_hdr->nInputPortIndex = nPortIndex;
427        buffer_hdr->nOutputPortIndex = (OMX_U32)-1;
428        buffer_hdr->pInputPortPrivate = this;
429        buffer_hdr->pOutputPortPrivate = NULL;
430    }
431    else {
432        buffer_hdr->nOutputPortIndex = nPortIndex;
433        buffer_hdr->nInputPortIndex = (OMX_U32)-1;
434        buffer_hdr->pOutputPortPrivate = this;
435        buffer_hdr->pInputPortPrivate = NULL;
436    }
437
438    buffer_hdrs = __list_add_tail(buffer_hdrs, entry);
439    nr_buffer_hdrs++;
440
441    LOGV("%s(): %s:%s:PortIndex %lu: a buffer allocated (%p:%lu/%lu)\n",
442         __FUNCTION__,
443         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
444         buffer_hdr, nr_buffer_hdrs, portdefinition.nBufferCountActual);
445
446    if (nr_buffer_hdrs == portdefinition.nBufferCountActual) {
447        portdefinition.bPopulated = OMX_TRUE;
448        buffer_hdrs_completion = true;
449        pthread_cond_signal(&hdrs_wait);
450        LOGV("%s(): %s:%s:PortIndex %lu: allocate all buffers (%lu)\n",
451             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
452             nPortIndex, portdefinition.nBufferCountActual);
453    }
454
455    *ppBuffer = buffer_hdr;
456
457    pthread_mutex_unlock(&hdrs_lock);
458
459    LOGV("%s(): %s:%s:PortIndex %lu: exit done\n", __FUNCTION__,
460         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
461    return OMX_ErrorNone;
462}
463
464OMX_ERRORTYPE PortBase::FreeBuffer(OMX_U32 nPortIndex,
465                                   OMX_BUFFERHEADERTYPE *pBuffer)
466{
467    struct list *entry;
468    OMX_ERRORTYPE ret;
469
470    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: enter\n", __FUNCTION__,
471         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
472
473    pthread_mutex_lock(&hdrs_lock);
474    entry = list_find(buffer_hdrs, pBuffer);
475
476    if (!entry) {
477        pthread_mutex_unlock(&hdrs_lock);
478        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
479             "cannot find list entry for pBuffer\n", __FUNCTION__,
480             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
481        return OMX_ErrorBadParameter;
482    }
483
484    if (entry->data != pBuffer) {
485        pthread_mutex_unlock(&hdrs_lock);
486        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure,"
487             "mismatch list entry\n" , __FUNCTION__,
488             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
489        return OMX_ErrorBadParameter;
490    }
491
492    ret = ComponentBase::CheckTypeHeader(pBuffer, sizeof(*pBuffer));
493    if (ret != OMX_ErrorNone) {
494        pthread_mutex_unlock(&hdrs_lock);
495        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure,"
496             "invalid type header\n", __FUNCTION__,
497             cbase->GetName(), cbase->GetWorkingRole(), nPortIndex, pBuffer);
498        return ret;
499    }
500
501    buffer_hdrs = __list_delete(buffer_hdrs, entry);
502    nr_buffer_hdrs--;
503
504    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: free a buffer (%lu/%lu)\n",
505         __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(), nPortIndex,
506         pBuffer, nr_buffer_hdrs, portdefinition.nBufferCountActual);
507
508    free(pBuffer);
509
510    portdefinition.bPopulated = OMX_FALSE;
511    if (!nr_buffer_hdrs) {
512        buffer_hdrs_completion = true;
513        pthread_cond_signal(&hdrs_wait);
514        LOGV("%s(): %s:%s:PortIndex %lu: free all allocated buffers (%lu)\n",
515             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
516             nPortIndex, portdefinition.nBufferCountActual);
517    }
518
519    pthread_mutex_unlock(&hdrs_lock);
520
521    LOGV("%s(): %s:%s:PortIndex %lu: exit done\n", __FUNCTION__,
522         cbase->GetName(), cbase->GetWorkingRole(), nPortIndex);
523    return OMX_ErrorNone;
524}
525
526void PortBase::WaitPortBufferCompletion(void)
527{
528    pthread_mutex_lock(&hdrs_lock);
529    if (!buffer_hdrs_completion) {
530        LOGV("%s(): %s:%s:PortIndex %lu: wait for buffer header completion\n",
531             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
532             portdefinition.nPortIndex);
533        pthread_cond_wait(&hdrs_wait, &hdrs_lock);
534        LOGV("%s(): %s:%s:PortIndex %lu: wokeup (buffer header completion)\n",
535             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
536             portdefinition.nPortIndex);
537    }
538    buffer_hdrs_completion = !buffer_hdrs_completion;
539    pthread_mutex_unlock(&hdrs_lock);
540}
541
542/* Empty/FillThisBuffer */
543OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
544{
545    int ret;
546
547    LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
548            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
549            portdefinition.nPortIndex, pBuffer);
550
551    pthread_mutex_lock(&bufferq_lock);
552    ret = queue_push_tail(&bufferq, pBuffer);
553    pthread_mutex_unlock(&bufferq_lock);
554
555    if (ret)
556        return OMX_ErrorInsufficientResources;
557
558    return OMX_ErrorNone;
559}
560
561OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void)
562{
563    OMX_BUFFERHEADERTYPE *buffer;
564
565    pthread_mutex_lock(&bufferq_lock);
566    buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
567    pthread_mutex_unlock(&bufferq_lock);
568
569    LOGV_IF(buffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
570            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
571            portdefinition.nPortIndex, buffer);
572
573    return buffer;
574}
575
576OMX_ERRORTYPE PortBase::MixPushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
577{
578    int ret;
579
580    LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
581            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
582            portdefinition.nPortIndex, pBuffer);
583
584    pthread_mutex_lock(&mixbufferq_lock);
585    ret = queue_push_tail(&mixbufferq, pBuffer);
586    pthread_mutex_unlock(&mixbufferq_lock);
587
588    if (ret)
589        return OMX_ErrorInsufficientResources;
590
591    return OMX_ErrorNone;
592}
593
594OMX_BUFFERHEADERTYPE *PortBase::MixPopBuffer(void)
595{
596    OMX_BUFFERHEADERTYPE *buffer;
597
598    pthread_mutex_lock(&mixbufferq_lock);
599    buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&mixbufferq);
600    pthread_mutex_unlock(&mixbufferq_lock);
601
602    LOGV_IF(buffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
603            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
604            portdefinition.nPortIndex, buffer);
605
606    return buffer;
607}
608
609OMX_ERRORTYPE PortBase::MixPushBufferHead(OMX_BUFFERHEADERTYPE *pBuffer)
610{
611    int ret;
612
613    LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %lu:pBuffer %p:\n",
614            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
615            portdefinition.nPortIndex, pBuffer);
616
617    pthread_mutex_lock(&mixbufferq_lock);
618    ret = queue_push_head(&mixbufferq,pBuffer);
619    pthread_mutex_unlock(&mixbufferq_lock);
620
621    if (ret)
622        return OMX_ErrorInsufficientResources;
623
624    return OMX_ErrorNone;
625}
626
627OMX_U32 PortBase::BufferQueueLength(void)
628{
629    OMX_U32 length;
630
631    pthread_mutex_lock(&bufferq_lock);
632    length = queue_length(&bufferq);
633    pthread_mutex_unlock(&bufferq_lock);
634
635    return length;
636}
637
638OMX_U32 PortBase::MixBufferQueueLength(void)
639{
640    OMX_U32 length;
641
642    pthread_mutex_lock(&mixbufferq_lock);
643    length = queue_length(&mixbufferq);
644    pthread_mutex_unlock(&mixbufferq_lock);
645
646    return length;
647}
648
649
650OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
651{
652    OMX_DIRTYPE direction = portdefinition.eDir;
653    OMX_U32 port_index;
654    OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE,
655                                         OMX_PTR,
656                                         OMX_BUFFERHEADERTYPE *);
657    OMX_ERRORTYPE ret;
658
659    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: enter\n", __FUNCTION__,
660         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
661         pBuffer);
662
663    if (!pBuffer) {
664        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
665             "invalid buffer pointer\n",
666             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
667             portdefinition.nPortIndex, pBuffer);
668        return OMX_ErrorBadParameter;
669    }
670
671    if (direction == OMX_DirInput) {
672        port_index = pBuffer->nInputPortIndex;
673        bufferdone_callback = callbacks->EmptyBufferDone;
674    }
675    else if (direction == OMX_DirOutput) {
676        port_index = pBuffer->nOutputPortIndex;
677        bufferdone_callback = callbacks->FillBufferDone;
678    }
679    else {
680        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
681             "invalid direction (%d)\n",
682             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
683             portdefinition.nPortIndex, pBuffer,
684             direction);
685        return OMX_ErrorBadParameter;
686    }
687
688    if (port_index != portdefinition.nPortIndex) {
689        LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
690             "invalid port index (%lu)\n", __FUNCTION__,
691             cbase->GetName(), cbase->GetWorkingRole(),
692             portdefinition.nPortIndex, pBuffer, port_index);
693        return OMX_ErrorBadParameter;
694    }
695
696    if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
697        LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: "
698             "Report OMX_EventBufferFlag (OMX_BUFFERFLAG_EOS)\n",
699             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
700             portdefinition.nPortIndex, pBuffer);
701
702        callbacks->EventHandler(owner, appdata,
703                                OMX_EventBufferFlag,
704                                port_index, pBuffer->nFlags, NULL);
705    }
706
707    if (pBuffer->hMarkTargetComponent == owner) {
708        LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: "
709             "Report OMX_EventMark\n",
710             __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
711             portdefinition.nPortIndex, pBuffer);
712
713        callbacks->EventHandler(owner, appdata, OMX_EventMark,
714                                0, 0, pBuffer->pMarkData);
715        pBuffer->hMarkTargetComponent = NULL;
716        pBuffer->pMarkData = NULL;
717    }
718
719    ret = bufferdone_callback(owner, appdata, pBuffer);
720
721    LOGV("%s(): %s:%s:PortIndex %lu: exit done, "
722         "callback returned (0x%08x)\n", __FUNCTION__,
723         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
724         ret);
725
726    return OMX_ErrorNone;
727}
728
729/* retain buffer */
730OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer,
731        bool accumulate)
732{
733    int ret;
734
735    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: enter, %s\n", __FUNCTION__,
736         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
737         pBuffer, (accumulate == true) ? "accumulate" : "getagain");
738
739    /* push at tail of retainedbufferq */
740    if (accumulate == true) {
741        /* do not accumulate a buffer set EOS flag */
742        if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
743            LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
744                 "cannot accumulate EOS buffer\n", __FUNCTION__,
745                 cbase->GetName(), cbase->GetWorkingRole(),
746                 portdefinition.nPortIndex, pBuffer);
747            return OMX_ErrorBadParameter;
748        }
749
750        pthread_mutex_lock(&retainedbufferq_lock);
751        if ((OMX_U32)queue_length(&retainedbufferq) <
752                portdefinition.nBufferCountActual)
753            ret = queue_push_tail(&retainedbufferq, pBuffer);
754        else {
755            ret = OMX_ErrorInsufficientResources;
756            LOGE("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit failure, "
757                 "retained bufferq length (%d) exceeds port's actual count "
758                 "(%lu)\n", __FUNCTION__,
759                 cbase->GetName(), cbase->GetWorkingRole(),
760                 portdefinition.nPortIndex, pBuffer,
761                 queue_length(&retainedbufferq),
762                 portdefinition.nBufferCountActual);
763        }
764        pthread_mutex_unlock(&retainedbufferq_lock);
765    }
766    /*
767     * just push at head of bufferq to get this buffer again in
768     * ComponentBase::ProcessorProcess()
769     */
770    else {
771        pthread_mutex_lock(&bufferq_lock);
772        ret = queue_push_head(&bufferq, pBuffer);
773        pthread_mutex_unlock(&bufferq_lock);
774    }
775
776    if (ret)
777        return OMX_ErrorInsufficientResources;
778
779    LOGV("%s(): %s:%s:PortIndex %lu:pBuffer %p: exit done\n", __FUNCTION__,
780         cbase->GetName(), cbase->GetWorkingRole(),
781         portdefinition.nPortIndex, pBuffer);
782    return OMX_ErrorNone;
783}
784
785void PortBase::ReturnAllRetainedBuffers(void)
786{
787    OMX_BUFFERHEADERTYPE *buffer;
788    OMX_ERRORTYPE ret;
789    int i = 0;
790
791    pthread_mutex_lock(&retainedbufferq_lock);
792
793    do {
794        buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
795
796        if (buffer) {
797            LOGV("%s(): %s:%s:PortIndex %lu: returns a retained buffer "
798                 "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
799                 cbase->GetWorkingRole(), portdefinition.nPortIndex,
800                 buffer, i++, queue_length(&retainedbufferq));
801
802            ret = ReturnThisBuffer(buffer);
803            if (ret != OMX_ErrorNone)
804                LOGE("%s(): %s:%s:PortIndex %lu: failed (ret : 0x%x08x)\n",
805                     __FUNCTION__,
806                     cbase->GetName(), cbase->GetWorkingRole(),
807                     portdefinition.nPortIndex, ret);
808        }
809    } while (buffer);
810
811    pthread_mutex_unlock(&retainedbufferq_lock);
812
813    LOGV_IF(i != 0,
814            "%s(): %s:%s:PortIndex %lu: returned all retained buffers (%d)\n",
815            __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
816            portdefinition.nPortIndex, i);
817}
818
819/* SendCommand:Flush/PortEnable/Disable */
820/* must be held ComponentBase::ports_block */
821OMX_ERRORTYPE PortBase::FlushPort(void)
822{
823    OMX_BUFFERHEADERTYPE *buffer;
824
825    LOGV("%s(): %s:%s:PortIndex %lu: enter\n", __FUNCTION__,
826         cbase->GetName(), cbase->GetWorkingRole(),
827         portdefinition.nPortIndex);
828
829    ReturnAllRetainedBuffers();
830
831    while ((buffer = PopBuffer()))
832        ReturnThisBuffer(buffer);
833
834    while ((buffer = MixPopBuffer()))
835        ReturnThisBuffer(buffer);
836
837    LOGV("%s(): %s:%s:PortIndex %lu: exit\n", __FUNCTION__,
838         cbase->GetName(), cbase->GetWorkingRole(),
839         portdefinition.nPortIndex);
840
841    return OMX_ErrorNone;
842}
843
844OMX_STATETYPE PortBase::GetOwnerState(void)
845{
846    OMX_STATETYPE state = OMX_StateInvalid;
847
848    if (owner) {
849        ComponentBase *cbase;
850        cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
851        if (!cbase)
852            return state;
853
854        cbase->CBaseGetState((void *)owner, &state);
855    }
856
857    return state;
858}
859
860bool PortBase::IsEnabled(void)
861{
862    bool enabled;
863    bool unlock = true;
864
865    if (pthread_mutex_trylock(&state_lock))
866        unlock = false;
867
868    enabled = (state == OMX_PortEnabled) ? true : false;
869
870    if (unlock)
871        pthread_mutex_unlock(&state_lock);
872
873    return enabled;
874}
875
876OMX_DIRTYPE PortBase::GetPortDirection(void)
877{
878    return portdefinition.eDir;
879}
880
881OMX_U32 PortBase::GetPortBufferCount(void)
882{
883    return nr_buffer_hdrs;
884}
885
886OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
887{
888    int ret;
889
890    pthread_mutex_lock(&markq_lock);
891    ret = queue_push_tail(&markq, mark);
892    pthread_mutex_unlock(&markq_lock);
893
894    if (ret)
895        return OMX_ErrorInsufficientResources;
896
897    return OMX_ErrorNone;
898}
899
900OMX_MARKTYPE *PortBase::PopMark(void)
901{
902    OMX_MARKTYPE *mark;
903
904    pthread_mutex_lock(&markq_lock);
905    mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
906    pthread_mutex_unlock(&markq_lock);
907
908    return mark;
909}
910
911static const char *state_name[PortBase::OMX_PortEnabled+2] = {
912    "OMX_PortDisabled",
913    "OMX_PortEnabled",
914    "UnKnown Port State",
915};
916
917const char *GetPortStateName(OMX_U8 state)
918{
919    if (state > PortBase::OMX_PortEnabled)
920        state = PortBase::OMX_PortEnabled+1;
921
922    return state_name[state];
923}
924
925OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
926{
927    OMX_U8 current;
928    OMX_ERRORTYPE ret = OMX_ErrorNone;
929
930    LOGV("%s(): %s:%s:PortIndex %lu: enter, transition from %s to %s\n",
931         __FUNCTION__,
932         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
933         GetPortStateName(state), GetPortStateName(transition));
934
935    pthread_mutex_lock(&state_lock);
936
937    current = state;
938
939    if (current == transition) {
940        ret = OMX_ErrorSameState;
941        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, same state (%s)\n",
942             __FUNCTION__,
943             cbase->GetName(), cbase->GetWorkingRole(),
944             portdefinition.nPortIndex, GetPortStateName(current));
945        goto unlock;
946    }
947
948    if (transition == OMX_PortEnabled) {
949        WaitPortBufferCompletion();
950        portdefinition.bEnabled = OMX_TRUE;
951    }
952    else if(transition == OMX_PortDisabled) {
953        FlushPort();
954        WaitPortBufferCompletion();
955        portdefinition.bEnabled = OMX_FALSE;
956    }
957    else {
958        ret = OMX_ErrorBadParameter;
959        LOGE("%s(): %s:%s:PortIndex %lu: exit failure, invalid transition "
960             "(%s)\n", __FUNCTION__,
961             cbase->GetName(), cbase->GetWorkingRole(),
962             portdefinition.nPortIndex, GetPortStateName(transition));
963        goto unlock;
964    }
965
966    state = transition;
967
968    LOGV("%s(): %s:%s:PortIndex %lu: transition from %s to %s complete\n",
969         __FUNCTION__,
970         cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
971         GetPortStateName(current), GetPortStateName(state));
972
973unlock:
974    pthread_mutex_unlock(&state_lock);
975    return ret;
976}
977
978OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void)
979{
980    OMX_ERRORTYPE ret;
981
982    ret = callbacks->EventHandler(owner, appdata,
983                                  OMX_EventPortSettingsChanged,
984                                  portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL);
985
986    FlushPort();
987
988    return ret;
989}
990
991/* end of component methods & helpers */
992
993/* end of PortBase */
994