GraphicBufferSource.cpp revision db43b34c3428e480f8c4c66e7e88f4001f37f91e
1/* 2 * Copyright (C) 2013 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#include <inttypes.h> 18 19#define LOG_TAG "GraphicBufferSource" 20//#define LOG_NDEBUG 0 21#include <utils/Log.h> 22 23#include "GraphicBufferSource.h" 24 25#include <OMX_Core.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28 29#include <media/hardware/MetadataBufferType.h> 30#include <ui/GraphicBuffer.h> 31 32namespace android { 33 34static const bool EXTRA_CHECK = true; 35 36 37GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, 38 uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) : 39 mInitCheck(UNKNOWN_ERROR), 40 mNodeInstance(nodeInstance), 41 mExecuting(false), 42 mSuspended(false), 43 mNumFramesAvailable(0), 44 mEndOfStream(false), 45 mEndOfStreamSent(false), 46 mRepeatAfterUs(-1ll), 47 mRepeatLastFrameGeneration(0), 48 mLatestSubmittedBufferId(-1), 49 mLatestSubmittedBufferFrameNum(0), 50 mLatestSubmittedBufferUseCount(0), 51 mRepeatBufferDeferred(false) { 52 53 ALOGV("GraphicBufferSource w=%u h=%u c=%u", 54 bufferWidth, bufferHeight, bufferCount); 55 56 if (bufferWidth == 0 || bufferHeight == 0) { 57 ALOGE("Invalid dimensions %ux%u", bufferWidth, bufferHeight); 58 mInitCheck = BAD_VALUE; 59 return; 60 } 61 62 String8 name("GraphicBufferSource"); 63 64 mBufferQueue = new BufferQueue(); 65 mBufferQueue->setConsumerName(name); 66 mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); 67 mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | 68 GRALLOC_USAGE_HW_TEXTURE); 69 70 mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount); 71 if (mInitCheck != NO_ERROR) { 72 ALOGE("Unable to set BQ max acquired buffer count to %u: %d", 73 bufferCount, mInitCheck); 74 return; 75 } 76 77 // Note that we can't create an sp<...>(this) in a ctor that will not keep a 78 // reference once the ctor ends, as that would cause the refcount of 'this' 79 // dropping to 0 at the end of the ctor. Since all we need is a wp<...> 80 // that's what we create. 81 wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this); 82 sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); 83 84 mInitCheck = mBufferQueue->consumerConnect(proxy, false); 85 if (mInitCheck != NO_ERROR) { 86 ALOGE("Error connecting to BufferQueue: %s (%d)", 87 strerror(-mInitCheck), mInitCheck); 88 return; 89 } 90 91 CHECK(mInitCheck == NO_ERROR); 92} 93 94GraphicBufferSource::~GraphicBufferSource() { 95 ALOGV("~GraphicBufferSource"); 96 if (mBufferQueue != NULL) { 97 status_t err = mBufferQueue->consumerDisconnect(); 98 if (err != NO_ERROR) { 99 ALOGW("consumerDisconnect failed: %d", err); 100 } 101 } 102} 103 104void GraphicBufferSource::omxExecuting() { 105 Mutex::Autolock autoLock(mMutex); 106 ALOGV("--> executing; avail=%d, codec vec size=%zd", 107 mNumFramesAvailable, mCodecBuffers.size()); 108 CHECK(!mExecuting); 109 mExecuting = true; 110 111 // Start by loading up as many buffers as possible. We want to do this, 112 // rather than just submit the first buffer, to avoid a degenerate case: 113 // if all BQ buffers arrive before we start executing, and we only submit 114 // one here, the other BQ buffers will just sit until we get notified 115 // that the codec buffer has been released. We'd then acquire and 116 // submit a single additional buffer, repeatedly, never using more than 117 // one codec buffer simultaneously. (We could instead try to submit 118 // all BQ buffers whenever any codec buffer is freed, but if we get the 119 // initial conditions right that will never be useful.) 120 while (mNumFramesAvailable) { 121 if (!fillCodecBuffer_l()) { 122 ALOGV("stop load with frames available (codecAvail=%d)", 123 isCodecBufferAvailable_l()); 124 break; 125 } 126 } 127 128 ALOGV("done loading initial frames, avail=%d", mNumFramesAvailable); 129 130 // If EOS has already been signaled, and there are no more frames to 131 // submit, try to send EOS now as well. 132 if (mEndOfStream && mNumFramesAvailable == 0) { 133 submitEndOfInputStream_l(); 134 } 135 136 if (mRepeatAfterUs > 0ll && mLooper == NULL) { 137 mReflector = new AHandlerReflector<GraphicBufferSource>(this); 138 139 mLooper = new ALooper; 140 mLooper->registerHandler(mReflector); 141 mLooper->start(); 142 143 if (mLatestSubmittedBufferId >= 0) { 144 sp<AMessage> msg = 145 new AMessage(kWhatRepeatLastFrame, mReflector->id()); 146 147 msg->setInt32("generation", ++mRepeatLastFrameGeneration); 148 msg->post(mRepeatAfterUs); 149 } 150 } 151} 152 153void GraphicBufferSource::omxIdle() { 154 ALOGV("omxIdle"); 155 156 Mutex::Autolock autoLock(mMutex); 157 158 if (mExecuting) { 159 // We are only interested in the transition from executing->idle, 160 // not loaded->idle. 161 mExecuting = false; 162 } 163} 164 165void GraphicBufferSource::omxLoaded(){ 166 Mutex::Autolock autoLock(mMutex); 167 if (!mExecuting) { 168 // This can happen if something failed very early. 169 ALOGW("Dropped back down to Loaded without Executing"); 170 } 171 172 if (mLooper != NULL) { 173 mLooper->unregisterHandler(mReflector->id()); 174 mReflector.clear(); 175 176 mLooper->stop(); 177 mLooper.clear(); 178 } 179 180 ALOGV("--> loaded; avail=%d eos=%d eosSent=%d", 181 mNumFramesAvailable, mEndOfStream, mEndOfStreamSent); 182 183 // Codec is no longer executing. Discard all codec-related state. 184 mCodecBuffers.clear(); 185 // TODO: scan mCodecBuffers to verify that all mGraphicBuffer entries 186 // are null; complain if not 187 188 mExecuting = false; 189} 190 191void GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) { 192 Mutex::Autolock autoLock(mMutex); 193 194 if (mExecuting) { 195 // This should never happen -- buffers can only be allocated when 196 // transitioning from "loaded" to "idle". 197 ALOGE("addCodecBuffer: buffer added while executing"); 198 return; 199 } 200 201 ALOGV("addCodecBuffer h=%p size=%" PRIu32 " p=%p", 202 header, header->nAllocLen, header->pBuffer); 203 CodecBuffer codecBuffer; 204 codecBuffer.mHeader = header; 205 mCodecBuffers.add(codecBuffer); 206} 207 208void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { 209 Mutex::Autolock autoLock(mMutex); 210 211 if (!mExecuting) { 212 return; 213 } 214 215 int cbi = findMatchingCodecBuffer_l(header); 216 if (cbi < 0) { 217 // This should never happen. 218 ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); 219 return; 220 } 221 222 ALOGV("codecBufferEmptied h=%p size=%" PRIu32 " filled=%" PRIu32 " p=%p", 223 header, header->nAllocLen, header->nFilledLen, 224 header->pBuffer); 225 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 226 227 // header->nFilledLen may not be the original value, so we can't compare 228 // that to zero to see of this was the EOS buffer. Instead we just 229 // see if the GraphicBuffer reference was null, which should only ever 230 // happen for EOS. 231 if (codecBuffer.mGraphicBuffer == NULL) { 232 if (!(mEndOfStream && mEndOfStreamSent)) { 233 // This can happen when broken code sends us the same buffer 234 // twice in a row. 235 ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer " 236 "(buffer emptied twice?)"); 237 } 238 // No GraphicBuffer to deal with, no additional input or output is 239 // expected, so just return. 240 return; 241 } 242 243 if (EXTRA_CHECK) { 244 // Pull the graphic buffer handle back out of the buffer, and confirm 245 // that it matches expectations. 246 OMX_U8* data = header->pBuffer; 247 buffer_handle_t bufferHandle; 248 memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); 249 if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { 250 // should never happen 251 ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", 252 bufferHandle, codecBuffer.mGraphicBuffer->handle); 253 CHECK(!"codecBufferEmptied: mismatched buffer"); 254 } 255 } 256 257 // Find matching entry in our cached copy of the BufferQueue slots. 258 // If we find a match, release that slot. If we don't, the BufferQueue 259 // has dropped that GraphicBuffer, and there's nothing for us to release. 260 int id = codecBuffer.mBuf; 261 if (mBufferSlot[id] != NULL && 262 mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { 263 ALOGV("cbi %d matches bq slot %d, handle=%p", 264 cbi, id, mBufferSlot[id]->handle); 265 266 if (id == mLatestSubmittedBufferId) { 267 CHECK_GT(mLatestSubmittedBufferUseCount--, 0); 268 } else { 269 mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, 270 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 271 } 272 } else { 273 ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", 274 cbi); 275 } 276 277 // Mark the codec buffer as available by clearing the GraphicBuffer ref. 278 codecBuffer.mGraphicBuffer = NULL; 279 280 if (mNumFramesAvailable) { 281 // Fill this codec buffer. 282 CHECK(!mEndOfStreamSent); 283 ALOGV("buffer freed, %d frames avail (eos=%d)", 284 mNumFramesAvailable, mEndOfStream); 285 fillCodecBuffer_l(); 286 } else if (mEndOfStream) { 287 // No frames available, but EOS is pending, so use this buffer to 288 // send that. 289 ALOGV("buffer freed, EOS pending"); 290 submitEndOfInputStream_l(); 291 } else if (mRepeatBufferDeferred) { 292 bool success = repeatLatestSubmittedBuffer_l(); 293 if (success) { 294 ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS"); 295 } else { 296 ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE"); 297 } 298 mRepeatBufferDeferred = false; 299 } 300 301 return; 302} 303 304void GraphicBufferSource::suspend(bool suspend) { 305 Mutex::Autolock autoLock(mMutex); 306 307 if (suspend) { 308 mSuspended = true; 309 310 while (mNumFramesAvailable > 0) { 311 BufferQueue::BufferItem item; 312 status_t err = mBufferQueue->acquireBuffer(&item, 0); 313 314 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 315 // shouldn't happen. 316 ALOGW("suspend: frame was not available"); 317 break; 318 } else if (err != OK) { 319 ALOGW("suspend: acquireBuffer returned err=%d", err); 320 break; 321 } 322 323 --mNumFramesAvailable; 324 325 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 326 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 327 } 328 return; 329 } 330 331 mSuspended = false; 332 333 if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) { 334 if (repeatLatestSubmittedBuffer_l()) { 335 ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS"); 336 337 mRepeatBufferDeferred = false; 338 } else { 339 ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE"); 340 } 341 } 342} 343 344bool GraphicBufferSource::fillCodecBuffer_l() { 345 CHECK(mExecuting && mNumFramesAvailable > 0); 346 347 if (mSuspended) { 348 return false; 349 } 350 351 int cbi = findAvailableCodecBuffer_l(); 352 if (cbi < 0) { 353 // No buffers available, bail. 354 ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d", 355 mNumFramesAvailable); 356 return false; 357 } 358 359 ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", 360 mNumFramesAvailable); 361 BufferQueue::BufferItem item; 362 status_t err = mBufferQueue->acquireBuffer(&item, 0); 363 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 364 // shouldn't happen 365 ALOGW("fillCodecBuffer_l: frame was not available"); 366 return false; 367 } else if (err != OK) { 368 // now what? fake end-of-stream? 369 ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err); 370 return false; 371 } 372 373 mNumFramesAvailable--; 374 375 // Wait for it to become available. 376 err = item.mFence->waitForever("GraphicBufferSource::fillCodecBuffer_l"); 377 if (err != OK) { 378 ALOGW("failed to wait for buffer fence: %d", err); 379 // keep going 380 } 381 382 // If this is the first time we're seeing this buffer, add it to our 383 // slot table. 384 if (item.mGraphicBuffer != NULL) { 385 ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); 386 mBufferSlot[item.mBuf] = item.mGraphicBuffer; 387 } 388 389 err = submitBuffer_l(item, cbi); 390 if (err != OK) { 391 ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); 392 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 393 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 394 } else { 395 ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); 396 setLatestSubmittedBuffer_l(item); 397 } 398 399 return true; 400} 401 402bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { 403 CHECK(mExecuting && mNumFramesAvailable == 0); 404 405 if (mLatestSubmittedBufferId < 0 || mSuspended) { 406 return false; 407 } 408 if (mBufferSlot[mLatestSubmittedBufferId] == NULL) { 409 // This can happen if the remote side disconnects, causing 410 // onBuffersReleased() to NULL out our copy of the slots. The 411 // buffer is gone, so we have nothing to show. 412 // 413 // To be on the safe side we try to release the buffer. 414 ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL"); 415 mBufferQueue->releaseBuffer( 416 mLatestSubmittedBufferId, 417 mLatestSubmittedBufferFrameNum, 418 EGL_NO_DISPLAY, 419 EGL_NO_SYNC_KHR, 420 Fence::NO_FENCE); 421 mLatestSubmittedBufferId = -1; 422 mLatestSubmittedBufferFrameNum = 0; 423 return false; 424 } 425 426 int cbi = findAvailableCodecBuffer_l(); 427 if (cbi < 0) { 428 // No buffers available, bail. 429 ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers."); 430 return false; 431 } 432 433 BufferQueue::BufferItem item; 434 item.mBuf = mLatestSubmittedBufferId; 435 item.mFrameNumber = mLatestSubmittedBufferFrameNum; 436 437 status_t err = submitBuffer_l(item, cbi); 438 439 if (err != OK) { 440 return false; 441 } 442 443 ++mLatestSubmittedBufferUseCount; 444 445 return true; 446} 447 448void GraphicBufferSource::setLatestSubmittedBuffer_l( 449 const BufferQueue::BufferItem &item) { 450 ALOGV("setLatestSubmittedBuffer_l"); 451 452 if (mLatestSubmittedBufferId >= 0) { 453 if (mLatestSubmittedBufferUseCount == 0) { 454 mBufferQueue->releaseBuffer( 455 mLatestSubmittedBufferId, 456 mLatestSubmittedBufferFrameNum, 457 EGL_NO_DISPLAY, 458 EGL_NO_SYNC_KHR, 459 Fence::NO_FENCE); 460 } 461 } 462 463 mLatestSubmittedBufferId = item.mBuf; 464 mLatestSubmittedBufferFrameNum = item.mFrameNumber; 465 mLatestSubmittedBufferUseCount = 1; 466 mRepeatBufferDeferred = false; 467 468 if (mReflector != NULL) { 469 sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); 470 msg->setInt32("generation", ++mRepeatLastFrameGeneration); 471 msg->post(mRepeatAfterUs); 472 } 473} 474 475status_t GraphicBufferSource::signalEndOfInputStream() { 476 Mutex::Autolock autoLock(mMutex); 477 ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d", 478 mExecuting, mNumFramesAvailable, mEndOfStream); 479 480 if (mEndOfStream) { 481 ALOGE("EOS was already signaled"); 482 return INVALID_OPERATION; 483 } 484 485 // Set the end-of-stream flag. If no frames are pending from the 486 // BufferQueue, and a codec buffer is available, and we're executing, 487 // we initiate the EOS from here. Otherwise, we'll let 488 // codecBufferEmptied() (or omxExecuting) do it. 489 // 490 // Note: if there are no pending frames and all codec buffers are 491 // available, we *must* submit the EOS from here or we'll just 492 // stall since no future events are expected. 493 mEndOfStream = true; 494 495 if (mExecuting && mNumFramesAvailable == 0) { 496 submitEndOfInputStream_l(); 497 } 498 499 return OK; 500} 501 502status_t GraphicBufferSource::submitBuffer_l( 503 const BufferQueue::BufferItem &item, int cbi) { 504 ALOGV("submitBuffer_l cbi=%d", cbi); 505 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 506 codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf]; 507 codecBuffer.mBuf = item.mBuf; 508 codecBuffer.mFrameNumber = item.mFrameNumber; 509 510 OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 511 CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t)); 512 OMX_U8* data = header->pBuffer; 513 const OMX_U32 type = kMetadataBufferTypeGrallocSource; 514 buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle; 515 memcpy(data, &type, 4); 516 memcpy(data + 4, &handle, sizeof(buffer_handle_t)); 517 518 status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 519 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, 520 item.mTimestamp / 1000); 521 if (err != OK) { 522 ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err); 523 codecBuffer.mGraphicBuffer = NULL; 524 return err; 525 } 526 527 ALOGV("emptyDirectBuffer succeeded, h=%p p=%p bufhandle=%p", 528 header, header->pBuffer, handle); 529 return OK; 530} 531 532void GraphicBufferSource::submitEndOfInputStream_l() { 533 CHECK(mEndOfStream); 534 if (mEndOfStreamSent) { 535 ALOGV("EOS already sent"); 536 return; 537 } 538 539 int cbi = findAvailableCodecBuffer_l(); 540 if (cbi < 0) { 541 ALOGV("submitEndOfInputStream_l: no codec buffers available"); 542 return; 543 } 544 545 // We reject any additional incoming graphic buffers, so there's no need 546 // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as 547 // in-use. 548 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 549 550 OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 551 if (EXTRA_CHECK) { 552 // Guard against implementations that don't check nFilledLen. 553 size_t fillLen = 4 + sizeof(buffer_handle_t); 554 CHECK(header->nAllocLen >= fillLen); 555 OMX_U8* data = header->pBuffer; 556 memset(data, 0xcd, fillLen); 557 } 558 559 uint64_t timestamp = 0; // does this matter? 560 561 status_t err = mNodeInstance->emptyDirectBuffer(header, /*offset*/ 0, 562 /*length*/ 0, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, 563 timestamp); 564 if (err != OK) { 565 ALOGW("emptyDirectBuffer EOS failed: 0x%x", err); 566 } else { 567 ALOGV("submitEndOfInputStream_l: buffer submitted, header=%p cbi=%d", 568 header, cbi); 569 mEndOfStreamSent = true; 570 } 571} 572 573int GraphicBufferSource::findAvailableCodecBuffer_l() { 574 CHECK(mCodecBuffers.size() > 0); 575 576 for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 577 if (mCodecBuffers[i].mGraphicBuffer == NULL) { 578 return i; 579 } 580 } 581 return -1; 582} 583 584int GraphicBufferSource::findMatchingCodecBuffer_l( 585 const OMX_BUFFERHEADERTYPE* header) { 586 for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 587 if (mCodecBuffers[i].mHeader == header) { 588 return i; 589 } 590 } 591 return -1; 592} 593 594// BufferQueue::ConsumerListener callback 595void GraphicBufferSource::onFrameAvailable() { 596 Mutex::Autolock autoLock(mMutex); 597 598 ALOGV("onFrameAvailable exec=%d avail=%d", 599 mExecuting, mNumFramesAvailable); 600 601 if (mEndOfStream || mSuspended) { 602 if (mEndOfStream) { 603 // This should only be possible if a new buffer was queued after 604 // EOS was signaled, i.e. the app is misbehaving. 605 606 ALOGW("onFrameAvailable: EOS is set, ignoring frame"); 607 } else { 608 ALOGV("onFrameAvailable: suspended, ignoring frame"); 609 } 610 611 BufferQueue::BufferItem item; 612 status_t err = mBufferQueue->acquireBuffer(&item, 0); 613 if (err == OK) { 614 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 615 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 616 } 617 return; 618 } 619 620 mNumFramesAvailable++; 621 622 mRepeatBufferDeferred = false; 623 ++mRepeatLastFrameGeneration; 624 625 if (mExecuting) { 626 fillCodecBuffer_l(); 627 } 628} 629 630// BufferQueue::ConsumerListener callback 631void GraphicBufferSource::onBuffersReleased() { 632 Mutex::Autolock lock(mMutex); 633 634 uint32_t slotMask; 635 if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) { 636 ALOGW("onBuffersReleased: unable to get released buffer set"); 637 slotMask = 0xffffffff; 638 } 639 640 ALOGV("onBuffersReleased: 0x%08x", slotMask); 641 642 for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { 643 if ((slotMask & 0x01) != 0) { 644 mBufferSlot[i] = NULL; 645 } 646 slotMask >>= 1; 647 } 648} 649 650status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs( 651 int64_t repeatAfterUs) { 652 Mutex::Autolock autoLock(mMutex); 653 654 if (mExecuting || repeatAfterUs <= 0ll) { 655 return INVALID_OPERATION; 656 } 657 658 mRepeatAfterUs = repeatAfterUs; 659 660 return OK; 661} 662 663void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) { 664 switch (msg->what()) { 665 case kWhatRepeatLastFrame: 666 { 667 Mutex::Autolock autoLock(mMutex); 668 669 int32_t generation; 670 CHECK(msg->findInt32("generation", &generation)); 671 672 if (generation != mRepeatLastFrameGeneration) { 673 // stale 674 break; 675 } 676 677 if (!mExecuting || mNumFramesAvailable > 0) { 678 break; 679 } 680 681 bool success = repeatLatestSubmittedBuffer_l(); 682 683 if (success) { 684 ALOGV("repeatLatestSubmittedBuffer_l SUCCESS"); 685 } else { 686 ALOGV("repeatLatestSubmittedBuffer_l FAILURE"); 687 mRepeatBufferDeferred = true; 688 } 689 break; 690 } 691 692 default: 693 TRESPASS(); 694 } 695} 696 697} // namespace android 698