OMXNodeInstance.cpp revision 83750eaf5a3f38c243a9e7eb81d4b2421e3a0d88
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "OMXNodeInstance" 19#include <utils/Log.h> 20 21#include "../include/OMXNodeInstance.h" 22#include "OMXMaster.h" 23 24#include <OMX_Component.h> 25 26#include <binder/IMemory.h> 27#include <media/stagefright/HardwareAPI.h> 28#include <media/stagefright/MediaDebug.h> 29#include <media/stagefright/MediaErrors.h> 30 31namespace android { 32 33struct BufferMeta { 34 BufferMeta(const sp<IMemory> &mem, bool is_backup = false) 35 : mMem(mem), 36 mIsBackup(is_backup) { 37 } 38 39 BufferMeta(size_t size) 40 : mSize(size), 41 mIsBackup(false) { 42 } 43 44 BufferMeta(const sp<GraphicBuffer> &graphicBuffer) 45 : mGraphicBuffer(graphicBuffer), 46 mIsBackup(false) { 47 } 48 49 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { 50 if (!mIsBackup) { 51 return; 52 } 53 54 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, 55 header->pBuffer + header->nOffset, 56 header->nFilledLen); 57 } 58 59 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { 60 if (!mIsBackup) { 61 return; 62 } 63 64 memcpy(header->pBuffer + header->nOffset, 65 (const OMX_U8 *)mMem->pointer() + header->nOffset, 66 header->nFilledLen); 67 } 68 69private: 70 sp<GraphicBuffer> mGraphicBuffer; 71 sp<IMemory> mMem; 72 size_t mSize; 73 bool mIsBackup; 74 75 BufferMeta(const BufferMeta &); 76 BufferMeta &operator=(const BufferMeta &); 77}; 78 79// static 80OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { 81 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone 82}; 83 84OMXNodeInstance::OMXNodeInstance( 85 OMX *owner, const sp<IOMXObserver> &observer) 86 : mOwner(owner), 87 mNodeID(NULL), 88 mHandle(NULL), 89 mObserver(observer), 90 mDying(false) { 91} 92 93OMXNodeInstance::~OMXNodeInstance() { 94 CHECK_EQ(mHandle, NULL); 95} 96 97void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) { 98 CHECK_EQ(mHandle, NULL); 99 mNodeID = node_id; 100 mHandle = handle; 101} 102 103OMX *OMXNodeInstance::owner() { 104 return mOwner; 105} 106 107sp<IOMXObserver> OMXNodeInstance::observer() { 108 return mObserver; 109} 110 111OMX::node_id OMXNodeInstance::nodeID() { 112 return mNodeID; 113} 114 115static status_t StatusFromOMXError(OMX_ERRORTYPE err) { 116 switch (err) { 117 case OMX_ErrorNone: 118 return OK; 119 case OMX_ErrorUnsupportedSetting: 120 return ERROR_UNSUPPORTED; 121 default: 122 return UNKNOWN_ERROR; 123 } 124} 125 126status_t OMXNodeInstance::freeNode(OMXMaster *master) { 127 // Transition the node from its current state all the way down 128 // to "Loaded". 129 // This ensures that all active buffers are properly freed even 130 // for components that don't do this themselves on a call to 131 // "FreeHandle". 132 133 // The code below may trigger some more events to be dispatched 134 // by the OMX component - we want to ignore them as our client 135 // does not expect them. 136 mDying = true; 137 138 OMX_STATETYPE state; 139 CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone); 140 switch (state) { 141 case OMX_StateExecuting: 142 { 143 LOGV("forcing Executing->Idle"); 144 sendCommand(OMX_CommandStateSet, OMX_StateIdle); 145 OMX_ERRORTYPE err; 146 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 147 && state != OMX_StateIdle 148 && state != OMX_StateInvalid) { 149 usleep(100000); 150 } 151 CHECK_EQ(err, OMX_ErrorNone); 152 153 if (state == OMX_StateInvalid) { 154 break; 155 } 156 157 // fall through 158 } 159 160 case OMX_StateIdle: 161 { 162 LOGV("forcing Idle->Loaded"); 163 sendCommand(OMX_CommandStateSet, OMX_StateLoaded); 164 165 freeActiveBuffers(); 166 167 OMX_ERRORTYPE err; 168 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 169 && state != OMX_StateLoaded 170 && state != OMX_StateInvalid) { 171 LOGV("waiting for Loaded state..."); 172 usleep(100000); 173 } 174 CHECK_EQ(err, OMX_ErrorNone); 175 176 // fall through 177 } 178 179 case OMX_StateLoaded: 180 case OMX_StateInvalid: 181 break; 182 183 default: 184 CHECK(!"should not be here, unknown state."); 185 break; 186 } 187 188 OMX_ERRORTYPE err = master->destroyComponentInstance( 189 static_cast<OMX_COMPONENTTYPE *>(mHandle)); 190 191 mHandle = NULL; 192 193 if (err != OMX_ErrorNone) { 194 LOGE("FreeHandle FAILED with error 0x%08x.", err); 195 } 196 197 mOwner->invalidateNodeID(mNodeID); 198 mNodeID = NULL; 199 200 LOGV("OMXNodeInstance going away."); 201 delete this; 202 203 return StatusFromOMXError(err); 204} 205 206status_t OMXNodeInstance::sendCommand( 207 OMX_COMMANDTYPE cmd, OMX_S32 param) { 208 Mutex::Autolock autoLock(mLock); 209 210 OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL); 211 return StatusFromOMXError(err); 212} 213 214status_t OMXNodeInstance::getParameter( 215 OMX_INDEXTYPE index, void *params, size_t size) { 216 Mutex::Autolock autoLock(mLock); 217 218 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); 219 return StatusFromOMXError(err); 220} 221 222status_t OMXNodeInstance::setParameter( 223 OMX_INDEXTYPE index, const void *params, size_t size) { 224 Mutex::Autolock autoLock(mLock); 225 226 OMX_ERRORTYPE err = OMX_SetParameter( 227 mHandle, index, const_cast<void *>(params)); 228 229 return StatusFromOMXError(err); 230} 231 232status_t OMXNodeInstance::getConfig( 233 OMX_INDEXTYPE index, void *params, size_t size) { 234 Mutex::Autolock autoLock(mLock); 235 236 OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params); 237 return StatusFromOMXError(err); 238} 239 240status_t OMXNodeInstance::setConfig( 241 OMX_INDEXTYPE index, const void *params, size_t size) { 242 Mutex::Autolock autoLock(mLock); 243 244 OMX_ERRORTYPE err = OMX_SetConfig( 245 mHandle, index, const_cast<void *>(params)); 246 247 return StatusFromOMXError(err); 248} 249 250status_t OMXNodeInstance::enableGraphicBuffers( 251 OMX_U32 portIndex, OMX_BOOL enable) { 252 Mutex::Autolock autoLock(mLock); 253 254 OMX_INDEXTYPE index; 255 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 256 mHandle, 257 const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"), 258 &index); 259 260 if (err != OMX_ErrorNone) { 261 LOGE("OMX_GetExtensionIndex failed"); 262 263 return StatusFromOMXError(err); 264 } 265 266 OMX_VERSIONTYPE ver; 267 ver.s.nVersionMajor = 1; 268 ver.s.nVersionMinor = 0; 269 ver.s.nRevision = 0; 270 ver.s.nStep = 0; 271 EnableAndroidNativeBuffersParams params = { 272 sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable, 273 }; 274 275 err = OMX_SetParameter(mHandle, index, ¶ms); 276 277 if (err != OMX_ErrorNone) { 278 LOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)", 279 err, err); 280 281 return UNKNOWN_ERROR; 282 } 283 284 return OK; 285} 286 287status_t OMXNodeInstance::useBuffer( 288 OMX_U32 portIndex, const sp<IMemory> ¶ms, 289 OMX::buffer_id *buffer) { 290 Mutex::Autolock autoLock(mLock); 291 292 BufferMeta *buffer_meta = new BufferMeta(params); 293 294 OMX_BUFFERHEADERTYPE *header; 295 296 OMX_ERRORTYPE err = OMX_UseBuffer( 297 mHandle, &header, portIndex, buffer_meta, 298 params->size(), static_cast<OMX_U8 *>(params->pointer())); 299 300 if (err != OMX_ErrorNone) { 301 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err); 302 303 delete buffer_meta; 304 buffer_meta = NULL; 305 306 *buffer = 0; 307 308 return UNKNOWN_ERROR; 309 } 310 311 CHECK_EQ(header->pAppPrivate, buffer_meta); 312 313 *buffer = header; 314 315 addActiveBuffer(portIndex, *buffer); 316 317 return OK; 318} 319 320status_t OMXNodeInstance::useGraphicBuffer( 321 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 322 OMX::buffer_id *buffer) { 323 Mutex::Autolock autoLock(mLock); 324 325 OMX_INDEXTYPE index; 326 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 327 mHandle, 328 const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"), 329 &index); 330 331 if (err != OMX_ErrorNone) { 332 LOGE("OMX_GetExtensionIndex failed"); 333 334 return StatusFromOMXError(err); 335 } 336 337 BufferMeta *bufferMeta = new BufferMeta(graphicBuffer); 338 339 OMX_BUFFERHEADERTYPE *header; 340 341 OMX_VERSIONTYPE ver; 342 ver.s.nVersionMajor = 1; 343 ver.s.nVersionMinor = 0; 344 ver.s.nRevision = 0; 345 ver.s.nStep = 0; 346 UseAndroidNativeBufferParams params = { 347 sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta, 348 &header, graphicBuffer, 349 }; 350 351 err = OMX_SetParameter(mHandle, index, ¶ms); 352 353 if (err != OMX_ErrorNone) { 354 LOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err, 355 err); 356 357 delete bufferMeta; 358 bufferMeta = NULL; 359 360 *buffer = 0; 361 362 return UNKNOWN_ERROR; 363 } 364 365 CHECK_EQ(header->pAppPrivate, bufferMeta); 366 367 *buffer = header; 368 369 addActiveBuffer(portIndex, *buffer); 370 371 return OK; 372} 373 374status_t OMXNodeInstance::allocateBuffer( 375 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer, 376 void **buffer_data) { 377 Mutex::Autolock autoLock(mLock); 378 379 BufferMeta *buffer_meta = new BufferMeta(size); 380 381 OMX_BUFFERHEADERTYPE *header; 382 383 OMX_ERRORTYPE err = OMX_AllocateBuffer( 384 mHandle, &header, portIndex, buffer_meta, size); 385 386 if (err != OMX_ErrorNone) { 387 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 388 389 delete buffer_meta; 390 buffer_meta = NULL; 391 392 *buffer = 0; 393 394 return UNKNOWN_ERROR; 395 } 396 397 CHECK_EQ(header->pAppPrivate, buffer_meta); 398 399 *buffer = header; 400 *buffer_data = header->pBuffer; 401 402 addActiveBuffer(portIndex, *buffer); 403 404 return OK; 405} 406 407status_t OMXNodeInstance::allocateBufferWithBackup( 408 OMX_U32 portIndex, const sp<IMemory> ¶ms, 409 OMX::buffer_id *buffer) { 410 Mutex::Autolock autoLock(mLock); 411 412 BufferMeta *buffer_meta = new BufferMeta(params, true); 413 414 OMX_BUFFERHEADERTYPE *header; 415 416 OMX_ERRORTYPE err = OMX_AllocateBuffer( 417 mHandle, &header, portIndex, buffer_meta, params->size()); 418 419 if (err != OMX_ErrorNone) { 420 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 421 422 delete buffer_meta; 423 buffer_meta = NULL; 424 425 *buffer = 0; 426 427 return UNKNOWN_ERROR; 428 } 429 430 CHECK_EQ(header->pAppPrivate, buffer_meta); 431 432 *buffer = header; 433 434 addActiveBuffer(portIndex, *buffer); 435 436 return OK; 437} 438 439status_t OMXNodeInstance::freeBuffer( 440 OMX_U32 portIndex, OMX::buffer_id buffer) { 441 Mutex::Autolock autoLock(mLock); 442 443 removeActiveBuffer(portIndex, buffer); 444 445 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 446 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); 447 448 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); 449 450 delete buffer_meta; 451 buffer_meta = NULL; 452 453 return StatusFromOMXError(err); 454} 455 456status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { 457 Mutex::Autolock autoLock(mLock); 458 459 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 460 header->nFilledLen = 0; 461 header->nOffset = 0; 462 header->nFlags = 0; 463 464 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); 465 466 return StatusFromOMXError(err); 467} 468 469status_t OMXNodeInstance::emptyBuffer( 470 OMX::buffer_id buffer, 471 OMX_U32 rangeOffset, OMX_U32 rangeLength, 472 OMX_U32 flags, OMX_TICKS timestamp) { 473 Mutex::Autolock autoLock(mLock); 474 475 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 476 header->nFilledLen = rangeLength; 477 header->nOffset = rangeOffset; 478 header->nFlags = flags; 479 header->nTimeStamp = timestamp; 480 481 BufferMeta *buffer_meta = 482 static_cast<BufferMeta *>(header->pAppPrivate); 483 buffer_meta->CopyToOMX(header); 484 485 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); 486 487 return StatusFromOMXError(err); 488} 489 490status_t OMXNodeInstance::getExtensionIndex( 491 const char *parameterName, OMX_INDEXTYPE *index) { 492 Mutex::Autolock autoLock(mLock); 493 494 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 495 mHandle, const_cast<char *>(parameterName), index); 496 497 return StatusFromOMXError(err); 498} 499 500void OMXNodeInstance::onMessage(const omx_message &msg) { 501 if (msg.type == omx_message::FILL_BUFFER_DONE) { 502 OMX_BUFFERHEADERTYPE *buffer = 503 static_cast<OMX_BUFFERHEADERTYPE *>( 504 msg.u.extended_buffer_data.buffer); 505 506 BufferMeta *buffer_meta = 507 static_cast<BufferMeta *>(buffer->pAppPrivate); 508 509 buffer_meta->CopyFromOMX(buffer); 510 } 511 512 mObserver->onMessage(msg); 513} 514 515void OMXNodeInstance::onObserverDied(OMXMaster *master) { 516 LOGE("!!! Observer died. Quickly, do something, ... anything..."); 517 518 // Try to force shutdown of the node and hope for the best. 519 freeNode(master); 520} 521 522void OMXNodeInstance::onGetHandleFailed() { 523 delete this; 524} 525 526// static 527OMX_ERRORTYPE OMXNodeInstance::OnEvent( 528 OMX_IN OMX_HANDLETYPE hComponent, 529 OMX_IN OMX_PTR pAppData, 530 OMX_IN OMX_EVENTTYPE eEvent, 531 OMX_IN OMX_U32 nData1, 532 OMX_IN OMX_U32 nData2, 533 OMX_IN OMX_PTR pEventData) { 534 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 535 if (instance->mDying) { 536 return OMX_ErrorNone; 537 } 538 return instance->owner()->OnEvent( 539 instance->nodeID(), eEvent, nData1, nData2, pEventData); 540} 541 542// static 543OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( 544 OMX_IN OMX_HANDLETYPE hComponent, 545 OMX_IN OMX_PTR pAppData, 546 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 547 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 548 if (instance->mDying) { 549 return OMX_ErrorNone; 550 } 551 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); 552} 553 554// static 555OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( 556 OMX_IN OMX_HANDLETYPE hComponent, 557 OMX_IN OMX_PTR pAppData, 558 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 559 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 560 if (instance->mDying) { 561 return OMX_ErrorNone; 562 } 563 return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer); 564} 565 566void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { 567 ActiveBuffer active; 568 active.mPortIndex = portIndex; 569 active.mID = id; 570 mActiveBuffers.push(active); 571} 572 573void OMXNodeInstance::removeActiveBuffer( 574 OMX_U32 portIndex, OMX::buffer_id id) { 575 bool found = false; 576 for (size_t i = 0; i < mActiveBuffers.size(); ++i) { 577 if (mActiveBuffers[i].mPortIndex == portIndex 578 && mActiveBuffers[i].mID == id) { 579 found = true; 580 mActiveBuffers.removeItemsAt(i); 581 break; 582 } 583 } 584 585 if (!found) { 586 LOGW("Attempt to remove an active buffer we know nothing about..."); 587 } 588} 589 590void OMXNodeInstance::freeActiveBuffers() { 591 // Make sure to count down here, as freeBuffer will in turn remove 592 // the active buffer from the vector... 593 for (size_t i = mActiveBuffers.size(); i--;) { 594 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID); 595 } 596} 597 598} // namespace android 599