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