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