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