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 rc = pthread_cond_timedwait(&hdrs_wait, &hdrs_lock, &tv);
599 }
600 if (rc == ETIMEDOUT) {
601 LOGE("%s(): %s:%s:PortIndex %u: wokeup (buffer header timeout)\n",
602 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
603 portdefinition.nPortIndex);
604 ret = OMX_ErrorTimeout;
605 }
606 buffer_hdrs_completion = !buffer_hdrs_completion;
607 pthread_mutex_unlock(&hdrs_lock);
608 return ret;
609 }
610
611 /* Empty/FillThisBuffer */
PushThisBuffer(OMX_BUFFERHEADERTYPE * pBuffer)612 OMX_ERRORTYPE PortBase::PushThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
613 {
614 int ret;
615 LOGV_IF(pBuffer != NULL, "%s(): %s:%s:PortIndex %u:pBuffer %p:\n",
616 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
617 portdefinition.nPortIndex, pBuffer);
618 pthread_mutex_lock(&bufferq_lock);
619 ret = queue_push_tail(&bufferq, pBuffer);
620 pthread_mutex_unlock(&bufferq_lock);
621
622 if (ret)
623 return OMX_ErrorInsufficientResources;
624
625 return OMX_ErrorNone;
626 }
627
PopBuffer(void)628 OMX_BUFFERHEADERTYPE *PortBase::PopBuffer(void)
629 {
630 OMX_BUFFERHEADERTYPE *buffer;
631
632 pthread_mutex_lock(&bufferq_lock);
633 buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
634 pthread_mutex_unlock(&bufferq_lock);
635 LOGV_IF((buffer != NULL || RetainedBufferQueueLength() > 0), "%s(): %s:%s:PortIndex %u:pBuffer %p:\n",
636 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
637 portdefinition.nPortIndex, buffer);
638 return buffer;
639 }
640
BufferQueueLength(void)641 OMX_U32 PortBase::BufferQueueLength(void)
642 {
643 OMX_U32 length;
644
645 pthread_mutex_lock(&bufferq_lock);
646 length = queue_length(&bufferq);
647 pthread_mutex_unlock(&bufferq_lock);
648
649 return length;
650 }
651
RetainedBufferQueueLength(void)652 OMX_U32 PortBase::RetainedBufferQueueLength(void)
653 {
654 OMX_U32 length;
655
656 pthread_mutex_lock(&retainedbufferq_lock);
657 length = queue_length(&retainedbufferq);
658 pthread_mutex_unlock(&retainedbufferq_lock);
659
660 return length;
661 }
662
ReturnThisBuffer(OMX_BUFFERHEADERTYPE * pBuffer)663 OMX_ERRORTYPE PortBase::ReturnThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer)
664 {
665 OMX_DIRTYPE direction = portdefinition.eDir;
666 OMX_U32 port_index;
667 OMX_ERRORTYPE (*bufferdone_callback)(OMX_HANDLETYPE,
668 OMX_PTR,
669 OMX_BUFFERHEADERTYPE *);
670 OMX_ERRORTYPE ret;
671
672 LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter\n", __FUNCTION__,
673 cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
674 pBuffer);
675
676 if (!pBuffer) {
677 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
678 "invalid buffer pointer\n",
679 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
680 portdefinition.nPortIndex, pBuffer);
681 return OMX_ErrorBadParameter;
682 }
683
684 if (direction == OMX_DirInput) {
685 port_index = pBuffer->nInputPortIndex;
686 bufferdone_callback = callbacks->EmptyBufferDone;
687 }
688 else if (direction == OMX_DirOutput) {
689 port_index = pBuffer->nOutputPortIndex;
690 bufferdone_callback = callbacks->FillBufferDone;
691 }
692 else {
693 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
694 "invalid direction (%d)\n",
695 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
696 portdefinition.nPortIndex, pBuffer,
697 direction);
698 return OMX_ErrorBadParameter;
699 }
700
701 if (port_index != portdefinition.nPortIndex) {
702 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
703 "invalid port index (%u)\n", __FUNCTION__,
704 cbase->GetName(), cbase->GetWorkingRole(),
705 portdefinition.nPortIndex, pBuffer, port_index);
706 return OMX_ErrorBadParameter;
707 }
708
709 if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
710 LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: "
711 "Report OMX_EventBufferFlag (OMX_BUFFERFLAG_EOS)\n",
712 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
713 portdefinition.nPortIndex, pBuffer);
714
715 callbacks->EventHandler(owner, appdata,
716 OMX_EventBufferFlag,
717 port_index, pBuffer->nFlags, NULL);
718 }
719
720 if (pBuffer->hMarkTargetComponent == owner) {
721 LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: "
722 "Report OMX_EventMark\n",
723 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
724 portdefinition.nPortIndex, pBuffer);
725
726 callbacks->EventHandler(owner, appdata, OMX_EventMark,
727 0, 0, pBuffer->pMarkData);
728 pBuffer->hMarkTargetComponent = NULL;
729 pBuffer->pMarkData = NULL;
730 }
731
732 ret = bufferdone_callback(owner, appdata, pBuffer);
733
734 LOGV("%s(): %s:%s:PortIndex %u: exit done, "
735 "callback returned (0x%08x)\n", __FUNCTION__,
736 cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
737 ret);
738
739 return OMX_ErrorNone;
740 }
741
RetainAndReturnBuffer(OMX_BUFFERHEADERTYPE * pRetain,OMX_BUFFERHEADERTYPE * pReturn)742 OMX_ERRORTYPE PortBase::RetainAndReturnBuffer( OMX_BUFFERHEADERTYPE *pRetain, OMX_BUFFERHEADERTYPE *pReturn)
743 {
744 OMX_ERRORTYPE ret;
745 OMX_U32 length;
746 if (pReturn == pRetain) {
747 return ReturnThisBuffer(pReturn);
748 }
749 ret = RetainThisBuffer(pRetain, false);
750 if (ret != OMX_ErrorNone) {
751 return ret;
752 }
753
754 pthread_mutex_lock(&bufferq_lock);
755 length = queue_length(&bufferq);
756 OMX_BUFFERHEADERTYPE *p;
757 /* remove returned buffer from the queue */
758 OMX_U32 i = 0;
759 for (i = 0; i < length; i++) {
760 p = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&bufferq);
761 if (p == pReturn) {
762 break;
763 }
764 queue_push_tail(&bufferq, p);
765 }
766 pthread_mutex_unlock(&bufferq_lock);
767
768 if (i == length) {
769 return OMX_ErrorNone;
770 }
771
772 return ReturnThisBuffer(pReturn);
773 }
774
775 /* retain buffer */
RetainThisBuffer(OMX_BUFFERHEADERTYPE * pBuffer,bool accumulate)776 OMX_ERRORTYPE PortBase::RetainThisBuffer(OMX_BUFFERHEADERTYPE *pBuffer,
777 bool accumulate)
778 {
779 int ret;
780
781 LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: enter, %s\n", __FUNCTION__,
782 cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
783 pBuffer, (accumulate == true) ? "accumulate" : "getagain");
784
785 /* push at tail of retainedbufferq */
786 if (accumulate == true) {
787
788 if (cbase->GetWorkingRole() == NULL || (strncmp((char*)cbase->GetWorkingRole(), "video_encoder", 13) != 0)) {
789 /* do not accumulate a buffer set EOS flag if not video encoder*/
790 if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
791 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
792 "cannot accumulate EOS buffer\n", __FUNCTION__,
793 cbase->GetName(), cbase->GetWorkingRole(),
794 portdefinition.nPortIndex, pBuffer);
795 return OMX_ErrorBadParameter;
796 }
797 }
798
799 pthread_mutex_lock(&retainedbufferq_lock);
800 if ((OMX_U32)queue_length(&retainedbufferq) <
801 portdefinition.nBufferCountActual)
802 ret = queue_push_tail(&retainedbufferq, pBuffer);
803 else {
804 ret = OMX_ErrorInsufficientResources;
805 LOGE("%s(): %s:%s:PortIndex %u:pBuffer %p: exit failure, "
806 "retained bufferq length (%d) exceeds port's actual count "
807 "(%u)\n", __FUNCTION__,
808 cbase->GetName(), cbase->GetWorkingRole(),
809 portdefinition.nPortIndex, pBuffer,
810 queue_length(&retainedbufferq),
811 portdefinition.nBufferCountActual);
812 }
813 pthread_mutex_unlock(&retainedbufferq_lock);
814 }
815 /*
816 * just push at head of bufferq to get this buffer again in
817 * ComponentBase::ProcessorProcess()
818 */
819 else {
820 pthread_mutex_lock(&bufferq_lock);
821 ret = queue_push_head(&bufferq, pBuffer);
822 pthread_mutex_unlock(&bufferq_lock);
823 }
824
825 if (ret)
826 return OMX_ErrorInsufficientResources;
827
828 LOGV("%s(): %s:%s:PortIndex %u:pBuffer %p: exit done\n", __FUNCTION__,
829 cbase->GetName(), cbase->GetWorkingRole(),
830 portdefinition.nPortIndex, pBuffer);
831 return OMX_ErrorNone;
832 }
833
ReturnAllRetainedBuffers(void)834 void PortBase::ReturnAllRetainedBuffers(void)
835 {
836 OMX_BUFFERHEADERTYPE *buffer;
837 OMX_ERRORTYPE ret;
838 int i = 0;
839
840 pthread_mutex_lock(&retainedbufferq_lock);
841
842 do {
843 buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
844
845 if (buffer) {
846 LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
847 "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
848 cbase->GetWorkingRole(), portdefinition.nPortIndex,
849 buffer, i++, queue_length(&retainedbufferq));
850
851 ret = ReturnThisBuffer(buffer);
852 if (ret != OMX_ErrorNone)
853 LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
854 __FUNCTION__,
855 cbase->GetName(), cbase->GetWorkingRole(),
856 portdefinition.nPortIndex, ret);
857 }
858 } while (buffer);
859
860 pthread_mutex_unlock(&retainedbufferq_lock);
861 LOGV_IF(i != 0,
862 "%s(): %s:%s:PortIndex %u: returned all retained buffers (%d)\n",
863 __FUNCTION__, cbase->GetName(), cbase->GetWorkingRole(),
864 portdefinition.nPortIndex, i);
865 }
866
ReturnOneRetainedBuffer(void)867 void PortBase::ReturnOneRetainedBuffer(void)
868 {
869 OMX_BUFFERHEADERTYPE *buffer;
870 OMX_ERRORTYPE ret;
871 int i =0;
872
873 pthread_mutex_lock(&retainedbufferq_lock);
874
875 buffer = (OMX_BUFFERHEADERTYPE *)queue_pop_head(&retainedbufferq);
876
877 if (buffer) {
878 LOGV("%s(): %s:%s:PortIndex %u: returns a retained buffer "
879 "(%p:%d/%d)\n", __FUNCTION__, cbase->GetName(),
880 cbase->GetWorkingRole(), portdefinition.nPortIndex,
881 buffer, i++, queue_length(&retainedbufferq));
882
883 ret = ReturnThisBuffer(buffer);
884 if (ret != OMX_ErrorNone)
885 LOGE("%s(): %s:%s:PortIndex %u: failed (ret : 0x%x08x)\n",
886 __FUNCTION__,
887 cbase->GetName(), cbase->GetWorkingRole(),
888 portdefinition.nPortIndex, ret);
889 }
890
891 pthread_mutex_unlock(&retainedbufferq_lock);
892
893 }
894
895 /* SendCommand:Flush/PortEnable/Disable */
896 /* must be held ComponentBase::ports_block */
FlushPort(void)897 OMX_ERRORTYPE PortBase::FlushPort(void)
898 {
899 OMX_BUFFERHEADERTYPE *buffer;
900
901 LOGV("%s(): %s:%s:PortIndex %u: enter\n", __FUNCTION__,
902 cbase->GetName(), cbase->GetWorkingRole(),
903 portdefinition.nPortIndex);
904
905 ReturnAllRetainedBuffers();
906
907 while ((buffer = PopBuffer()))
908 ReturnThisBuffer(buffer);
909
910 LOGV("%s(): %s:%s:PortIndex %u: exit\n", __FUNCTION__,
911 cbase->GetName(), cbase->GetWorkingRole(),
912 portdefinition.nPortIndex);
913
914 return OMX_ErrorNone;
915 }
916
GetOwnerState(void)917 OMX_STATETYPE PortBase::GetOwnerState(void)
918 {
919 OMX_STATETYPE state = OMX_StateInvalid;
920
921 if (owner) {
922 ComponentBase *cbase;
923 cbase = static_cast<ComponentBase *>(owner->pComponentPrivate);
924 if (!cbase)
925 return state;
926
927 cbase->CBaseGetState((void *)owner, &state);
928 }
929
930 return state;
931 }
932
IsEnabled(void)933 bool PortBase::IsEnabled(void)
934 {
935 bool enabled;
936 bool unlock = true;
937
938 if (pthread_mutex_trylock(&state_lock))
939 unlock = false;
940
941 enabled = (state == OMX_PortEnabled) ? true : false;
942
943 if (unlock)
944 pthread_mutex_unlock(&state_lock);
945
946 return enabled;
947 }
948
GetPortDirection(void)949 OMX_DIRTYPE PortBase::GetPortDirection(void)
950 {
951 return portdefinition.eDir;
952 }
953
GetPortBufferCount(void)954 OMX_U32 PortBase::GetPortBufferCount(void)
955 {
956 return nr_buffer_hdrs;
957 }
958
PushMark(OMX_MARKTYPE * mark)959 OMX_ERRORTYPE PortBase::PushMark(OMX_MARKTYPE *mark)
960 {
961 int ret;
962
963 pthread_mutex_lock(&markq_lock);
964 ret = queue_push_tail(&markq, mark);
965 pthread_mutex_unlock(&markq_lock);
966
967 if (ret)
968 return OMX_ErrorInsufficientResources;
969
970 return OMX_ErrorNone;
971 }
972
PopMark(void)973 OMX_MARKTYPE *PortBase::PopMark(void)
974 {
975 OMX_MARKTYPE *mark;
976
977 pthread_mutex_lock(&markq_lock);
978 mark = (OMX_MARKTYPE *)queue_pop_head(&markq);
979 pthread_mutex_unlock(&markq_lock);
980
981 return mark;
982 }
983
984 static const char *state_name[PortBase::OMX_PortEnabled+2] = {
985 "OMX_PortDisabled",
986 "OMX_PortEnabled",
987 "UnKnown Port State",
988 };
989
GetPortStateName(OMX_U8 state)990 const char *GetPortStateName(OMX_U8 state)
991 {
992 if (state > PortBase::OMX_PortEnabled)
993 state = PortBase::OMX_PortEnabled+1;
994
995 return state_name[state];
996 }
997
TransState(OMX_U8 transition)998 OMX_ERRORTYPE PortBase::TransState(OMX_U8 transition)
999 {
1000 OMX_U8 current;
1001 OMX_ERRORTYPE ret = OMX_ErrorNone;
1002
1003 LOGV("%s(): %s:%s:PortIndex %u: enter, transition from %s to %s\n",
1004 __FUNCTION__,
1005 cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
1006 GetPortStateName(state), GetPortStateName(transition));
1007
1008 pthread_mutex_lock(&state_lock);
1009
1010 current = state;
1011
1012 if (current == transition) {
1013 ret = OMX_ErrorSameState;
1014 LOGE("%s(): %s:%s:PortIndex %u: exit failure, same state (%s)\n",
1015 __FUNCTION__,
1016 cbase->GetName(), cbase->GetWorkingRole(),
1017 portdefinition.nPortIndex, GetPortStateName(current));
1018 goto unlock;
1019 }
1020
1021 if (transition == OMX_PortEnabled) {
1022 if (cbase->GetWorkingRole() != NULL &&
1023 !strncmp (cbase->GetWorkingRole(),"video_decoder", 13 )) {
1024 ret = WaitPortBufferCompletionTimeout(800); //0.8s timeout
1025 if (!nr_buffer_hdrs) {
1026 // event is trigger by freeing buffer instead of allocating buffer
1027 ret = OMX_ErrorBadParameter;
1028 }
1029 if (ret != OMX_ErrorNone) {
1030 goto unlock;
1031 }
1032 } else {
1033 WaitPortBufferCompletion();
1034 }
1035 portdefinition.bEnabled = OMX_TRUE;
1036 }
1037 else if(transition == OMX_PortDisabled) {
1038 /*need to flush only if port is not empty*/
1039 if (nr_buffer_hdrs)
1040 {
1041 FlushPort();
1042 WaitPortBufferCompletion();
1043 }
1044 portdefinition.bEnabled = OMX_FALSE;
1045 }
1046 else {
1047 ret = OMX_ErrorBadParameter;
1048 LOGE("%s(): %s:%s:PortIndex %u: exit failure, invalid transition "
1049 "(%s)\n", __FUNCTION__,
1050 cbase->GetName(), cbase->GetWorkingRole(),
1051 portdefinition.nPortIndex, GetPortStateName(transition));
1052 goto unlock;
1053 }
1054
1055 state = transition;
1056
1057 LOGV("%s(): %s:%s:PortIndex %u: transition from %s to %s complete\n",
1058 __FUNCTION__,
1059 cbase->GetName(), cbase->GetWorkingRole(), portdefinition.nPortIndex,
1060 GetPortStateName(current), GetPortStateName(state));
1061
1062 unlock:
1063 pthread_mutex_unlock(&state_lock);
1064 return ret;
1065 }
1066
ReportPortSettingsChanged(void)1067 OMX_ERRORTYPE PortBase::ReportPortSettingsChanged(void)
1068 {
1069 OMX_ERRORTYPE ret;
1070
1071 ret = callbacks->EventHandler(owner, appdata,
1072 OMX_EventPortSettingsChanged,
1073 portdefinition.nPortIndex,OMX_IndexParamPortDefinition, NULL);
1074
1075 FlushPort();
1076
1077 return ret;
1078 }
1079
ReportOutputCrop(void)1080 OMX_ERRORTYPE PortBase::ReportOutputCrop(void)
1081 {
1082 OMX_ERRORTYPE ret;
1083
1084 ret = callbacks->EventHandler(owner, appdata,
1085 OMX_EventPortSettingsChanged,
1086 portdefinition.nPortIndex,OMX_IndexConfigCommonOutputCrop, NULL);
1087
1088 return ret;
1089 }
1090
1091
1092 /* end of component methods & helpers */
1093
1094 /* end of PortBase */
1095