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