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