GraphicBufferSource.cpp revision 1c608ab33acab82d4a87f1abedcc99a623d1b53a
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::omxIdle() { 152 ALOGV("omxIdle"); 153 154 Mutex::Autolock autoLock(mMutex); 155 156 if (mExecuting) { 157 // We are only interested in the transition from executing->idle, 158 // not loaded->idle. 159 mExecuting = false; 160 } 161} 162 163void GraphicBufferSource::omxLoaded(){ 164 Mutex::Autolock autoLock(mMutex); 165 if (!mExecuting) { 166 // This can happen if something failed very early. 167 ALOGW("Dropped back down to Loaded without Executing"); 168 } 169 170 if (mLooper != NULL) { 171 mLooper->unregisterHandler(mReflector->id()); 172 mReflector.clear(); 173 174 mLooper->stop(); 175 mLooper.clear(); 176 } 177 178 ALOGV("--> loaded; avail=%d eos=%d eosSent=%d", 179 mNumFramesAvailable, mEndOfStream, mEndOfStreamSent); 180 181 // Codec is no longer executing. Discard all codec-related state. 182 mCodecBuffers.clear(); 183 // TODO: scan mCodecBuffers to verify that all mGraphicBuffer entries 184 // are null; complain if not 185 186 mExecuting = false; 187} 188 189void GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) { 190 Mutex::Autolock autoLock(mMutex); 191 192 if (mExecuting) { 193 // This should never happen -- buffers can only be allocated when 194 // transitioning from "loaded" to "idle". 195 ALOGE("addCodecBuffer: buffer added while executing"); 196 return; 197 } 198 199 ALOGV("addCodecBuffer h=%p size=%lu p=%p", 200 header, header->nAllocLen, header->pBuffer); 201 CodecBuffer codecBuffer; 202 codecBuffer.mHeader = header; 203 mCodecBuffers.add(codecBuffer); 204} 205 206void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { 207 Mutex::Autolock autoLock(mMutex); 208 209 if (!mExecuting) { 210 return; 211 } 212 213 int cbi = findMatchingCodecBuffer_l(header); 214 if (cbi < 0) { 215 // This should never happen. 216 ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); 217 return; 218 } 219 220 ALOGV("codecBufferEmptied h=%p size=%lu filled=%lu p=%p", 221 header, header->nAllocLen, header->nFilledLen, 222 header->pBuffer); 223 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 224 225 // header->nFilledLen may not be the original value, so we can't compare 226 // that to zero to see of this was the EOS buffer. Instead we just 227 // see if the GraphicBuffer reference was null, which should only ever 228 // happen for EOS. 229 if (codecBuffer.mGraphicBuffer == NULL) { 230 if (!(mEndOfStream && mEndOfStreamSent)) { 231 // This can happen when broken code sends us the same buffer 232 // twice in a row. 233 ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer " 234 "(buffer emptied twice?)"); 235 } 236 // No GraphicBuffer to deal with, no additional input or output is 237 // expected, so just return. 238 return; 239 } 240 241 if (EXTRA_CHECK) { 242 // Pull the graphic buffer handle back out of the buffer, and confirm 243 // that it matches expectations. 244 OMX_U8* data = header->pBuffer; 245 buffer_handle_t bufferHandle; 246 memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); 247 if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { 248 // should never happen 249 ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", 250 bufferHandle, codecBuffer.mGraphicBuffer->handle); 251 CHECK(!"codecBufferEmptied: mismatched buffer"); 252 } 253 } 254 255 // Find matching entry in our cached copy of the BufferQueue slots. 256 // If we find a match, release that slot. If we don't, the BufferQueue 257 // has dropped that GraphicBuffer, and there's nothing for us to release. 258 int id = codecBuffer.mBuf; 259 if (mBufferSlot[id] != NULL && 260 mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { 261 ALOGV("cbi %d matches bq slot %d, handle=%p", 262 cbi, id, mBufferSlot[id]->handle); 263 264 if (id == mLatestSubmittedBufferId) { 265 CHECK_GT(mLatestSubmittedBufferUseCount--, 0); 266 } else { 267 mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, 268 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 269 } 270 } else { 271 ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", 272 cbi); 273 } 274 275 // Mark the codec buffer as available by clearing the GraphicBuffer ref. 276 codecBuffer.mGraphicBuffer = NULL; 277 278 if (mNumFramesAvailable) { 279 // Fill this codec buffer. 280 CHECK(!mEndOfStreamSent); 281 ALOGV("buffer freed, %d frames avail (eos=%d)", 282 mNumFramesAvailable, mEndOfStream); 283 fillCodecBuffer_l(); 284 } else if (mEndOfStream) { 285 // No frames available, but EOS is pending, so use this buffer to 286 // send that. 287 ALOGV("buffer freed, EOS pending"); 288 submitEndOfInputStream_l(); 289 } else if (mRepeatBufferDeferred) { 290 bool success = repeatLatestSubmittedBuffer_l(); 291 if (success) { 292 ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS"); 293 } else { 294 ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE"); 295 } 296 mRepeatBufferDeferred = false; 297 } 298 299 return; 300} 301 302void GraphicBufferSource::suspend(bool suspend) { 303 Mutex::Autolock autoLock(mMutex); 304 305 if (suspend) { 306 mSuspended = true; 307 308 while (mNumFramesAvailable > 0) { 309 BufferQueue::BufferItem item; 310 status_t err = mBufferQueue->acquireBuffer(&item, 0); 311 312 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 313 // shouldn't happen. 314 ALOGW("suspend: frame was not available"); 315 break; 316 } else if (err != OK) { 317 ALOGW("suspend: acquireBuffer returned err=%d", err); 318 break; 319 } 320 321 --mNumFramesAvailable; 322 323 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 324 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 325 } 326 return; 327 } 328 329 mSuspended = false; 330 331 if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) { 332 if (repeatLatestSubmittedBuffer_l()) { 333 ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS"); 334 335 mRepeatBufferDeferred = false; 336 } else { 337 ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE"); 338 } 339 } 340} 341 342bool GraphicBufferSource::fillCodecBuffer_l() { 343 CHECK(mExecuting && mNumFramesAvailable > 0); 344 345 if (mSuspended) { 346 return false; 347 } 348 349 int cbi = findAvailableCodecBuffer_l(); 350 if (cbi < 0) { 351 // No buffers available, bail. 352 ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d", 353 mNumFramesAvailable); 354 return false; 355 } 356 357 ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", 358 mNumFramesAvailable); 359 BufferQueue::BufferItem item; 360 status_t err = mBufferQueue->acquireBuffer(&item, 0); 361 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 362 // shouldn't happen 363 ALOGW("fillCodecBuffer_l: frame was not available"); 364 return false; 365 } else if (err != OK) { 366 // now what? fake end-of-stream? 367 ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err); 368 return false; 369 } 370 371 mNumFramesAvailable--; 372 373 // Wait for it to become available. 374 err = item.mFence->waitForever("GraphicBufferSource::fillCodecBuffer_l"); 375 if (err != OK) { 376 ALOGW("failed to wait for buffer fence: %d", err); 377 // keep going 378 } 379 380 // If this is the first time we're seeing this buffer, add it to our 381 // slot table. 382 if (item.mGraphicBuffer != NULL) { 383 ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); 384 mBufferSlot[item.mBuf] = item.mGraphicBuffer; 385 } 386 387 err = submitBuffer_l(item, cbi); 388 if (err != OK) { 389 ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); 390 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 391 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 392 } else { 393 ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); 394 setLatestSubmittedBuffer_l(item); 395 } 396 397 return true; 398} 399 400bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { 401 CHECK(mExecuting && mNumFramesAvailable == 0); 402 403 if (mLatestSubmittedBufferId < 0 || mSuspended) { 404 return false; 405 } 406 if (mBufferSlot[mLatestSubmittedBufferId] == NULL) { 407 // This can happen if the remote side disconnects, causing 408 // onBuffersReleased() to NULL out our copy of the slots. The 409 // buffer is gone, so we have nothing to show. 410 // 411 // To be on the safe side we try to release the buffer. 412 ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL"); 413 mBufferQueue->releaseBuffer( 414 mLatestSubmittedBufferId, 415 mLatestSubmittedBufferFrameNum, 416 EGL_NO_DISPLAY, 417 EGL_NO_SYNC_KHR, 418 Fence::NO_FENCE); 419 mLatestSubmittedBufferId = -1; 420 mLatestSubmittedBufferFrameNum = 0; 421 return false; 422 } 423 424 int cbi = findAvailableCodecBuffer_l(); 425 if (cbi < 0) { 426 // No buffers available, bail. 427 ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers."); 428 return false; 429 } 430 431 BufferQueue::BufferItem item; 432 item.mBuf = mLatestSubmittedBufferId; 433 item.mFrameNumber = mLatestSubmittedBufferFrameNum; 434 435 status_t err = submitBuffer_l(item, cbi); 436 437 if (err != OK) { 438 return false; 439 } 440 441 ++mLatestSubmittedBufferUseCount; 442 443 return true; 444} 445 446void GraphicBufferSource::setLatestSubmittedBuffer_l( 447 const BufferQueue::BufferItem &item) { 448 ALOGV("setLatestSubmittedBuffer_l"); 449 450 if (mLatestSubmittedBufferId >= 0) { 451 if (mLatestSubmittedBufferUseCount == 0) { 452 mBufferQueue->releaseBuffer( 453 mLatestSubmittedBufferId, 454 mLatestSubmittedBufferFrameNum, 455 EGL_NO_DISPLAY, 456 EGL_NO_SYNC_KHR, 457 Fence::NO_FENCE); 458 } 459 } 460 461 mLatestSubmittedBufferId = item.mBuf; 462 mLatestSubmittedBufferFrameNum = item.mFrameNumber; 463 mLatestSubmittedBufferUseCount = 1; 464 mRepeatBufferDeferred = false; 465 466 if (mReflector != NULL) { 467 sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); 468 msg->setInt32("generation", ++mRepeatLastFrameGeneration); 469 msg->post(mRepeatAfterUs); 470 } 471} 472 473status_t GraphicBufferSource::signalEndOfInputStream() { 474 Mutex::Autolock autoLock(mMutex); 475 ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d", 476 mExecuting, mNumFramesAvailable, mEndOfStream); 477 478 if (mEndOfStream) { 479 ALOGE("EOS was already signaled"); 480 return INVALID_OPERATION; 481 } 482 483 // Set the end-of-stream flag. If no frames are pending from the 484 // BufferQueue, and a codec buffer is available, and we're executing, 485 // we initiate the EOS from here. Otherwise, we'll let 486 // codecBufferEmptied() (or omxExecuting) do it. 487 // 488 // Note: if there are no pending frames and all codec buffers are 489 // available, we *must* submit the EOS from here or we'll just 490 // stall since no future events are expected. 491 mEndOfStream = true; 492 493 if (mExecuting && mNumFramesAvailable == 0) { 494 submitEndOfInputStream_l(); 495 } 496 497 return OK; 498} 499 500status_t GraphicBufferSource::submitBuffer_l( 501 const BufferQueue::BufferItem &item, int cbi) { 502 ALOGV("submitBuffer_l cbi=%d", cbi); 503 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 504 codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf]; 505 codecBuffer.mBuf = item.mBuf; 506 codecBuffer.mFrameNumber = item.mFrameNumber; 507 508 OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 509 CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t)); 510 OMX_U8* data = header->pBuffer; 511 const OMX_U32 type = kMetadataBufferTypeGrallocSource; 512 buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle; 513 memcpy(data, &type, 4); 514 memcpy(data + 4, &handle, sizeof(buffer_handle_t)); 515 516 status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 517 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, 518 item.mTimestamp / 1000); 519 if (err != OK) { 520 ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err); 521 codecBuffer.mGraphicBuffer = NULL; 522 return err; 523 } 524 525 ALOGV("emptyDirectBuffer succeeded, h=%p p=%p bufhandle=%p", 526 header, header->pBuffer, handle); 527 return OK; 528} 529 530void GraphicBufferSource::submitEndOfInputStream_l() { 531 CHECK(mEndOfStream); 532 if (mEndOfStreamSent) { 533 ALOGV("EOS already sent"); 534 return; 535 } 536 537 int cbi = findAvailableCodecBuffer_l(); 538 if (cbi < 0) { 539 ALOGV("submitEndOfInputStream_l: no codec buffers available"); 540 return; 541 } 542 543 // We reject any additional incoming graphic buffers, so there's no need 544 // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as 545 // in-use. 546 CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 547 548 OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 549 if (EXTRA_CHECK) { 550 // Guard against implementations that don't check nFilledLen. 551 size_t fillLen = 4 + sizeof(buffer_handle_t); 552 CHECK(header->nAllocLen >= fillLen); 553 OMX_U8* data = header->pBuffer; 554 memset(data, 0xcd, fillLen); 555 } 556 557 uint64_t timestamp = 0; // does this matter? 558 559 status_t err = mNodeInstance->emptyDirectBuffer(header, /*offset*/ 0, 560 /*length*/ 0, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, 561 timestamp); 562 if (err != OK) { 563 ALOGW("emptyDirectBuffer EOS failed: 0x%x", err); 564 } else { 565 ALOGV("submitEndOfInputStream_l: buffer submitted, header=%p cbi=%d", 566 header, cbi); 567 mEndOfStreamSent = true; 568 } 569} 570 571int GraphicBufferSource::findAvailableCodecBuffer_l() { 572 CHECK(mCodecBuffers.size() > 0); 573 574 for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 575 if (mCodecBuffers[i].mGraphicBuffer == NULL) { 576 return i; 577 } 578 } 579 return -1; 580} 581 582int GraphicBufferSource::findMatchingCodecBuffer_l( 583 const OMX_BUFFERHEADERTYPE* header) { 584 for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 585 if (mCodecBuffers[i].mHeader == header) { 586 return i; 587 } 588 } 589 return -1; 590} 591 592// BufferQueue::ConsumerListener callback 593void GraphicBufferSource::onFrameAvailable() { 594 Mutex::Autolock autoLock(mMutex); 595 596 ALOGV("onFrameAvailable exec=%d avail=%d", 597 mExecuting, mNumFramesAvailable); 598 599 if (mEndOfStream || mSuspended) { 600 if (mEndOfStream) { 601 // This should only be possible if a new buffer was queued after 602 // EOS was signaled, i.e. the app is misbehaving. 603 604 ALOGW("onFrameAvailable: EOS is set, ignoring frame"); 605 } else { 606 ALOGV("onFrameAvailable: suspended, ignoring frame"); 607 } 608 609 BufferQueue::BufferItem item; 610 status_t err = mBufferQueue->acquireBuffer(&item, 0); 611 if (err == OK) { 612 // If this is the first time we're seeing this buffer, add it to our 613 // slot table. 614 if (item.mGraphicBuffer != NULL) { 615 ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); 616 mBufferSlot[item.mBuf] = item.mGraphicBuffer; 617 } 618 mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 619 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 620 } 621 return; 622 } 623 624 mNumFramesAvailable++; 625 626 mRepeatBufferDeferred = false; 627 ++mRepeatLastFrameGeneration; 628 629 if (mExecuting) { 630 fillCodecBuffer_l(); 631 } 632} 633 634// BufferQueue::ConsumerListener callback 635void GraphicBufferSource::onBuffersReleased() { 636 Mutex::Autolock lock(mMutex); 637 638 uint32_t slotMask; 639 if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) { 640 ALOGW("onBuffersReleased: unable to get released buffer set"); 641 slotMask = 0xffffffff; 642 } 643 644 ALOGV("onBuffersReleased: 0x%08x", slotMask); 645 646 for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { 647 if ((slotMask & 0x01) != 0) { 648 mBufferSlot[i] = NULL; 649 } 650 slotMask >>= 1; 651 } 652} 653 654status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs( 655 int64_t repeatAfterUs) { 656 Mutex::Autolock autoLock(mMutex); 657 658 if (mExecuting || repeatAfterUs <= 0ll) { 659 return INVALID_OPERATION; 660 } 661 662 mRepeatAfterUs = repeatAfterUs; 663 664 return OK; 665} 666 667void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) { 668 switch (msg->what()) { 669 case kWhatRepeatLastFrame: 670 { 671 Mutex::Autolock autoLock(mMutex); 672 673 int32_t generation; 674 CHECK(msg->findInt32("generation", &generation)); 675 676 if (generation != mRepeatLastFrameGeneration) { 677 // stale 678 break; 679 } 680 681 if (!mExecuting || mNumFramesAvailable > 0) { 682 break; 683 } 684 685 bool success = repeatLatestSubmittedBuffer_l(); 686 687 if (success) { 688 ALOGV("repeatLatestSubmittedBuffer_l SUCCESS"); 689 } else { 690 ALOGV("repeatLatestSubmittedBuffer_l FAILURE"); 691 mRepeatBufferDeferred = true; 692 } 693 break; 694 } 695 696 default: 697 TRESPASS(); 698 } 699} 700 701} // namespace android 702