OMXNodeInstance.cpp revision 03b268eac37ca2589bfff0bf58daf79d29cc14f4
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/MediaDebug.h> 28#include <media/stagefright/MediaErrors.h> 29 30namespace android { 31 32struct BufferMeta { 33 BufferMeta(const sp<IMemory> &mem, bool is_backup = false) 34 : mMem(mem), 35 mIsBackup(is_backup) { 36 } 37 38 BufferMeta(size_t size) 39 : mSize(size), 40 mIsBackup(false) { 41 } 42 43 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { 44 if (!mIsBackup) { 45 return; 46 } 47 48 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, 49 header->pBuffer + header->nOffset, 50 header->nFilledLen); 51 } 52 53 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { 54 if (!mIsBackup) { 55 return; 56 } 57 58 memcpy(header->pBuffer + header->nOffset, 59 (const OMX_U8 *)mMem->pointer() + header->nOffset, 60 header->nFilledLen); 61 } 62 63private: 64 sp<IMemory> mMem; 65 size_t mSize; 66 bool mIsBackup; 67 68 BufferMeta(const BufferMeta &); 69 BufferMeta &operator=(const BufferMeta &); 70}; 71 72// static 73OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { 74 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone 75}; 76 77OMXNodeInstance::OMXNodeInstance( 78 OMX *owner, const sp<IOMXObserver> &observer) 79 : mOwner(owner), 80 mNodeID(NULL), 81 mHandle(NULL), 82 mObserver(observer), 83 mDying(false) { 84} 85 86OMXNodeInstance::~OMXNodeInstance() { 87 CHECK_EQ(mHandle, NULL); 88} 89 90void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) { 91 CHECK_EQ(mHandle, NULL); 92 mNodeID = node_id; 93 mHandle = handle; 94} 95 96OMX *OMXNodeInstance::owner() { 97 return mOwner; 98} 99 100sp<IOMXObserver> OMXNodeInstance::observer() { 101 return mObserver; 102} 103 104OMX::node_id OMXNodeInstance::nodeID() { 105 return mNodeID; 106} 107 108static status_t StatusFromOMXError(OMX_ERRORTYPE err) { 109 switch (err) { 110 case OMX_ErrorNone: 111 return OK; 112 case OMX_ErrorUnsupportedSetting: 113 return ERROR_UNSUPPORTED; 114 default: 115 return UNKNOWN_ERROR; 116 } 117} 118 119status_t OMXNodeInstance::freeNode(OMXMaster *master) { 120 // Transition the node from its current state all the way down 121 // to "Loaded". 122 // This ensures that all active buffers are properly freed even 123 // for components that don't do this themselves on a call to 124 // "FreeHandle". 125 126 // The code below may trigger some more events to be dispatched 127 // by the OMX component - we want to ignore them as our client 128 // does not expect them. 129 mDying = true; 130 131 OMX_STATETYPE state; 132 CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone); 133 switch (state) { 134 case OMX_StateExecuting: 135 { 136 LOGV("forcing Executing->Idle"); 137 sendCommand(OMX_CommandStateSet, OMX_StateIdle); 138 OMX_ERRORTYPE err; 139 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 140 && state != OMX_StateIdle 141 && state != OMX_StateInvalid) { 142 usleep(100000); 143 } 144 CHECK_EQ(err, OMX_ErrorNone); 145 146 if (state == OMX_StateInvalid) { 147 break; 148 } 149 150 // fall through 151 } 152 153 case OMX_StateIdle: 154 { 155 LOGV("forcing Idle->Loaded"); 156 sendCommand(OMX_CommandStateSet, OMX_StateLoaded); 157 158 freeActiveBuffers(); 159 160 OMX_ERRORTYPE err; 161 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 162 && state != OMX_StateLoaded 163 && state != OMX_StateInvalid) { 164 LOGV("waiting for Loaded state..."); 165 usleep(100000); 166 } 167 CHECK_EQ(err, OMX_ErrorNone); 168 169 // fall through 170 } 171 172 case OMX_StateLoaded: 173 case OMX_StateInvalid: 174 break; 175 176 default: 177 CHECK(!"should not be here, unknown state."); 178 break; 179 } 180 181 OMX_ERRORTYPE err = master->destroyComponentInstance( 182 static_cast<OMX_COMPONENTTYPE *>(mHandle)); 183 184 mHandle = NULL; 185 186 if (err != OMX_ErrorNone) { 187 LOGE("FreeHandle FAILED with error 0x%08x.", err); 188 } 189 190 mOwner->invalidateNodeID(mNodeID); 191 mNodeID = NULL; 192 193 LOGV("OMXNodeInstance going away."); 194 delete this; 195 196 return StatusFromOMXError(err); 197} 198 199status_t OMXNodeInstance::sendCommand( 200 OMX_COMMANDTYPE cmd, OMX_S32 param) { 201 Mutex::Autolock autoLock(mLock); 202 203 OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL); 204 return StatusFromOMXError(err); 205} 206 207status_t OMXNodeInstance::getParameter( 208 OMX_INDEXTYPE index, void *params, size_t size) { 209 Mutex::Autolock autoLock(mLock); 210 211 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); 212 return StatusFromOMXError(err); 213} 214 215status_t OMXNodeInstance::setParameter( 216 OMX_INDEXTYPE index, const void *params, size_t size) { 217 Mutex::Autolock autoLock(mLock); 218 219 OMX_ERRORTYPE err = OMX_SetParameter( 220 mHandle, index, const_cast<void *>(params)); 221 222 return StatusFromOMXError(err); 223} 224 225status_t OMXNodeInstance::getConfig( 226 OMX_INDEXTYPE index, void *params, size_t size) { 227 Mutex::Autolock autoLock(mLock); 228 229 OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params); 230 return StatusFromOMXError(err); 231} 232 233status_t OMXNodeInstance::setConfig( 234 OMX_INDEXTYPE index, const void *params, size_t size) { 235 Mutex::Autolock autoLock(mLock); 236 237 OMX_ERRORTYPE err = OMX_SetConfig( 238 mHandle, index, const_cast<void *>(params)); 239 240 return StatusFromOMXError(err); 241} 242 243status_t OMXNodeInstance::useBuffer( 244 OMX_U32 portIndex, const sp<IMemory> ¶ms, 245 OMX::buffer_id *buffer) { 246 Mutex::Autolock autoLock(mLock); 247 248 BufferMeta *buffer_meta = new BufferMeta(params); 249 250 OMX_BUFFERHEADERTYPE *header; 251 252 OMX_ERRORTYPE err = OMX_UseBuffer( 253 mHandle, &header, portIndex, buffer_meta, 254 params->size(), static_cast<OMX_U8 *>(params->pointer())); 255 256 if (err != OMX_ErrorNone) { 257 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err); 258 259 delete buffer_meta; 260 buffer_meta = NULL; 261 262 *buffer = 0; 263 264 return UNKNOWN_ERROR; 265 } 266 267 CHECK_EQ(header->pAppPrivate, buffer_meta); 268 269 *buffer = header; 270 271 addActiveBuffer(portIndex, *buffer); 272 273 return OK; 274} 275 276status_t OMXNodeInstance::allocateBuffer( 277 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer, 278 void **buffer_data) { 279 Mutex::Autolock autoLock(mLock); 280 281 BufferMeta *buffer_meta = new BufferMeta(size); 282 283 OMX_BUFFERHEADERTYPE *header; 284 285 OMX_ERRORTYPE err = OMX_AllocateBuffer( 286 mHandle, &header, portIndex, buffer_meta, size); 287 288 if (err != OMX_ErrorNone) { 289 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 290 291 delete buffer_meta; 292 buffer_meta = NULL; 293 294 *buffer = 0; 295 296 return UNKNOWN_ERROR; 297 } 298 299 CHECK_EQ(header->pAppPrivate, buffer_meta); 300 301 *buffer = header; 302 *buffer_data = header->pBuffer; 303 304 addActiveBuffer(portIndex, *buffer); 305 306 return OK; 307} 308 309status_t OMXNodeInstance::allocateBufferWithBackup( 310 OMX_U32 portIndex, const sp<IMemory> ¶ms, 311 OMX::buffer_id *buffer) { 312 Mutex::Autolock autoLock(mLock); 313 314 BufferMeta *buffer_meta = new BufferMeta(params, true); 315 316 OMX_BUFFERHEADERTYPE *header; 317 318 OMX_ERRORTYPE err = OMX_AllocateBuffer( 319 mHandle, &header, portIndex, buffer_meta, params->size()); 320 321 if (err != OMX_ErrorNone) { 322 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err); 323 324 delete buffer_meta; 325 buffer_meta = NULL; 326 327 *buffer = 0; 328 329 return UNKNOWN_ERROR; 330 } 331 332 CHECK_EQ(header->pAppPrivate, buffer_meta); 333 334 *buffer = header; 335 336 addActiveBuffer(portIndex, *buffer); 337 338 return OK; 339} 340 341status_t OMXNodeInstance::freeBuffer( 342 OMX_U32 portIndex, OMX::buffer_id buffer) { 343 Mutex::Autolock autoLock(mLock); 344 345 removeActiveBuffer(portIndex, buffer); 346 347 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 348 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); 349 350 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); 351 352 delete buffer_meta; 353 buffer_meta = NULL; 354 355 return StatusFromOMXError(err); 356} 357 358status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { 359 Mutex::Autolock autoLock(mLock); 360 361 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 362 header->nFilledLen = 0; 363 header->nOffset = 0; 364 header->nFlags = 0; 365 366 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); 367 368 return StatusFromOMXError(err); 369} 370 371status_t OMXNodeInstance::emptyBuffer( 372 OMX::buffer_id buffer, 373 OMX_U32 rangeOffset, OMX_U32 rangeLength, 374 OMX_U32 flags, OMX_TICKS timestamp) { 375 Mutex::Autolock autoLock(mLock); 376 377 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; 378 header->nFilledLen = rangeLength; 379 header->nOffset = rangeOffset; 380 header->nFlags = flags; 381 header->nTimeStamp = timestamp; 382 383 BufferMeta *buffer_meta = 384 static_cast<BufferMeta *>(header->pAppPrivate); 385 buffer_meta->CopyToOMX(header); 386 387 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); 388 389 return StatusFromOMXError(err); 390} 391 392status_t OMXNodeInstance::getExtensionIndex( 393 const char *parameterName, OMX_INDEXTYPE *index) { 394 Mutex::Autolock autoLock(mLock); 395 396 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 397 mHandle, const_cast<char *>(parameterName), index); 398 399 return StatusFromOMXError(err); 400} 401 402void OMXNodeInstance::onMessage(const omx_message &msg) { 403 if (msg.type == omx_message::FILL_BUFFER_DONE) { 404 OMX_BUFFERHEADERTYPE *buffer = 405 static_cast<OMX_BUFFERHEADERTYPE *>( 406 msg.u.extended_buffer_data.buffer); 407 408 BufferMeta *buffer_meta = 409 static_cast<BufferMeta *>(buffer->pAppPrivate); 410 411 buffer_meta->CopyFromOMX(buffer); 412 } 413 414 mObserver->onMessage(msg); 415} 416 417void OMXNodeInstance::onObserverDied(OMXMaster *master) { 418 LOGE("!!! Observer died. Quickly, do something, ... anything..."); 419 420 // Try to force shutdown of the node and hope for the best. 421 freeNode(master); 422} 423 424void OMXNodeInstance::onGetHandleFailed() { 425 delete this; 426} 427 428// static 429OMX_ERRORTYPE OMXNodeInstance::OnEvent( 430 OMX_IN OMX_HANDLETYPE hComponent, 431 OMX_IN OMX_PTR pAppData, 432 OMX_IN OMX_EVENTTYPE eEvent, 433 OMX_IN OMX_U32 nData1, 434 OMX_IN OMX_U32 nData2, 435 OMX_IN OMX_PTR pEventData) { 436 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 437 if (instance->mDying) { 438 return OMX_ErrorNone; 439 } 440 return instance->owner()->OnEvent( 441 instance->nodeID(), eEvent, nData1, nData2, pEventData); 442} 443 444// static 445OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( 446 OMX_IN OMX_HANDLETYPE hComponent, 447 OMX_IN OMX_PTR pAppData, 448 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 449 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 450 if (instance->mDying) { 451 return OMX_ErrorNone; 452 } 453 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); 454} 455 456// static 457OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( 458 OMX_IN OMX_HANDLETYPE hComponent, 459 OMX_IN OMX_PTR pAppData, 460 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 461 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 462 if (instance->mDying) { 463 return OMX_ErrorNone; 464 } 465 return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer); 466} 467 468void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { 469 ActiveBuffer active; 470 active.mPortIndex = portIndex; 471 active.mID = id; 472 mActiveBuffers.push(active); 473} 474 475void OMXNodeInstance::removeActiveBuffer( 476 OMX_U32 portIndex, OMX::buffer_id id) { 477 bool found = false; 478 for (size_t i = 0; i < mActiveBuffers.size(); ++i) { 479 if (mActiveBuffers[i].mPortIndex == portIndex 480 && mActiveBuffers[i].mID == id) { 481 found = true; 482 mActiveBuffers.removeItemsAt(i); 483 break; 484 } 485 } 486 487 if (!found) { 488 LOGW("Attempt to remove an active buffer we know nothing about..."); 489 } 490} 491 492void OMXNodeInstance::freeActiveBuffers() { 493 // Make sure to count down here, as freeBuffer will in turn remove 494 // the active buffer from the vector... 495 for (size_t i = mActiveBuffers.size(); i--;) { 496 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID); 497 } 498} 499 500} // namespace android 501 502