OMXNodeInstance.cpp revision 559dc605bfe2deb73ad718e0d5c5dc55e27c45df
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 EnableAndroidNativeBuffersParams params = { 267 portIndex, enable, 268 }; 269 270 err = OMX_SetParameter(mHandle, index, ¶ms); 271 272 if (err != OMX_ErrorNone) { 273 LOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)", 274 err, err); 275 276 return UNKNOWN_ERROR; 277 } 278 279 return OK; 280} 281 282status_t OMXNodeInstance::useBuffer( 283 OMX_U32 portIndex, const sp<IMemory> ¶ms, 284 OMX::buffer_id *buffer) { 285 Mutex::Autolock autoLock(mLock); 286 287 BufferMeta *buffer_meta = new BufferMeta(params); 288 289 OMX_BUFFERHEADERTYPE *header; 290 291 OMX_ERRORTYPE err = OMX_UseBuffer( 292 mHandle, &header, portIndex, buffer_meta, 293 params->size(), static_cast<OMX_U8 *>(params->pointer())); 294 295 if (err != OMX_ErrorNone) { 296 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err); 297 298 delete buffer_meta; 299 buffer_meta = NULL; 300 301 *buffer = 0; 302 303 return UNKNOWN_ERROR; 304 } 305 306 CHECK_EQ(header->pAppPrivate, buffer_meta); 307 308 *buffer = header; 309 310 addActiveBuffer(portIndex, *buffer); 311 312 return OK; 313} 314 315status_t OMXNodeInstance::useGraphicBuffer( 316 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 317 OMX::buffer_id *buffer) { 318 Mutex::Autolock autoLock(mLock); 319 320 OMX_INDEXTYPE index; 321 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 322 mHandle, 323 const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"), 324 &index); 325 326 if (err != OMX_ErrorNone) { 327 LOGE("OMX_GetExtensionIndex failed"); 328 329 return StatusFromOMXError(err); 330 } 331 332 BufferMeta *bufferMeta = new BufferMeta(graphicBuffer); 333 334 OMX_BUFFERHEADERTYPE *header; 335 336 UseAndroidNativeBufferParams params = { 337 &header, portIndex, bufferMeta, graphicBuffer, 338 }; 339 340 err = OMX_SetParameter(mHandle, index, ¶ms); 341 342 if (err != OMX_ErrorNone) { 343 LOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err, 344 err); 345 346 delete bufferMeta; 347 bufferMeta = NULL; 348 349 *buffer = 0; 350 351 return UNKNOWN_ERROR; 352 } 353 354 CHECK_EQ(header->pAppPrivate, bufferMeta); 355 356 *buffer = header; 357 358 addActiveBuffer(portIndex, *buffer); 359 360 return OK; 361} 362 363status_t OMXNodeInstance::allocateBuffer( 364 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer, 365 void **buffer_data) { 366 Mutex::Autolock autoLock(mLock); 367 368 BufferMeta *buffer_meta = new BufferMeta(size); 369 370 OMX_BUFFERHEADERTYPE *header; 371 372 OMX_ERRORTYPE err = OMX_AllocateBuffer( 373 mHandle, &header, portIndex, buffer_meta, size); 374 375 if (err != OMX_ErrorNone) { 376 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 377 378 delete buffer_meta; 379 buffer_meta = NULL; 380 381 *buffer = 0; 382 383 return UNKNOWN_ERROR; 384 } 385 386 CHECK_EQ(header->pAppPrivate, buffer_meta); 387 388 *buffer = header; 389 *buffer_data = header->pBuffer; 390 391 addActiveBuffer(portIndex, *buffer); 392 393 return OK; 394} 395 396status_t OMXNodeInstance::allocateBufferWithBackup( 397 OMX_U32 portIndex, const sp<IMemory> ¶ms, 398 OMX::buffer_id *buffer) { 399 Mutex::Autolock autoLock(mLock); 400 401 BufferMeta *buffer_meta = new BufferMeta(params, true); 402 403 OMX_BUFFERHEADERTYPE *header; 404 405 OMX_ERRORTYPE err = OMX_AllocateBuffer( 406 mHandle, &header, portIndex, buffer_meta, params->size()); 407 408 if (err != OMX_ErrorNone) { 409 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 410 411 delete buffer_meta; 412 buffer_meta = NULL; 413 414 *buffer = 0; 415 416 return UNKNOWN_ERROR; 417 } 418 419 CHECK_EQ(header->pAppPrivate, buffer_meta); 420 421 *buffer = header; 422 423 addActiveBuffer(portIndex, *buffer); 424 425 return OK; 426} 427 428status_t OMXNodeInstance::freeBuffer( 429 OMX_U32 portIndex, OMX::buffer_id buffer) { 430 Mutex::Autolock autoLock(mLock); 431 432 removeActiveBuffer(portIndex, buffer); 433 434 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 435 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); 436 437 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); 438 439 delete buffer_meta; 440 buffer_meta = NULL; 441 442 return StatusFromOMXError(err); 443} 444 445status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { 446 Mutex::Autolock autoLock(mLock); 447 448 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 449 header->nFilledLen = 0; 450 header->nOffset = 0; 451 header->nFlags = 0; 452 453 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); 454 455 return StatusFromOMXError(err); 456} 457 458status_t OMXNodeInstance::emptyBuffer( 459 OMX::buffer_id buffer, 460 OMX_U32 rangeOffset, OMX_U32 rangeLength, 461 OMX_U32 flags, OMX_TICKS timestamp) { 462 Mutex::Autolock autoLock(mLock); 463 464 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 465 header->nFilledLen = rangeLength; 466 header->nOffset = rangeOffset; 467 header->nFlags = flags; 468 header->nTimeStamp = timestamp; 469 470 BufferMeta *buffer_meta = 471 static_cast<BufferMeta *>(header->pAppPrivate); 472 buffer_meta->CopyToOMX(header); 473 474 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); 475 476 return StatusFromOMXError(err); 477} 478 479status_t OMXNodeInstance::getExtensionIndex( 480 const char *parameterName, OMX_INDEXTYPE *index) { 481 Mutex::Autolock autoLock(mLock); 482 483 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 484 mHandle, const_cast<char *>(parameterName), index); 485 486 return StatusFromOMXError(err); 487} 488 489void OMXNodeInstance::onMessage(const omx_message &msg) { 490 if (msg.type == omx_message::FILL_BUFFER_DONE) { 491 OMX_BUFFERHEADERTYPE *buffer = 492 static_cast<OMX_BUFFERHEADERTYPE *>( 493 msg.u.extended_buffer_data.buffer); 494 495 BufferMeta *buffer_meta = 496 static_cast<BufferMeta *>(buffer->pAppPrivate); 497 498 buffer_meta->CopyFromOMX(buffer); 499 } 500 501 mObserver->onMessage(msg); 502} 503 504void OMXNodeInstance::onObserverDied(OMXMaster *master) { 505 LOGE("!!! Observer died. Quickly, do something, ... anything..."); 506 507 // Try to force shutdown of the node and hope for the best. 508 freeNode(master); 509} 510 511void OMXNodeInstance::onGetHandleFailed() { 512 delete this; 513} 514 515// static 516OMX_ERRORTYPE OMXNodeInstance::OnEvent( 517 OMX_IN OMX_HANDLETYPE hComponent, 518 OMX_IN OMX_PTR pAppData, 519 OMX_IN OMX_EVENTTYPE eEvent, 520 OMX_IN OMX_U32 nData1, 521 OMX_IN OMX_U32 nData2, 522 OMX_IN OMX_PTR pEventData) { 523 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 524 if (instance->mDying) { 525 return OMX_ErrorNone; 526 } 527 return instance->owner()->OnEvent( 528 instance->nodeID(), eEvent, nData1, nData2, pEventData); 529} 530 531// static 532OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( 533 OMX_IN OMX_HANDLETYPE hComponent, 534 OMX_IN OMX_PTR pAppData, 535 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 536 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 537 if (instance->mDying) { 538 return OMX_ErrorNone; 539 } 540 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); 541} 542 543// static 544OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( 545 OMX_IN OMX_HANDLETYPE hComponent, 546 OMX_IN OMX_PTR pAppData, 547 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 548 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 549 if (instance->mDying) { 550 return OMX_ErrorNone; 551 } 552 return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer); 553} 554 555void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { 556 ActiveBuffer active; 557 active.mPortIndex = portIndex; 558 active.mID = id; 559 mActiveBuffers.push(active); 560} 561 562void OMXNodeInstance::removeActiveBuffer( 563 OMX_U32 portIndex, OMX::buffer_id id) { 564 bool found = false; 565 for (size_t i = 0; i < mActiveBuffers.size(); ++i) { 566 if (mActiveBuffers[i].mPortIndex == portIndex 567 && mActiveBuffers[i].mID == id) { 568 found = true; 569 mActiveBuffers.removeItemsAt(i); 570 break; 571 } 572 } 573 574 if (!found) { 575 LOGW("Attempt to remove an active buffer we know nothing about..."); 576 } 577} 578 579void OMXNodeInstance::freeActiveBuffers() { 580 // Make sure to count down here, as freeBuffer will in turn remove 581 // the active buffer from the vector... 582 for (size_t i = mActiveBuffers.size(); i--;) { 583 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID); 584 } 585} 586 587} // namespace android 588