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