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 <inttypes.h> 22 23 #include "../include/OMXNodeInstance.h" 24 #include "OMXMaster.h" 25 #include "GraphicBufferSource.h" 26 27 #include <OMX_Component.h> 28 #include <OMX_IndexExt.h> 29 #include <OMX_AsString.h> 30 31 #include <binder/IMemory.h> 32 #include <gui/BufferQueue.h> 33 #include <HardwareAPI.h> 34 #include <media/stagefright/foundation/ADebug.h> 35 #include <media/stagefright/foundation/ABuffer.h> 36 #include <media/stagefright/MediaErrors.h> 37 38 #include <utils/misc.h> 39 40 static const OMX_U32 kPortIndexInput = 0; 41 static const OMX_U32 kPortIndexOutput = 1; 42 43 #define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__) 44 45 #define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \ 46 ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \ 47 mNodeID, mName, ##__VA_ARGS__, asString(err), err) 48 #define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__) 49 #define CLOG_IF_ERROR(fn, err, fmt, ...) \ 50 CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__) 51 52 #define CLOGI_(level, fn, fmt, ...) \ 53 ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__) 54 #define CLOGD_(level, fn, fmt, ...) \ 55 ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__) 56 57 #define CLOG_LIFE(fn, fmt, ...) CLOGI_(ADebug::kDebugLifeCycle, fn, fmt, ##__VA_ARGS__) 58 #define CLOG_STATE(fn, fmt, ...) CLOGI_(ADebug::kDebugState, fn, fmt, ##__VA_ARGS__) 59 #define CLOG_CONFIG(fn, fmt, ...) CLOGI_(ADebug::kDebugConfig, fn, fmt, ##__VA_ARGS__) 60 #define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__) 61 62 #define CLOG_DEBUG_IF(cond, fn, fmt, ...) \ 63 ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__) 64 65 #define CLOG_BUFFER(fn, fmt, ...) \ 66 CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__) 67 #define CLOG_BUMPED_BUFFER(fn, fmt, ...) \ 68 CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__) 69 70 /* buffer formatting */ 71 #define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__ 72 #define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \ 73 BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id)) 74 75 #define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data)) 76 #define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \ 77 NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data)) 78 79 #define EMPTY_BUFFER(addr, header, fenceFd) "%#x [%u@%p fc=%d]", \ 80 (addr), (header)->nAllocLen, (header)->pBuffer, (fenceFd) 81 #define FULL_BUFFER(addr, header, fenceFd) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld fc=%d]", \ 82 (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \ 83 (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp, (fenceFd) 84 85 #define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \ 86 mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \ 87 mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput] 88 // TRICKY: this is needed so formatting macros expand before substitution 89 #define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__) 90 91 template<class T> 92 static void InitOMXParams(T *params) { 93 memset(params, 0, sizeof(T)); 94 params->nSize = sizeof(T); 95 params->nVersion.s.nVersionMajor = 1; 96 params->nVersion.s.nVersionMinor = 0; 97 params->nVersion.s.nRevision = 0; 98 params->nVersion.s.nStep = 0; 99 } 100 101 namespace android { 102 103 struct BufferMeta { 104 BufferMeta(const sp<IMemory> &mem, bool is_backup = false) 105 : mMem(mem), 106 mIsBackup(is_backup) { 107 } 108 109 BufferMeta(size_t size) 110 : mSize(size), 111 mIsBackup(false) { 112 } 113 114 BufferMeta(const sp<GraphicBuffer> &graphicBuffer) 115 : mGraphicBuffer(graphicBuffer), 116 mIsBackup(false) { 117 } 118 119 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) { 120 if (!mIsBackup) { 121 return; 122 } 123 124 // check component returns proper range 125 sp<ABuffer> codec = getBuffer(header, false /* backup */, true /* limit */); 126 127 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size()); 128 } 129 130 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { 131 if (!mIsBackup) { 132 return; 133 } 134 135 memcpy(header->pBuffer + header->nOffset, 136 (const OMX_U8 *)mMem->pointer() + header->nOffset, 137 header->nFilledLen); 138 } 139 140 // return either the codec or the backup buffer 141 sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup, bool limit) { 142 sp<ABuffer> buf; 143 if (backup && mMem != NULL) { 144 buf = new ABuffer(mMem->pointer(), mMem->size()); 145 } else { 146 buf = new ABuffer(header->pBuffer, header->nAllocLen); 147 } 148 if (limit) { 149 if (header->nOffset + header->nFilledLen > header->nOffset 150 && header->nOffset + header->nFilledLen <= header->nAllocLen) { 151 buf->setRange(header->nOffset, header->nFilledLen); 152 } else { 153 buf->setRange(0, 0); 154 } 155 } 156 return buf; 157 } 158 159 void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) { 160 mGraphicBuffer = graphicBuffer; 161 } 162 163 private: 164 sp<GraphicBuffer> mGraphicBuffer; 165 sp<IMemory> mMem; 166 size_t mSize; 167 bool mIsBackup; 168 169 BufferMeta(const BufferMeta &); 170 BufferMeta &operator=(const BufferMeta &); 171 }; 172 173 // static 174 OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { 175 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone 176 }; 177 178 static inline const char *portString(OMX_U32 portIndex) { 179 switch (portIndex) { 180 case kPortIndexInput: return "Input"; 181 case kPortIndexOutput: return "Output"; 182 case ~0U: return "All"; 183 default: return "port"; 184 } 185 } 186 187 OMXNodeInstance::OMXNodeInstance( 188 OMX *owner, const sp<IOMXObserver> &observer, const char *name) 189 : mOwner(owner), 190 mNodeID(0), 191 mHandle(NULL), 192 mObserver(observer), 193 mDying(false), 194 mBufferIDCount(0) 195 { 196 mName = ADebug::GetDebugName(name); 197 DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug"); 198 ALOGV("debug level for %s is %d", name, DEBUG); 199 DEBUG_BUMP = DEBUG; 200 mNumPortBuffers[0] = 0; 201 mNumPortBuffers[1] = 0; 202 mDebugLevelBumpPendingBuffers[0] = 0; 203 mDebugLevelBumpPendingBuffers[1] = 0; 204 mMetadataType[0] = kMetadataBufferTypeInvalid; 205 mMetadataType[1] = kMetadataBufferTypeInvalid; 206 } 207 208 OMXNodeInstance::~OMXNodeInstance() { 209 free(mName); 210 CHECK(mHandle == NULL); 211 } 212 213 void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) { 214 mNodeID = node_id; 215 CLOG_LIFE(allocateNode, "handle=%p", handle); 216 CHECK(mHandle == NULL); 217 mHandle = handle; 218 } 219 220 sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() { 221 Mutex::Autolock autoLock(mGraphicBufferSourceLock); 222 return mGraphicBufferSource; 223 } 224 225 void OMXNodeInstance::setGraphicBufferSource( 226 const sp<GraphicBufferSource>& bufferSource) { 227 Mutex::Autolock autoLock(mGraphicBufferSourceLock); 228 CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get()); 229 mGraphicBufferSource = bufferSource; 230 } 231 232 OMX *OMXNodeInstance::owner() { 233 return mOwner; 234 } 235 236 sp<IOMXObserver> OMXNodeInstance::observer() { 237 return mObserver; 238 } 239 240 OMX::node_id OMXNodeInstance::nodeID() { 241 return mNodeID; 242 } 243 244 status_t StatusFromOMXError(OMX_ERRORTYPE err) { 245 switch (err) { 246 case OMX_ErrorNone: 247 return OK; 248 case OMX_ErrorUnsupportedSetting: 249 case OMX_ErrorUnsupportedIndex: 250 return ERROR_UNSUPPORTED; 251 case OMX_ErrorInsufficientResources: 252 return NO_MEMORY; 253 default: 254 return UNKNOWN_ERROR; 255 } 256 } 257 258 status_t OMXNodeInstance::freeNode(OMXMaster *master) { 259 CLOG_LIFE(freeNode, "handle=%p", mHandle); 260 static int32_t kMaxNumIterations = 10; 261 262 // exit if we have already freed the node 263 if (mHandle == NULL) { 264 return OK; 265 } 266 267 // Transition the node from its current state all the way down 268 // to "Loaded". 269 // This ensures that all active buffers are properly freed even 270 // for components that don't do this themselves on a call to 271 // "FreeHandle". 272 273 // The code below may trigger some more events to be dispatched 274 // by the OMX component - we want to ignore them as our client 275 // does not expect them. 276 mDying = true; 277 278 OMX_STATETYPE state; 279 CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone); 280 switch (state) { 281 case OMX_StateExecuting: 282 { 283 ALOGV("forcing Executing->Idle"); 284 sendCommand(OMX_CommandStateSet, OMX_StateIdle); 285 OMX_ERRORTYPE err; 286 int32_t iteration = 0; 287 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 288 && state != OMX_StateIdle 289 && state != OMX_StateInvalid) { 290 if (++iteration > kMaxNumIterations) { 291 CLOGW("failed to enter Idle state (now %s(%d), aborting.", 292 asString(state), state); 293 state = OMX_StateInvalid; 294 break; 295 } 296 297 usleep(100000); 298 } 299 CHECK_EQ(err, OMX_ErrorNone); 300 301 if (state == OMX_StateInvalid) { 302 break; 303 } 304 305 // fall through 306 } 307 308 case OMX_StateIdle: 309 { 310 ALOGV("forcing Idle->Loaded"); 311 sendCommand(OMX_CommandStateSet, OMX_StateLoaded); 312 313 freeActiveBuffers(); 314 315 OMX_ERRORTYPE err; 316 int32_t iteration = 0; 317 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone 318 && state != OMX_StateLoaded 319 && state != OMX_StateInvalid) { 320 if (++iteration > kMaxNumIterations) { 321 CLOGW("failed to enter Loaded state (now %s(%d), aborting.", 322 asString(state), state); 323 state = OMX_StateInvalid; 324 break; 325 } 326 327 ALOGV("waiting for Loaded state..."); 328 usleep(100000); 329 } 330 CHECK_EQ(err, OMX_ErrorNone); 331 332 // fall through 333 } 334 335 case OMX_StateLoaded: 336 case OMX_StateInvalid: 337 break; 338 339 default: 340 LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state); 341 break; 342 } 343 344 ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName); 345 OMX_ERRORTYPE err = master->destroyComponentInstance( 346 static_cast<OMX_COMPONENTTYPE *>(mHandle)); 347 348 mHandle = NULL; 349 CLOG_IF_ERROR(freeNode, err, ""); 350 free(mName); 351 mName = NULL; 352 353 mOwner->invalidateNodeID(mNodeID); 354 mNodeID = 0; 355 356 ALOGV("OMXNodeInstance going away."); 357 delete this; 358 359 return StatusFromOMXError(err); 360 } 361 362 status_t OMXNodeInstance::sendCommand( 363 OMX_COMMANDTYPE cmd, OMX_S32 param) { 364 const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource()); 365 if (bufferSource != NULL && cmd == OMX_CommandStateSet) { 366 if (param == OMX_StateIdle) { 367 // Initiating transition from Executing -> Idle 368 // ACodec is waiting for all buffers to be returned, do NOT 369 // submit any more buffers to the codec. 370 bufferSource->omxIdle(); 371 } else if (param == OMX_StateLoaded) { 372 // Initiating transition from Idle/Executing -> Loaded 373 // Buffers are about to be freed. 374 bufferSource->omxLoaded(); 375 setGraphicBufferSource(NULL); 376 } 377 378 // fall through 379 } 380 381 Mutex::Autolock autoLock(mLock); 382 383 // bump internal-state debug level for 2 input and output frames past a command 384 { 385 Mutex::Autolock _l(mDebugLock); 386 bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */); 387 } 388 389 const char *paramString = 390 cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param); 391 CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param); 392 OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL); 393 CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param); 394 return StatusFromOMXError(err); 395 } 396 397 status_t OMXNodeInstance::getParameter( 398 OMX_INDEXTYPE index, void *params, size_t /* size */) { 399 Mutex::Autolock autoLock(mLock); 400 401 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params); 402 OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; 403 // some errors are expected for getParameter 404 if (err != OMX_ErrorNoMore) { 405 CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index); 406 } 407 return StatusFromOMXError(err); 408 } 409 410 status_t OMXNodeInstance::setParameter( 411 OMX_INDEXTYPE index, const void *params, size_t size) { 412 Mutex::Autolock autoLock(mLock); 413 OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; 414 CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params); 415 416 OMX_ERRORTYPE err = OMX_SetParameter( 417 mHandle, index, const_cast<void *>(params)); 418 CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index); 419 return StatusFromOMXError(err); 420 } 421 422 status_t OMXNodeInstance::getConfig( 423 OMX_INDEXTYPE index, void *params, size_t /* size */) { 424 Mutex::Autolock autoLock(mLock); 425 426 OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params); 427 OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; 428 // some errors are expected for getConfig 429 if (err != OMX_ErrorNoMore) { 430 CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index); 431 } 432 return StatusFromOMXError(err); 433 } 434 435 status_t OMXNodeInstance::setConfig( 436 OMX_INDEXTYPE index, const void *params, size_t size) { 437 Mutex::Autolock autoLock(mLock); 438 OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index; 439 CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params); 440 441 OMX_ERRORTYPE err = OMX_SetConfig( 442 mHandle, index, const_cast<void *>(params)); 443 CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index); 444 return StatusFromOMXError(err); 445 } 446 447 status_t OMXNodeInstance::getState(OMX_STATETYPE* state) { 448 Mutex::Autolock autoLock(mLock); 449 450 OMX_ERRORTYPE err = OMX_GetState(mHandle, state); 451 CLOG_IF_ERROR(getState, err, ""); 452 return StatusFromOMXError(err); 453 } 454 455 status_t OMXNodeInstance::enableGraphicBuffers( 456 OMX_U32 portIndex, OMX_BOOL enable) { 457 Mutex::Autolock autoLock(mLock); 458 CLOG_CONFIG(enableGraphicBuffers, "%s:%u, %d", portString(portIndex), portIndex, enable); 459 OMX_STRING name = const_cast<OMX_STRING>( 460 "OMX.google.android.index.enableAndroidNativeBuffers"); 461 462 OMX_INDEXTYPE index; 463 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); 464 465 if (err != OMX_ErrorNone) { 466 CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name); 467 return StatusFromOMXError(err); 468 } 469 470 EnableAndroidNativeBuffersParams params; 471 InitOMXParams(¶ms); 472 params.nPortIndex = portIndex; 473 params.enable = enable; 474 475 err = OMX_SetParameter(mHandle, index, ¶ms); 476 CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index, 477 portString(portIndex), portIndex, enable); 478 return StatusFromOMXError(err); 479 } 480 481 status_t OMXNodeInstance::getGraphicBufferUsage( 482 OMX_U32 portIndex, OMX_U32* usage) { 483 Mutex::Autolock autoLock(mLock); 484 485 OMX_INDEXTYPE index; 486 OMX_STRING name = const_cast<OMX_STRING>( 487 "OMX.google.android.index.getAndroidNativeBufferUsage"); 488 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); 489 490 if (err != OMX_ErrorNone) { 491 CLOG_ERROR(getExtensionIndex, err, "%s", name); 492 return StatusFromOMXError(err); 493 } 494 495 GetAndroidNativeBufferUsageParams params; 496 InitOMXParams(¶ms); 497 params.nPortIndex = portIndex; 498 499 err = OMX_GetParameter(mHandle, index, ¶ms); 500 if (err != OMX_ErrorNone) { 501 CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index, 502 portString(portIndex), portIndex); 503 return StatusFromOMXError(err); 504 } 505 506 *usage = params.nUsage; 507 508 return OK; 509 } 510 511 status_t OMXNodeInstance::storeMetaDataInBuffers( 512 OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { 513 Mutex::Autolock autolock(mLock); 514 CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable); 515 return storeMetaDataInBuffers_l(portIndex, enable, type); 516 } 517 518 status_t OMXNodeInstance::storeMetaDataInBuffers_l( 519 OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { 520 if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { 521 return BAD_VALUE; 522 } 523 524 OMX_INDEXTYPE index; 525 OMX_STRING name = const_cast<OMX_STRING>( 526 "OMX.google.android.index.storeMetaDataInBuffers"); 527 528 OMX_STRING nativeBufferName = const_cast<OMX_STRING>( 529 "OMX.google.android.index.storeANWBufferInMetadata"); 530 MetadataBufferType negotiatedType; 531 532 StoreMetaDataInBuffersParams params; 533 InitOMXParams(¶ms); 534 params.nPortIndex = portIndex; 535 params.bStoreMetaData = enable; 536 537 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, nativeBufferName, &index); 538 OMX_ERRORTYPE xerr = err; 539 if (err == OMX_ErrorNone) { 540 err = OMX_SetParameter(mHandle, index, ¶ms); 541 if (err == OMX_ErrorNone) { 542 name = nativeBufferName; // set name for debugging 543 negotiatedType = kMetadataBufferTypeANWBuffer; 544 } 545 } 546 if (err != OMX_ErrorNone) { 547 err = OMX_GetExtensionIndex(mHandle, name, &index); 548 xerr = err; 549 if (err == OMX_ErrorNone) { 550 negotiatedType = kMetadataBufferTypeGrallocSource; 551 err = OMX_SetParameter(mHandle, index, ¶ms); 552 } 553 } 554 555 // don't log loud error if component does not support metadata mode on the output 556 if (err != OMX_ErrorNone) { 557 if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) { 558 CLOGW("component does not support metadata mode; using fallback"); 559 } else if (xerr != OMX_ErrorNone) { 560 CLOG_ERROR(getExtensionIndex, xerr, "%s", name); 561 } else { 562 CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index, 563 portString(portIndex), portIndex, enable, negotiatedType); 564 } 565 negotiatedType = mMetadataType[portIndex]; 566 } else { 567 if (!enable) { 568 negotiatedType = kMetadataBufferTypeInvalid; 569 } 570 mMetadataType[portIndex] = negotiatedType; 571 } 572 CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u negotiated %s:%d", 573 portString(portIndex), portIndex, asString(negotiatedType), negotiatedType); 574 575 if (type != NULL) { 576 *type = negotiatedType; 577 } 578 579 return StatusFromOMXError(err); 580 } 581 582 status_t OMXNodeInstance::prepareForAdaptivePlayback( 583 OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth, 584 OMX_U32 maxFrameHeight) { 585 Mutex::Autolock autolock(mLock); 586 CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u", 587 portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight); 588 589 OMX_INDEXTYPE index; 590 OMX_STRING name = const_cast<OMX_STRING>( 591 "OMX.google.android.index.prepareForAdaptivePlayback"); 592 593 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); 594 if (err != OMX_ErrorNone) { 595 CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name); 596 return StatusFromOMXError(err); 597 } 598 599 PrepareForAdaptivePlaybackParams params; 600 InitOMXParams(¶ms); 601 params.nPortIndex = portIndex; 602 params.bEnable = enable; 603 params.nMaxFrameWidth = maxFrameWidth; 604 params.nMaxFrameHeight = maxFrameHeight; 605 606 err = OMX_SetParameter(mHandle, index, ¶ms); 607 CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index, 608 portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight); 609 return StatusFromOMXError(err); 610 } 611 612 status_t OMXNodeInstance::configureVideoTunnelMode( 613 OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync, 614 native_handle_t **sidebandHandle) { 615 Mutex::Autolock autolock(mLock); 616 CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u", 617 portString(portIndex), portIndex, tunneled, audioHwSync); 618 619 OMX_INDEXTYPE index; 620 OMX_STRING name = const_cast<OMX_STRING>( 621 "OMX.google.android.index.configureVideoTunnelMode"); 622 623 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); 624 if (err != OMX_ErrorNone) { 625 CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name); 626 return StatusFromOMXError(err); 627 } 628 629 ConfigureVideoTunnelModeParams tunnelParams; 630 InitOMXParams(&tunnelParams); 631 tunnelParams.nPortIndex = portIndex; 632 tunnelParams.bTunneled = tunneled; 633 tunnelParams.nAudioHwSync = audioHwSync; 634 err = OMX_SetParameter(mHandle, index, &tunnelParams); 635 if (err != OMX_ErrorNone) { 636 CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index, 637 portString(portIndex), portIndex, tunneled, audioHwSync); 638 return StatusFromOMXError(err); 639 } 640 641 err = OMX_GetParameter(mHandle, index, &tunnelParams); 642 if (err != OMX_ErrorNone) { 643 CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index, 644 portString(portIndex), portIndex, tunneled, audioHwSync); 645 return StatusFromOMXError(err); 646 } 647 if (sidebandHandle) { 648 *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow; 649 } 650 651 return OK; 652 } 653 654 status_t OMXNodeInstance::useBuffer( 655 OMX_U32 portIndex, const sp<IMemory> ¶ms, 656 OMX::buffer_id *buffer, OMX_U32 allottedSize) { 657 Mutex::Autolock autoLock(mLock); 658 if (allottedSize > params->size()) { 659 return BAD_VALUE; 660 } 661 662 BufferMeta *buffer_meta = new BufferMeta(params); 663 664 OMX_BUFFERHEADERTYPE *header; 665 666 OMX_ERRORTYPE err = OMX_UseBuffer( 667 mHandle, &header, portIndex, buffer_meta, 668 allottedSize, static_cast<OMX_U8 *>(params->pointer())); 669 670 if (err != OMX_ErrorNone) { 671 CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER( 672 portIndex, (size_t)allottedSize, params->pointer())); 673 674 delete buffer_meta; 675 buffer_meta = NULL; 676 677 *buffer = 0; 678 679 return StatusFromOMXError(err); 680 } 681 682 CHECK_EQ(header->pAppPrivate, buffer_meta); 683 684 *buffer = makeBufferID(header); 685 686 addActiveBuffer(portIndex, *buffer); 687 688 sp<GraphicBufferSource> bufferSource(getGraphicBufferSource()); 689 if (bufferSource != NULL && portIndex == kPortIndexInput) { 690 bufferSource->addCodecBuffer(header); 691 } 692 693 CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT( 694 *buffer, portIndex, "%u(%zu)@%p", allottedSize, params->size(), params->pointer())); 695 return OK; 696 } 697 698 status_t OMXNodeInstance::useGraphicBuffer2_l( 699 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 700 OMX::buffer_id *buffer) { 701 702 // port definition 703 OMX_PARAM_PORTDEFINITIONTYPE def; 704 InitOMXParams(&def); 705 def.nPortIndex = portIndex; 706 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def); 707 if (err != OMX_ErrorNone) { 708 OMX_INDEXTYPE index = OMX_IndexParamPortDefinition; 709 CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", 710 asString(index), index, portString(portIndex), portIndex); 711 return UNKNOWN_ERROR; 712 } 713 714 BufferMeta *bufferMeta = new BufferMeta(graphicBuffer); 715 716 OMX_BUFFERHEADERTYPE *header = NULL; 717 OMX_U8* bufferHandle = const_cast<OMX_U8*>( 718 reinterpret_cast<const OMX_U8*>(graphicBuffer->handle)); 719 720 err = OMX_UseBuffer( 721 mHandle, 722 &header, 723 portIndex, 724 bufferMeta, 725 def.nBufferSize, 726 bufferHandle); 727 728 if (err != OMX_ErrorNone) { 729 CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle)); 730 delete bufferMeta; 731 bufferMeta = NULL; 732 *buffer = 0; 733 return StatusFromOMXError(err); 734 } 735 736 CHECK_EQ(header->pBuffer, bufferHandle); 737 CHECK_EQ(header->pAppPrivate, bufferMeta); 738 739 *buffer = makeBufferID(header); 740 741 addActiveBuffer(portIndex, *buffer); 742 CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT( 743 *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle)); 744 return OK; 745 } 746 747 // XXX: This function is here for backwards compatibility. Once the OMX 748 // implementations have been updated this can be removed and useGraphicBuffer2 749 // can be renamed to useGraphicBuffer. 750 status_t OMXNodeInstance::useGraphicBuffer( 751 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 752 OMX::buffer_id *buffer) { 753 Mutex::Autolock autoLock(mLock); 754 755 // See if the newer version of the extension is present. 756 OMX_INDEXTYPE index; 757 if (OMX_GetExtensionIndex( 758 mHandle, 759 const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer2"), 760 &index) == OMX_ErrorNone) { 761 return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer); 762 } 763 764 OMX_STRING name = const_cast<OMX_STRING>( 765 "OMX.google.android.index.useAndroidNativeBuffer"); 766 OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index); 767 if (err != OMX_ErrorNone) { 768 CLOG_ERROR(getExtensionIndex, err, "%s", name); 769 return StatusFromOMXError(err); 770 } 771 772 BufferMeta *bufferMeta = new BufferMeta(graphicBuffer); 773 774 OMX_BUFFERHEADERTYPE *header; 775 776 OMX_VERSIONTYPE ver; 777 ver.s.nVersionMajor = 1; 778 ver.s.nVersionMinor = 0; 779 ver.s.nRevision = 0; 780 ver.s.nStep = 0; 781 UseAndroidNativeBufferParams params = { 782 sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta, 783 &header, graphicBuffer, 784 }; 785 786 err = OMX_SetParameter(mHandle, index, ¶ms); 787 788 if (err != OMX_ErrorNone) { 789 CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index, 790 portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle); 791 792 delete bufferMeta; 793 bufferMeta = NULL; 794 795 *buffer = 0; 796 797 return StatusFromOMXError(err); 798 } 799 800 CHECK_EQ(header->pAppPrivate, bufferMeta); 801 802 *buffer = makeBufferID(header); 803 804 addActiveBuffer(portIndex, *buffer); 805 CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT( 806 *buffer, portIndex, "GB=%p", graphicBuffer->handle)); 807 return OK; 808 } 809 810 status_t OMXNodeInstance::updateGraphicBufferInMeta_l( 811 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 812 OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) { 813 if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { 814 return BAD_VALUE; 815 } 816 817 BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate); 818 bufferMeta->setGraphicBuffer(graphicBuffer); 819 if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource 820 && header->nAllocLen >= sizeof(VideoGrallocMetadata)) { 821 VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(header->pBuffer); 822 metadata.eType = kMetadataBufferTypeGrallocSource; 823 metadata.pHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle; 824 } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer 825 && header->nAllocLen >= sizeof(VideoNativeMetadata)) { 826 VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(header->pBuffer); 827 metadata.eType = kMetadataBufferTypeANWBuffer; 828 metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer(); 829 metadata.nFenceFd = -1; 830 } else { 831 CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x bad type (%d) or size (%u)", 832 portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen); 833 return BAD_VALUE; 834 } 835 836 CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p", 837 portString(portIndex), portIndex, buffer, 838 graphicBuffer == NULL ? NULL : graphicBuffer->handle); 839 return OK; 840 } 841 842 status_t OMXNodeInstance::updateGraphicBufferInMeta( 843 OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, 844 OMX::buffer_id buffer) { 845 Mutex::Autolock autoLock(mLock); 846 OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); 847 return updateGraphicBufferInMeta_l(portIndex, graphicBuffer, buffer, header); 848 } 849 850 status_t OMXNodeInstance::createGraphicBufferSource( 851 OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) { 852 status_t err; 853 854 const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource(); 855 if (surfaceCheck != NULL) { 856 if (portIndex < NELEM(mMetadataType) && type != NULL) { 857 *type = mMetadataType[portIndex]; 858 } 859 return ALREADY_EXISTS; 860 } 861 862 // Input buffers will hold meta-data (ANativeWindowBuffer references). 863 err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type); 864 if (err != OK) { 865 return err; 866 } 867 868 // Retrieve the width and height of the graphic buffer, set when the 869 // codec was configured. 870 OMX_PARAM_PORTDEFINITIONTYPE def; 871 InitOMXParams(&def); 872 def.nPortIndex = portIndex; 873 OMX_ERRORTYPE oerr = OMX_GetParameter( 874 mHandle, OMX_IndexParamPortDefinition, &def); 875 if (oerr != OMX_ErrorNone) { 876 OMX_INDEXTYPE index = OMX_IndexParamPortDefinition; 877 CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u", 878 asString(index), index, portString(portIndex), portIndex); 879 return UNKNOWN_ERROR; 880 } 881 882 if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) { 883 CLOGW("createInputSurface requires COLOR_FormatSurface " 884 "(AndroidOpaque) color format instead of %s(%#x)", 885 asString(def.format.video.eColorFormat), def.format.video.eColorFormat); 886 return INVALID_OPERATION; 887 } 888 889 uint32_t usageBits; 890 oerr = OMX_GetParameter( 891 mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits); 892 if (oerr != OMX_ErrorNone) { 893 usageBits = 0; 894 } 895 896 sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this, 897 def.format.video.nFrameWidth, 898 def.format.video.nFrameHeight, 899 def.nBufferCountActual, 900 usageBits, 901 bufferConsumer); 902 903 if ((err = bufferSource->initCheck()) != OK) { 904 return err; 905 } 906 setGraphicBufferSource(bufferSource); 907 908 return OK; 909 } 910 911 status_t OMXNodeInstance::createInputSurface( 912 OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { 913 Mutex::Autolock autolock(mLock); 914 status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type); 915 916 if (err != OK) { 917 return err; 918 } 919 920 *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer(); 921 return OK; 922 } 923 924 //static 925 status_t OMXNodeInstance::createPersistentInputSurface( 926 sp<IGraphicBufferProducer> *bufferProducer, 927 sp<IGraphicBufferConsumer> *bufferConsumer) { 928 String8 name("GraphicBufferSource"); 929 930 sp<IGraphicBufferProducer> producer; 931 sp<IGraphicBufferConsumer> consumer; 932 BufferQueue::createBufferQueue(&producer, &consumer); 933 consumer->setConsumerName(name); 934 consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); 935 936 sp<BufferQueue::ProxyConsumerListener> proxy = 937 new BufferQueue::ProxyConsumerListener(NULL); 938 status_t err = consumer->consumerConnect(proxy, false); 939 if (err != NO_ERROR) { 940 ALOGE("Error connecting to BufferQueue: %s (%d)", 941 strerror(-err), err); 942 return err; 943 } 944 945 *bufferProducer = producer; 946 *bufferConsumer = consumer; 947 948 return OK; 949 } 950 951 status_t OMXNodeInstance::setInputSurface( 952 OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer, 953 MetadataBufferType *type) { 954 Mutex::Autolock autolock(mLock); 955 return createGraphicBufferSource(portIndex, bufferConsumer, type); 956 } 957 958 status_t OMXNodeInstance::signalEndOfInputStream() { 959 // For non-Surface input, the MediaCodec should convert the call to a 960 // pair of requests (dequeue input buffer, queue input buffer with EOS 961 // flag set). Seems easier than doing the equivalent from here. 962 sp<GraphicBufferSource> bufferSource(getGraphicBufferSource()); 963 if (bufferSource == NULL) { 964 CLOGW("signalEndOfInputStream can only be used with Surface input"); 965 return INVALID_OPERATION; 966 } 967 return bufferSource->signalEndOfInputStream(); 968 } 969 970 status_t OMXNodeInstance::allocateBuffer( 971 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer, 972 void **buffer_data) { 973 Mutex::Autolock autoLock(mLock); 974 975 BufferMeta *buffer_meta = new BufferMeta(size); 976 977 OMX_BUFFERHEADERTYPE *header; 978 979 OMX_ERRORTYPE err = OMX_AllocateBuffer( 980 mHandle, &header, portIndex, buffer_meta, size); 981 982 if (err != OMX_ErrorNone) { 983 CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size)); 984 delete buffer_meta; 985 buffer_meta = NULL; 986 987 *buffer = 0; 988 989 return StatusFromOMXError(err); 990 } 991 992 CHECK_EQ(header->pAppPrivate, buffer_meta); 993 994 *buffer = makeBufferID(header); 995 *buffer_data = header->pBuffer; 996 997 addActiveBuffer(portIndex, *buffer); 998 999 sp<GraphicBufferSource> bufferSource(getGraphicBufferSource()); 1000 if (bufferSource != NULL && portIndex == kPortIndexInput) { 1001 bufferSource->addCodecBuffer(header); 1002 } 1003 CLOG_BUFFER(allocateBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p", size, *buffer_data)); 1004 1005 return OK; 1006 } 1007 1008 status_t OMXNodeInstance::allocateBufferWithBackup( 1009 OMX_U32 portIndex, const sp<IMemory> ¶ms, 1010 OMX::buffer_id *buffer, OMX_U32 allottedSize) { 1011 Mutex::Autolock autoLock(mLock); 1012 if (allottedSize > params->size()) { 1013 return BAD_VALUE; 1014 } 1015 1016 BufferMeta *buffer_meta = new BufferMeta(params, true); 1017 1018 OMX_BUFFERHEADERTYPE *header; 1019 1020 OMX_ERRORTYPE err = OMX_AllocateBuffer( 1021 mHandle, &header, portIndex, buffer_meta, allottedSize); 1022 if (err != OMX_ErrorNone) { 1023 CLOG_ERROR(allocateBufferWithBackup, err, 1024 SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer())); 1025 delete buffer_meta; 1026 buffer_meta = NULL; 1027 1028 *buffer = 0; 1029 1030 return StatusFromOMXError(err); 1031 } 1032 1033 CHECK_EQ(header->pAppPrivate, buffer_meta); 1034 1035 *buffer = makeBufferID(header); 1036 1037 addActiveBuffer(portIndex, *buffer); 1038 1039 sp<GraphicBufferSource> bufferSource(getGraphicBufferSource()); 1040 if (bufferSource != NULL && portIndex == kPortIndexInput) { 1041 bufferSource->addCodecBuffer(header); 1042 } 1043 1044 CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p", 1045 params->size(), params->pointer(), allottedSize, header->pBuffer)); 1046 1047 return OK; 1048 } 1049 1050 status_t OMXNodeInstance::freeBuffer( 1051 OMX_U32 portIndex, OMX::buffer_id buffer) { 1052 Mutex::Autolock autoLock(mLock); 1053 CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer); 1054 1055 removeActiveBuffer(portIndex, buffer); 1056 1057 OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); 1058 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); 1059 1060 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); 1061 CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer); 1062 1063 delete buffer_meta; 1064 buffer_meta = NULL; 1065 invalidateBufferID(buffer); 1066 1067 return StatusFromOMXError(err); 1068 } 1069 1070 status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) { 1071 Mutex::Autolock autoLock(mLock); 1072 1073 OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); 1074 header->nFilledLen = 0; 1075 header->nOffset = 0; 1076 header->nFlags = 0; 1077 1078 // meta now owns fenceFd 1079 status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput); 1080 if (res != OK) { 1081 CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd)); 1082 return res; 1083 } 1084 1085 { 1086 Mutex::Autolock _l(mDebugLock); 1087 mOutputBuffersWithCodec.add(header); 1088 CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd))); 1089 } 1090 1091 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); 1092 if (err != OMX_ErrorNone) { 1093 CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd)); 1094 Mutex::Autolock _l(mDebugLock); 1095 mOutputBuffersWithCodec.remove(header); 1096 } 1097 return StatusFromOMXError(err); 1098 } 1099 1100 status_t OMXNodeInstance::emptyBuffer( 1101 OMX::buffer_id buffer, 1102 OMX_U32 rangeOffset, OMX_U32 rangeLength, 1103 OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { 1104 Mutex::Autolock autoLock(mLock); 1105 1106 OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); 1107 BufferMeta *buffer_meta = 1108 static_cast<BufferMeta *>(header->pAppPrivate); 1109 sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */); 1110 sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */); 1111 1112 // convert incoming ANW meta buffers if component is configured for gralloc metadata mode 1113 // ignore rangeOffset in this case 1114 if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource 1115 && backup->capacity() >= sizeof(VideoNativeMetadata) 1116 && codec->capacity() >= sizeof(VideoGrallocMetadata) 1117 && ((VideoNativeMetadata *)backup->base())->eType 1118 == kMetadataBufferTypeANWBuffer) { 1119 VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base(); 1120 VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base(); 1121 CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p", 1122 backupMeta.pBuffer, backupMeta.pBuffer->handle); 1123 codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL; 1124 codecMeta.eType = kMetadataBufferTypeGrallocSource; 1125 header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0; 1126 header->nOffset = 0; 1127 } else { 1128 // rangeLength and rangeOffset must be a subset of the allocated data in the buffer. 1129 // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0. 1130 if (rangeOffset > header->nAllocLen 1131 || rangeLength > header->nAllocLen - rangeOffset) { 1132 CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd)); 1133 if (fenceFd >= 0) { 1134 ::close(fenceFd); 1135 } 1136 return BAD_VALUE; 1137 } 1138 header->nFilledLen = rangeLength; 1139 header->nOffset = rangeOffset; 1140 1141 buffer_meta->CopyToOMX(header); 1142 } 1143 1144 return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd); 1145 } 1146 1147 // log queued buffer activity for the next few input and/or output frames 1148 // if logging at internal state level 1149 void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) { 1150 if (DEBUG == ADebug::kDebugInternalState) { 1151 DEBUG_BUMP = ADebug::kDebugAll; 1152 if (numInputBuffers > 0) { 1153 mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers; 1154 } 1155 if (numOutputBuffers > 0) { 1156 mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers; 1157 } 1158 } 1159 } 1160 1161 void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) { 1162 if (mDebugLevelBumpPendingBuffers[portIndex]) { 1163 --mDebugLevelBumpPendingBuffers[portIndex]; 1164 } 1165 if (!mDebugLevelBumpPendingBuffers[0] 1166 && !mDebugLevelBumpPendingBuffers[1]) { 1167 DEBUG_BUMP = DEBUG; 1168 } 1169 } 1170 1171 status_t OMXNodeInstance::storeFenceInMeta_l( 1172 OMX_BUFFERHEADERTYPE *header, int fenceFd, OMX_U32 portIndex) { 1173 // propagate fence if component supports it; wait for it otherwise 1174 OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nFilledLen : header->nAllocLen; 1175 if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer 1176 && metaSize >= sizeof(VideoNativeMetadata)) { 1177 VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); 1178 if (nativeMeta.nFenceFd >= 0) { 1179 ALOGE("fence (%d) already exists in meta", nativeMeta.nFenceFd); 1180 if (fenceFd >= 0) { 1181 ::close(fenceFd); 1182 } 1183 return ALREADY_EXISTS; 1184 } 1185 nativeMeta.nFenceFd = fenceFd; 1186 } else if (fenceFd >= 0) { 1187 CLOG_BUFFER(storeFenceInMeta, "waiting for fence %d", fenceFd); 1188 sp<Fence> fence = new Fence(fenceFd); 1189 return fence->wait(IOMX::kFenceTimeoutMs); 1190 } 1191 return OK; 1192 } 1193 1194 int OMXNodeInstance::retrieveFenceFromMeta_l( 1195 OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex) { 1196 OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen; 1197 int fenceFd = -1; 1198 if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer 1199 && header->nAllocLen >= sizeof(VideoNativeMetadata)) { 1200 VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)(header->pBuffer); 1201 if (nativeMeta.eType == kMetadataBufferTypeANWBuffer) { 1202 fenceFd = nativeMeta.nFenceFd; 1203 nativeMeta.nFenceFd = -1; 1204 } 1205 if (metaSize < sizeof(nativeMeta) && fenceFd >= 0) { 1206 CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE, FULL_BUFFER( 1207 NULL, header, nativeMeta.nFenceFd)); 1208 fenceFd = -1; 1209 } 1210 } 1211 return fenceFd; 1212 } 1213 1214 status_t OMXNodeInstance::emptyBuffer_l( 1215 OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, 1216 intptr_t debugAddr, int fenceFd) { 1217 header->nFlags = flags; 1218 header->nTimeStamp = timestamp; 1219 1220 status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput); 1221 if (res != OK) { 1222 CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS( 1223 FULL_BUFFER(debugAddr, header, fenceFd))); 1224 return res; 1225 } 1226 1227 { 1228 Mutex::Autolock _l(mDebugLock); 1229 mInputBuffersWithCodec.add(header); 1230 1231 // bump internal-state debug level for 2 input frames past a buffer with CSD 1232 if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { 1233 bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */); 1234 } 1235 1236 CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd))); 1237 } 1238 1239 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); 1240 CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd)); 1241 1242 { 1243 Mutex::Autolock _l(mDebugLock); 1244 if (err != OMX_ErrorNone) { 1245 mInputBuffersWithCodec.remove(header); 1246 } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) { 1247 unbumpDebugLevel_l(kPortIndexInput); 1248 } 1249 } 1250 1251 return StatusFromOMXError(err); 1252 } 1253 1254 // like emptyBuffer, but the data is already in header->pBuffer 1255 status_t OMXNodeInstance::emptyGraphicBuffer( 1256 OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer, 1257 OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) { 1258 Mutex::Autolock autoLock(mLock); 1259 OMX::buffer_id buffer = findBufferID(header); 1260 status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header); 1261 if (err != OK) { 1262 CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER( 1263 (intptr_t)header->pBuffer, header, fenceFd)); 1264 return err; 1265 } 1266 1267 header->nOffset = 0; 1268 header->nFilledLen = graphicBuffer == NULL ? 0 : header->nAllocLen; 1269 return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd); 1270 } 1271 1272 status_t OMXNodeInstance::getExtensionIndex( 1273 const char *parameterName, OMX_INDEXTYPE *index) { 1274 Mutex::Autolock autoLock(mLock); 1275 1276 OMX_ERRORTYPE err = OMX_GetExtensionIndex( 1277 mHandle, const_cast<char *>(parameterName), index); 1278 1279 return StatusFromOMXError(err); 1280 } 1281 1282 inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") { 1283 switch (i) { 1284 case IOMX::INTERNAL_OPTION_SUSPEND: return "SUSPEND"; 1285 case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: 1286 return "REPEAT_PREVIOUS_FRAME_DELAY"; 1287 case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP"; 1288 case IOMX::INTERNAL_OPTION_MAX_FPS: return "MAX_FPS"; 1289 case IOMX::INTERNAL_OPTION_START_TIME: return "START_TIME"; 1290 case IOMX::INTERNAL_OPTION_TIME_LAPSE: return "TIME_LAPSE"; 1291 default: return def; 1292 } 1293 } 1294 1295 status_t OMXNodeInstance::setInternalOption( 1296 OMX_U32 portIndex, 1297 IOMX::InternalOptionType type, 1298 const void *data, 1299 size_t size) { 1300 CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p", 1301 asString(type), type, portString(portIndex), portIndex, size, data); 1302 switch (type) { 1303 case IOMX::INTERNAL_OPTION_SUSPEND: 1304 case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: 1305 case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: 1306 case IOMX::INTERNAL_OPTION_MAX_FPS: 1307 case IOMX::INTERNAL_OPTION_START_TIME: 1308 case IOMX::INTERNAL_OPTION_TIME_LAPSE: 1309 { 1310 const sp<GraphicBufferSource> &bufferSource = 1311 getGraphicBufferSource(); 1312 1313 if (bufferSource == NULL || portIndex != kPortIndexInput) { 1314 CLOGW("setInternalOption is only for Surface input"); 1315 return ERROR_UNSUPPORTED; 1316 } 1317 1318 if (type == IOMX::INTERNAL_OPTION_SUSPEND) { 1319 if (size != sizeof(bool)) { 1320 return INVALID_OPERATION; 1321 } 1322 1323 bool suspend = *(bool *)data; 1324 CLOG_CONFIG(setInternalOption, "suspend=%d", suspend); 1325 bufferSource->suspend(suspend); 1326 } else if (type == 1327 IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){ 1328 if (size != sizeof(int64_t)) { 1329 return INVALID_OPERATION; 1330 } 1331 1332 int64_t delayUs = *(int64_t *)data; 1333 CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs); 1334 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs); 1335 } else if (type == 1336 IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){ 1337 if (size != sizeof(int64_t)) { 1338 return INVALID_OPERATION; 1339 } 1340 1341 int64_t maxGapUs = *(int64_t *)data; 1342 CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs); 1343 return bufferSource->setMaxTimestampGapUs(maxGapUs); 1344 } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) { 1345 if (size != sizeof(float)) { 1346 return INVALID_OPERATION; 1347 } 1348 1349 float maxFps = *(float *)data; 1350 CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps); 1351 return bufferSource->setMaxFps(maxFps); 1352 } else if (type == IOMX::INTERNAL_OPTION_START_TIME) { 1353 if (size != sizeof(int64_t)) { 1354 return INVALID_OPERATION; 1355 } 1356 1357 int64_t skipFramesBeforeUs = *(int64_t *)data; 1358 CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs); 1359 bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs); 1360 } else { // IOMX::INTERNAL_OPTION_TIME_LAPSE 1361 if (size != sizeof(int64_t) * 2) { 1362 return INVALID_OPERATION; 1363 } 1364 1365 int64_t timePerFrameUs = ((int64_t *)data)[0]; 1366 int64_t timePerCaptureUs = ((int64_t *)data)[1]; 1367 CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld", 1368 (long long)timePerFrameUs, (long long)timePerCaptureUs); 1369 1370 bufferSource->setTimeLapseUs((int64_t *)data); 1371 } 1372 1373 return OK; 1374 } 1375 1376 default: 1377 return ERROR_UNSUPPORTED; 1378 } 1379 } 1380 1381 bool OMXNodeInstance::handleMessage(omx_message &msg) { 1382 const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource()); 1383 1384 if (msg.type == omx_message::FILL_BUFFER_DONE) { 1385 OMX_BUFFERHEADERTYPE *buffer = 1386 findBufferHeader(msg.u.extended_buffer_data.buffer); 1387 1388 { 1389 Mutex::Autolock _l(mDebugLock); 1390 mOutputBuffersWithCodec.remove(buffer); 1391 1392 CLOG_BUMPED_BUFFER( 1393 FBD, WITH_STATS(FULL_BUFFER( 1394 msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd))); 1395 1396 unbumpDebugLevel_l(kPortIndexOutput); 1397 } 1398 1399 BufferMeta *buffer_meta = 1400 static_cast<BufferMeta *>(buffer->pAppPrivate); 1401 1402 if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset 1403 || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) { 1404 CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter, 1405 FULL_BUFFER(NULL, buffer, msg.fenceFd)); 1406 } 1407 buffer_meta->CopyFromOMX(buffer); 1408 1409 if (bufferSource != NULL) { 1410 // fix up the buffer info (especially timestamp) if needed 1411 bufferSource->codecBufferFilled(buffer); 1412 1413 msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp; 1414 } 1415 } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) { 1416 OMX_BUFFERHEADERTYPE *buffer = 1417 findBufferHeader(msg.u.buffer_data.buffer); 1418 1419 { 1420 Mutex::Autolock _l(mDebugLock); 1421 mInputBuffersWithCodec.remove(buffer); 1422 1423 CLOG_BUMPED_BUFFER( 1424 EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd))); 1425 } 1426 1427 if (bufferSource != NULL) { 1428 // This is one of the buffers used exclusively by 1429 // GraphicBufferSource. 1430 // Don't dispatch a message back to ACodec, since it doesn't 1431 // know that anyone asked to have the buffer emptied and will 1432 // be very confused. 1433 bufferSource->codecBufferEmptied(buffer, msg.fenceFd); 1434 return true; 1435 } 1436 } 1437 1438 return false; 1439 } 1440 1441 void OMXNodeInstance::onMessages(std::list<omx_message> &messages) { 1442 for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) { 1443 if (handleMessage(*it)) { 1444 messages.erase(it++); 1445 } else { 1446 ++it; 1447 } 1448 } 1449 1450 if (!messages.empty()) { 1451 mObserver->onMessages(messages); 1452 } 1453 } 1454 1455 void OMXNodeInstance::onObserverDied(OMXMaster *master) { 1456 ALOGE("!!! Observer died. Quickly, do something, ... anything..."); 1457 1458 // Try to force shutdown of the node and hope for the best. 1459 freeNode(master); 1460 } 1461 1462 void OMXNodeInstance::onGetHandleFailed() { 1463 delete this; 1464 } 1465 1466 // OMXNodeInstance::OnEvent calls OMX::OnEvent, which then calls here. 1467 // Don't try to acquire mLock here -- in rare circumstances this will hang. 1468 void OMXNodeInstance::onEvent( 1469 OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) { 1470 const char *arg1String = "??"; 1471 const char *arg2String = "??"; 1472 ADebug::Level level = ADebug::kDebugInternalState; 1473 1474 switch (event) { 1475 case OMX_EventCmdComplete: 1476 arg1String = asString((OMX_COMMANDTYPE)arg1); 1477 switch (arg1) { 1478 case OMX_CommandStateSet: 1479 arg2String = asString((OMX_STATETYPE)arg2); 1480 level = ADebug::kDebugState; 1481 break; 1482 case OMX_CommandFlush: 1483 case OMX_CommandPortEnable: 1484 { 1485 // bump internal-state debug level for 2 input and output frames 1486 Mutex::Autolock _l(mDebugLock); 1487 bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */); 1488 } 1489 // fall through 1490 default: 1491 arg2String = portString(arg2); 1492 } 1493 break; 1494 case OMX_EventError: 1495 arg1String = asString((OMX_ERRORTYPE)arg1); 1496 level = ADebug::kDebugLifeCycle; 1497 break; 1498 case OMX_EventPortSettingsChanged: 1499 arg2String = asString((OMX_INDEXEXTTYPE)arg2); 1500 // fall through 1501 default: 1502 arg1String = portString(arg1); 1503 } 1504 1505 CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)", 1506 asString(event), event, arg1String, arg1, arg2String, arg2); 1507 const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource()); 1508 1509 if (bufferSource != NULL 1510 && event == OMX_EventCmdComplete 1511 && arg1 == OMX_CommandStateSet 1512 && arg2 == OMX_StateExecuting) { 1513 bufferSource->omxExecuting(); 1514 } 1515 } 1516 1517 // static 1518 OMX_ERRORTYPE OMXNodeInstance::OnEvent( 1519 OMX_IN OMX_HANDLETYPE /* hComponent */, 1520 OMX_IN OMX_PTR pAppData, 1521 OMX_IN OMX_EVENTTYPE eEvent, 1522 OMX_IN OMX_U32 nData1, 1523 OMX_IN OMX_U32 nData2, 1524 OMX_IN OMX_PTR pEventData) { 1525 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 1526 if (instance->mDying) { 1527 return OMX_ErrorNone; 1528 } 1529 return instance->owner()->OnEvent( 1530 instance->nodeID(), eEvent, nData1, nData2, pEventData); 1531 } 1532 1533 // static 1534 OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( 1535 OMX_IN OMX_HANDLETYPE /* hComponent */, 1536 OMX_IN OMX_PTR pAppData, 1537 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 1538 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 1539 if (instance->mDying) { 1540 return OMX_ErrorNone; 1541 } 1542 int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput); 1543 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), 1544 instance->findBufferID(pBuffer), pBuffer, fenceFd); 1545 } 1546 1547 // static 1548 OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone( 1549 OMX_IN OMX_HANDLETYPE /* hComponent */, 1550 OMX_IN OMX_PTR pAppData, 1551 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { 1552 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData); 1553 if (instance->mDying) { 1554 return OMX_ErrorNone; 1555 } 1556 int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput); 1557 return instance->owner()->OnFillBufferDone(instance->nodeID(), 1558 instance->findBufferID(pBuffer), pBuffer, fenceFd); 1559 } 1560 1561 void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) { 1562 ActiveBuffer active; 1563 active.mPortIndex = portIndex; 1564 active.mID = id; 1565 mActiveBuffers.push(active); 1566 1567 if (portIndex < NELEM(mNumPortBuffers)) { 1568 ++mNumPortBuffers[portIndex]; 1569 } 1570 } 1571 1572 void OMXNodeInstance::removeActiveBuffer( 1573 OMX_U32 portIndex, OMX::buffer_id id) { 1574 for (size_t i = 0; i < mActiveBuffers.size(); ++i) { 1575 if (mActiveBuffers[i].mPortIndex == portIndex 1576 && mActiveBuffers[i].mID == id) { 1577 mActiveBuffers.removeItemsAt(i); 1578 1579 if (portIndex < NELEM(mNumPortBuffers)) { 1580 --mNumPortBuffers[portIndex]; 1581 } 1582 return; 1583 } 1584 } 1585 1586 CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id); 1587 } 1588 1589 void OMXNodeInstance::freeActiveBuffers() { 1590 // Make sure to count down here, as freeBuffer will in turn remove 1591 // the active buffer from the vector... 1592 for (size_t i = mActiveBuffers.size(); i--;) { 1593 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID); 1594 } 1595 } 1596 1597 OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { 1598 if (bufferHeader == NULL) { 1599 return 0; 1600 } 1601 Mutex::Autolock autoLock(mBufferIDLock); 1602 OMX::buffer_id buffer; 1603 do { // handle the very unlikely case of ID overflow 1604 if (++mBufferIDCount == 0) { 1605 ++mBufferIDCount; 1606 } 1607 buffer = (OMX::buffer_id)mBufferIDCount; 1608 } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0); 1609 mBufferIDToBufferHeader.add(buffer, bufferHeader); 1610 mBufferHeaderToBufferID.add(bufferHeader, buffer); 1611 return buffer; 1612 } 1613 1614 OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) { 1615 if (buffer == 0) { 1616 return NULL; 1617 } 1618 Mutex::Autolock autoLock(mBufferIDLock); 1619 ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); 1620 if (index < 0) { 1621 CLOGW("findBufferHeader: buffer %u not found", buffer); 1622 return NULL; 1623 } 1624 return mBufferIDToBufferHeader.valueAt(index); 1625 } 1626 1627 OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { 1628 if (bufferHeader == NULL) { 1629 return 0; 1630 } 1631 Mutex::Autolock autoLock(mBufferIDLock); 1632 ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader); 1633 if (index < 0) { 1634 CLOGW("findBufferID: bufferHeader %p not found", bufferHeader); 1635 return 0; 1636 } 1637 return mBufferHeaderToBufferID.valueAt(index); 1638 } 1639 1640 void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) { 1641 if (buffer == 0) { 1642 return; 1643 } 1644 Mutex::Autolock autoLock(mBufferIDLock); 1645 ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); 1646 if (index < 0) { 1647 CLOGW("invalidateBufferID: buffer %u not found", buffer); 1648 return; 1649 } 1650 mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index)); 1651 mBufferIDToBufferHeader.removeItemsAt(index); 1652 } 1653 1654 } // namespace android 1655