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