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