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