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