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