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