Revert "Remove GraphicBufferSource wrapper from OMX HAL: 1"
This reverts commit 2b93f6b7d44513b99edd8db031c28695c5b1652d.
Change-Id: I292b28a8d61560d97d7fa673c2de0e90f6074bde
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
deleted file mode 100644
index 2f457ac..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.cpp
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-#define LOG_TAG "GraphicBufferSource"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
-
-#include "GraphicBufferSource.h"
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ColorUtils.h>
-
-#include <media/hardware/MetadataBufferType.h>
-#include <ui/GraphicBuffer.h>
-#include <gui/BufferItem.h>
-#include <HardwareAPI.h>
-#include "omx/OMXUtils.h"
-#include <OMX_Component.h>
-#include <OMX_IndexExt.h>
-#include "OMXBuffer.h"
-
-#include <inttypes.h>
-#include "FrameDropper.h"
-
-namespace android {
-
-static const OMX_U32 kPortIndexInput = 0;
-
-class GraphicBufferSource::OmxBufferSource : public BnOMXBufferSource {
-public:
- GraphicBufferSource* mSource;
-
- OmxBufferSource(GraphicBufferSource* source): mSource(source) {
- }
-
- Status onOmxExecuting() override {
- return mSource->onOmxExecuting();
- }
-
- Status onOmxIdle() override {
- return mSource->onOmxIdle();
- }
-
- Status onOmxLoaded() override {
- return mSource->onOmxLoaded();
- }
-
- Status onInputBufferAdded(int bufferId) override {
- return mSource->onInputBufferAdded(bufferId);
- }
-
- Status onInputBufferEmptied(
- int bufferId, const OMXFenceParcelable& fenceParcel) override {
- return mSource->onInputBufferEmptied(bufferId, fenceParcel);
- }
-};
-
-GraphicBufferSource::GraphicBufferSource() :
- mInitCheck(UNKNOWN_ERROR),
- mExecuting(false),
- mSuspended(false),
- mStopTimeUs(-1),
- mLastDataSpace(HAL_DATASPACE_UNKNOWN),
- mNumFramesAvailable(0),
- mNumBufferAcquired(0),
- mEndOfStream(false),
- mEndOfStreamSent(false),
- mLastActionTimeUs(-1ll),
- mPrevOriginalTimeUs(-1ll),
- mSkipFramesBeforeNs(-1ll),
- mRepeatAfterUs(-1ll),
- mRepeatLastFrameGeneration(0),
- mRepeatLastFrameTimestamp(-1ll),
- mRepeatLastFrameCount(0),
- mLatestBufferId(-1),
- mLatestBufferFrameNum(0),
- mLatestBufferFence(Fence::NO_FENCE),
- mRepeatBufferDeferred(false),
- mTimePerCaptureUs(-1ll),
- mTimePerFrameUs(-1ll),
- mPrevCaptureUs(-1ll),
- mPrevFrameUs(-1ll),
- mInputBufferTimeOffsetUs(0ll),
- mOmxBufferSource(new OmxBufferSource(this)) {
- ALOGV("GraphicBufferSource");
-
- String8 name("GraphicBufferSource");
-
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mConsumer->setConsumerName(name);
-
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<BufferQueue::ConsumerListener> listener =
- static_cast<BufferQueue::ConsumerListener*>(this);
- sp<IConsumerListener> proxy =
- new BufferQueue::ProxyConsumerListener(listener);
-
- mInitCheck = mConsumer->consumerConnect(proxy, false);
- if (mInitCheck != NO_ERROR) {
- ALOGE("Error connecting to BufferQueue: %s (%d)",
- strerror(-mInitCheck), mInitCheck);
- return;
- }
-
- memset(&mColorAspects, 0, sizeof(mColorAspects));
-
- CHECK(mInitCheck == NO_ERROR);
-}
-
-GraphicBufferSource::~GraphicBufferSource() {
- ALOGV("~GraphicBufferSource");
- if (mLatestBufferId >= 0) {
- releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
- }
- if (mNumBufferAcquired != 0) {
- ALOGW("potential buffer leak (acquired %d)", mNumBufferAcquired);
- }
- if (mConsumer != NULL) {
- status_t err = mConsumer->consumerDisconnect();
- if (err != NO_ERROR) {
- ALOGW("consumerDisconnect failed: %d", err);
- }
- }
-}
-
-Status GraphicBufferSource::onOmxExecuting() {
- Mutex::Autolock autoLock(mMutex);
- ALOGV("--> executing; avail=%zu, codec vec size=%zd",
- mNumFramesAvailable, mCodecBuffers.size());
- CHECK(!mExecuting);
- mExecuting = true;
- mLastDataSpace = HAL_DATASPACE_UNKNOWN;
- ALOGV("clearing last dataSpace");
-
- // Start by loading up as many buffers as possible. We want to do this,
- // rather than just submit the first buffer, to avoid a degenerate case:
- // if all BQ buffers arrive before we start executing, and we only submit
- // one here, the other BQ buffers will just sit until we get notified
- // that the codec buffer has been released. We'd then acquire and
- // submit a single additional buffer, repeatedly, never using more than
- // one codec buffer simultaneously. (We could instead try to submit
- // all BQ buffers whenever any codec buffer is freed, but if we get the
- // initial conditions right that will never be useful.)
- while (mNumFramesAvailable) {
- if (!fillCodecBuffer_l()) {
- ALOGV("stop load with frames available (codecAvail=%d)",
- isCodecBufferAvailable_l());
- break;
- }
- }
-
- ALOGV("done loading initial frames, avail=%zu", mNumFramesAvailable);
-
- // If EOS has already been signaled, and there are no more frames to
- // submit, try to send EOS now as well.
- if (mStopTimeUs == -1 && mEndOfStream && mNumFramesAvailable == 0) {
- submitEndOfInputStream_l();
- }
-
- if (mRepeatAfterUs > 0ll && mLooper == NULL) {
- mReflector = new AHandlerReflector<GraphicBufferSource>(this);
-
- mLooper = new ALooper;
- mLooper->registerHandler(mReflector);
- mLooper->start();
-
- if (mLatestBufferId >= 0) {
- sp<AMessage> msg =
- new AMessage(kWhatRepeatLastFrame, mReflector);
-
- msg->setInt32("generation", ++mRepeatLastFrameGeneration);
- msg->post(mRepeatAfterUs);
- }
- }
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::onOmxIdle() {
- ALOGV("omxIdle");
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting) {
- // We are only interested in the transition from executing->idle,
- // not loaded->idle.
- mExecuting = false;
- }
- return Status::ok();
-}
-
-Status GraphicBufferSource::onOmxLoaded(){
- Mutex::Autolock autoLock(mMutex);
- if (!mExecuting) {
- // This can happen if something failed very early.
- ALOGW("Dropped back down to Loaded without Executing");
- }
-
- if (mLooper != NULL) {
- mLooper->unregisterHandler(mReflector->id());
- mReflector.clear();
-
- mLooper->stop();
- mLooper.clear();
- }
-
- ALOGV("--> loaded; avail=%zu eos=%d eosSent=%d acquired=%d",
- mNumFramesAvailable, mEndOfStream, mEndOfStreamSent, mNumBufferAcquired);
-
- // Codec is no longer executing. Releasing all buffers to bq.
- for (int i = (int)mCodecBuffers.size() - 1; i >= 0; --i) {
- if (mCodecBuffers[i].mGraphicBuffer != NULL) {
- int id = mCodecBuffers[i].mSlot;
- if (id != mLatestBufferId) {
- ALOGV("releasing buffer for codec: slot=%d, useCount=%d, latest=%d",
- id, mBufferUseCount[id], mLatestBufferId);
- sp<Fence> fence = new Fence(-1);
- releaseBuffer(id, mCodecBuffers[i].mFrameNumber, fence);
- mBufferUseCount[id] = 0;
- }
- }
- }
- // Also release the latest buffer
- if (mLatestBufferId >= 0) {
- releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
- mBufferUseCount[mLatestBufferId] = 0;
- mLatestBufferId = -1;
- }
-
- mCodecBuffers.clear();
- mOMXNode.clear();
- mExecuting = false;
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::onInputBufferAdded(int32_t bufferID) {
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting) {
- // This should never happen -- buffers can only be allocated when
- // transitioning from "loaded" to "idle".
- ALOGE("addCodecBuffer: buffer added while executing");
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- ALOGV("addCodecBuffer: bufferID=%u", bufferID);
-
- CodecBuffer codecBuffer;
- codecBuffer.mBufferID = bufferID;
- mCodecBuffers.add(codecBuffer);
- return Status::ok();
-}
-
-Status GraphicBufferSource::onInputBufferEmptied(
- int32_t bufferID, const OMXFenceParcelable &fenceParcel) {
- int fenceFd = fenceParcel.get();
-
- Mutex::Autolock autoLock(mMutex);
- if (!mExecuting) {
- if (fenceFd >= 0) {
- ::close(fenceFd);
- }
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- int cbi = findMatchingCodecBuffer_l(bufferID);
- if (cbi < 0) {
- // This should never happen.
- ALOGE("codecBufferEmptied: buffer not recognized (bufferID=%u)", bufferID);
- if (fenceFd >= 0) {
- ::close(fenceFd);
- }
- return Status::fromServiceSpecificError(BAD_VALUE);
- }
-
- ALOGV("codecBufferEmptied: bufferID=%u, cbi=%d", bufferID, cbi);
- CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
-
- // header->nFilledLen may not be the original value, so we can't compare
- // that to zero to see of this was the EOS buffer. Instead we just
- // see if the GraphicBuffer reference was null, which should only ever
- // happen for EOS.
- if (codecBuffer.mGraphicBuffer == NULL) {
- if (!(mEndOfStream && mEndOfStreamSent)) {
- // This can happen when broken code sends us the same buffer
- // twice in a row.
- ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer "
- "(buffer emptied twice?)");
- }
- // No GraphicBuffer to deal with, no additional input or output is
- // expected, so just return.
- if (fenceFd >= 0) {
- ::close(fenceFd);
- }
- return Status::fromServiceSpecificError(BAD_VALUE);
- }
-
- // Find matching entry in our cached copy of the BufferQueue slots.
- // If we find a match, release that slot. If we don't, the BufferQueue
- // has dropped that GraphicBuffer, and there's nothing for us to release.
- int id = codecBuffer.mSlot;
- sp<Fence> fence = new Fence(fenceFd);
- if (mBufferSlot[id] != NULL &&
- mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
- mBufferUseCount[id]--;
-
- if (mBufferUseCount[id] < 0) {
- ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
- mBufferUseCount[id] = 0;
- }
- if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
- releaseBuffer(id, codecBuffer.mFrameNumber, fence);
- }
- ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, acquired=%d, handle=%p",
- id, cbi, mBufferUseCount[id], mNumBufferAcquired, mBufferSlot[id]->handle);
- } else {
- ALOGV("codecBufferEmptied: no match for emptied buffer, "
- "slot=%d, cbi=%d, useCount=%d, acquired=%d",
- id, cbi, mBufferUseCount[id], mNumBufferAcquired);
- // we will not reuse codec buffer, so there is no need to wait for fence
- }
-
- // Mark the codec buffer as available by clearing the GraphicBuffer ref.
- codecBuffer.mGraphicBuffer = NULL;
-
- if (mNumFramesAvailable) {
- // Fill this codec buffer.
- CHECK(!mEndOfStreamSent);
- ALOGV("buffer freed, %zu frames avail (eos=%d)",
- mNumFramesAvailable, mEndOfStream);
- fillCodecBuffer_l();
- } else if (mEndOfStream && mStopTimeUs == -1) {
- // No frames available, but EOS is pending and no stop time, so use this buffer to
- // send that.
- ALOGV("buffer freed, EOS pending");
- submitEndOfInputStream_l();
- } else if (mRepeatBufferDeferred) {
- bool success = repeatLatestBuffer_l();
- if (success) {
- ALOGV("deferred repeatLatestBuffer_l SUCCESS");
- } else {
- ALOGV("deferred repeatLatestBuffer_l FAILURE");
- }
- mRepeatBufferDeferred = false;
- }
-
- return Status::ok();
-}
-
-void GraphicBufferSource::onDataSpaceChanged_l(
- android_dataspace dataSpace, android_pixel_format pixelFormat) {
- ALOGD("got buffer with new dataSpace #%x", dataSpace);
- mLastDataSpace = dataSpace;
-
- if (ColorUtils::convertDataSpaceToV0(dataSpace)) {
- omx_message msg;
- msg.type = omx_message::EVENT;
- msg.fenceFd = -1;
- msg.u.event_data.event = OMX_EventDataSpaceChanged;
- msg.u.event_data.data1 = mLastDataSpace;
- msg.u.event_data.data2 = ColorUtils::packToU32(mColorAspects);
- msg.u.event_data.data3 = pixelFormat;
-
- mOMXNode->dispatchMessage(msg);
- }
-}
-
-bool GraphicBufferSource::fillCodecBuffer_l() {
- CHECK(mExecuting && mNumFramesAvailable > 0);
-
- if (mSuspended && mActionQueue.empty()) {
- return false;
- }
-
- int cbi = findAvailableCodecBuffer_l();
- if (cbi < 0) {
- // No buffers available, bail.
- ALOGV("fillCodecBuffer_l: no codec buffers, avail now %zu",
- mNumFramesAvailable);
- return false;
- }
-
- ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%zu",
- mNumFramesAvailable);
- BufferItem item;
- status_t err = acquireBuffer(&item);
- if (err != OK) {
- ALOGE("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
- return false;
- }
-
- int64_t itemTimeUs = item.mTimestamp / 1000;
-
- mNumFramesAvailable--;
-
- // Process ActionItem in the Queue if there is any. If a buffer's timestamp
- // is smaller than the first action's timestamp, no action need to be performed.
- // If buffer's timestamp is larger or equal than the last action's timestamp,
- // only the last action needs to be performed as all the acitions before the
- // the action are overridden by the last action. For the other cases, traverse
- // the Queue to find the newest action that with timestamp smaller or equal to
- // the buffer's timestamp. For example, an action queue like
- // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
- // receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
- // to be handled and [pause, 1us], [resume 2us] will be discarded.
- bool dropped = false;
- bool done = false;
- if (!mActionQueue.empty()) {
- // First scan to check if bufferTimestamp is smaller than first action's timestamp.
- ActionItem nextAction = *(mActionQueue.begin());
- if (itemTimeUs < nextAction.mActionTimeUs) {
- ALOGV("No action. buffer timestamp %lld us < action timestamp: %lld us",
- (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
- // All the actions are ahead. No action need to perform now.
- // Release the buffer if is in suspended state, or process the buffer
- // if not in suspended state.
- dropped = mSuspended;
- done = true;
- }
-
- if (!done) {
- List<ActionItem>::iterator it = mActionQueue.begin();
- while(it != mActionQueue.end()) {
- nextAction = *it;
- mActionQueue.erase(it);
- if (nextAction.mActionTimeUs > itemTimeUs) {
- break;
- }
- ++it;
- }
-
- CHECK(itemTimeUs >= nextAction.mActionTimeUs);
- switch (nextAction.mAction) {
- case ActionItem::PAUSE:
- {
- mSuspended = true;
- dropped = true;
- ALOGV("RUNNING/PAUSE -> PAUSE at buffer %lld us PAUSE Time: %lld us",
- (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
- break;
- }
- case ActionItem::RESUME:
- {
- mSuspended = false;
- ALOGV("PAUSE/RUNNING -> RUNNING at buffer %lld us RESUME Time: %lld us",
- (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
- break;
- }
- case ActionItem::STOP:
- {
- ALOGV("RUNNING/PAUSE -> STOP at buffer %lld us STOP Time: %lld us",
- (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
- dropped = true;
- // Clear the whole ActionQueue as recording is done
- mActionQueue.clear();
- submitEndOfInputStream_l();
- break;
- }
- default:
- ALOGE("Unknown action type");
- return false;
- }
- }
- }
-
- if (dropped) {
- releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
- return true;
- }
-
- if (item.mDataSpace != mLastDataSpace) {
- onDataSpaceChanged_l(
- item.mDataSpace, (android_pixel_format)mBufferSlot[item.mSlot]->getPixelFormat());
- }
-
- err = UNKNOWN_ERROR;
-
- // only submit sample if start time is unspecified, or sample
- // is queued after the specified start time
- if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
- // if start time is set, offset time stamp by start time
- if (mSkipFramesBeforeNs > 0) {
- item.mTimestamp -= mSkipFramesBeforeNs;
- }
-
- int64_t timeUs = item.mTimestamp / 1000;
- if (mFrameDropper != NULL && mFrameDropper->shouldDrop(timeUs)) {
- ALOGV("skipping frame (%lld) to meet max framerate", static_cast<long long>(timeUs));
- // set err to OK so that the skipped frame can still be saved as the lastest frame
- err = OK;
- dropped = true;
- } else {
- err = submitBuffer_l(item, cbi);
- }
- }
-
- if (err != OK) {
- ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
- releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
- } else {
- // Don't set the last buffer id if we're not repeating,
- // we'll be holding on to the last buffer for nothing.
- if (mRepeatAfterUs > 0ll) {
- setLatestBuffer_l(item);
- }
- if (!dropped) {
- ++mBufferUseCount[item.mSlot];
- }
- ALOGV("buffer submitted: slot=%d, cbi=%d, useCount=%d, acquired=%d",
- item.mSlot, cbi, mBufferUseCount[item.mSlot], mNumBufferAcquired);
- }
-
- return true;
-}
-
-bool GraphicBufferSource::repeatLatestBuffer_l() {
- CHECK(mExecuting && mNumFramesAvailable == 0);
-
- if (mLatestBufferId < 0 || mSuspended) {
- return false;
- }
- if (mBufferSlot[mLatestBufferId] == NULL) {
- // This can happen if the remote side disconnects, causing
- // onBuffersReleased() to NULL out our copy of the slots. The
- // buffer is gone, so we have nothing to show.
- //
- // To be on the safe side we try to release the buffer.
- ALOGD("repeatLatestBuffer_l: slot was NULL");
- mConsumer->releaseBuffer(
- mLatestBufferId,
- mLatestBufferFrameNum,
- EGL_NO_DISPLAY,
- EGL_NO_SYNC_KHR,
- mLatestBufferFence);
- mLatestBufferId = -1;
- mLatestBufferFrameNum = 0;
- mLatestBufferFence = Fence::NO_FENCE;
- return false;
- }
-
- int cbi = findAvailableCodecBuffer_l();
- if (cbi < 0) {
- // No buffers available, bail.
- ALOGV("repeatLatestBuffer_l: no codec buffers.");
- return false;
- }
-
- BufferItem item;
- item.mSlot = mLatestBufferId;
- item.mFrameNumber = mLatestBufferFrameNum;
- item.mTimestamp = mRepeatLastFrameTimestamp;
- item.mFence = mLatestBufferFence;
-
- status_t err = submitBuffer_l(item, cbi);
-
- if (err != OK) {
- return false;
- }
-
- ++mBufferUseCount[item.mSlot];
-
- /* repeat last frame up to kRepeatLastFrameCount times.
- * in case of static scene, a single repeat might not get rid of encoder
- * ghosting completely, refresh a couple more times to get better quality
- */
- if (--mRepeatLastFrameCount > 0) {
- mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
-
- if (mReflector != NULL) {
- sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
- msg->setInt32("generation", ++mRepeatLastFrameGeneration);
- msg->post(mRepeatAfterUs);
- }
- }
-
- return true;
-}
-
-void GraphicBufferSource::setLatestBuffer_l(const BufferItem &item) {
- if (mLatestBufferId >= 0 && mBufferUseCount[mLatestBufferId] == 0) {
- releaseBuffer(mLatestBufferId, mLatestBufferFrameNum, mLatestBufferFence);
- // mLatestBufferFence will be set to new fence just below
- }
-
- mLatestBufferId = item.mSlot;
- mLatestBufferFrameNum = item.mFrameNumber;
- mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
-
- ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
- item.mSlot, mBufferUseCount[item.mSlot]);
-
- mRepeatBufferDeferred = false;
- mRepeatLastFrameCount = kRepeatLastFrameCount;
- mLatestBufferFence = item.mFence;
-
- if (mReflector != NULL) {
- sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector);
- msg->setInt32("generation", ++mRepeatLastFrameGeneration);
- msg->post(mRepeatAfterUs);
- }
-}
-
-bool GraphicBufferSource::getTimestamp(
- const BufferItem &item, int64_t *codecTimeUs) {
- int64_t timeUs = item.mTimestamp / 1000;
- timeUs += mInputBufferTimeOffsetUs;
-
- if (mTimePerCaptureUs > 0ll
- && (mTimePerCaptureUs > 2 * mTimePerFrameUs
- || mTimePerFrameUs > 2 * mTimePerCaptureUs)) {
- // Time lapse or slow motion mode
- if (mPrevCaptureUs < 0ll) {
- // first capture
- mPrevCaptureUs = timeUs;
- // adjust the first sample timestamp.
- mPrevFrameUs = (timeUs * mTimePerFrameUs) / mTimePerCaptureUs;
- } else {
- // snap to nearest capture point
- int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
- / mTimePerCaptureUs;
- if (nFrames <= 0) {
- // skip this frame as it's too close to previous capture
- ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
- return false;
- }
- mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs;
- mPrevFrameUs += mTimePerFrameUs * nFrames;
- }
-
- ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
- static_cast<long long>(timeUs),
- static_cast<long long>(mPrevCaptureUs),
- static_cast<long long>(mPrevFrameUs));
-
- *codecTimeUs = mPrevFrameUs;
- return true;
- } else {
- int64_t originalTimeUs = timeUs;
- if (originalTimeUs <= mPrevOriginalTimeUs) {
- // Drop the frame if it's going backward in time. Bad timestamp
- // could disrupt encoder's rate control completely.
- ALOGW("Dropping frame that's going backward in time");
- return false;
- }
-
- mPrevOriginalTimeUs = originalTimeUs;
- }
-
- *codecTimeUs = timeUs;
- return true;
-}
-
-status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
- ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
-
- int64_t codecTimeUs;
- if (!getTimestamp(item, &codecTimeUs)) {
- return UNKNOWN_ERROR;
- }
-
- CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
- codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
- codecBuffer.mSlot = item.mSlot;
- codecBuffer.mFrameNumber = item.mFrameNumber;
-
- IOMX::buffer_id bufferID = codecBuffer.mBufferID;
- const sp<GraphicBuffer> &buffer = codecBuffer.mGraphicBuffer;
- int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
-
- status_t err = mOMXNode->emptyBuffer(
- bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
-
- if (err != OK) {
- ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
- codecBuffer.mGraphicBuffer = NULL;
- return err;
- }
-
- ALOGV("emptyGraphicBuffer succeeded, bufferID=%u buf=%p bufhandle=%p",
- bufferID, buffer->getNativeBuffer(), buffer->handle);
- return OK;
-}
-
-void GraphicBufferSource::submitEndOfInputStream_l() {
- CHECK(mEndOfStream);
- if (mEndOfStreamSent) {
- ALOGV("EOS already sent");
- return;
- }
-
- int cbi = findAvailableCodecBuffer_l();
- if (cbi < 0) {
- ALOGV("submitEndOfInputStream_l: no codec buffers available");
- return;
- }
-
- // We reject any additional incoming graphic buffers, so there's no need
- // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as
- // in-use.
- CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
- IOMX::buffer_id bufferID = codecBuffer.mBufferID;
-
- status_t err = mOMXNode->emptyBuffer(
- bufferID, (sp<GraphicBuffer>)NULL,
- OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
- 0 /* timestamp */, -1 /* fenceFd */);
- if (err != OK) {
- ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
- } else {
- ALOGV("submitEndOfInputStream_l: buffer submitted, bufferID=%u cbi=%d",
- bufferID, cbi);
- mEndOfStreamSent = true;
- }
-}
-
-int GraphicBufferSource::findAvailableCodecBuffer_l() {
- CHECK(mCodecBuffers.size() > 0);
-
- for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
- if (mCodecBuffers[i].mGraphicBuffer == NULL) {
- return i;
- }
- }
- return -1;
-}
-
-int GraphicBufferSource::findMatchingCodecBuffer_l(IOMX::buffer_id bufferID) {
- for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
- if (mCodecBuffers[i].mBufferID == bufferID) {
- return i;
- }
- }
- return -1;
-}
-
-status_t GraphicBufferSource::acquireBuffer(BufferItem *bi) {
- status_t err = mConsumer->acquireBuffer(bi, 0);
- if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
- // shouldn't happen
- ALOGW("acquireBuffer: frame was not available");
- return err;
- } else if (err != OK) {
- ALOGW("acquireBuffer: failed with err=%d", err);
- return err;
- }
- // If this is the first time we're seeing this buffer, add it to our
- // slot table.
- if (bi->mGraphicBuffer != NULL) {
- ALOGV("acquireBuffer: setting mBufferSlot %d", bi->mSlot);
- mBufferSlot[bi->mSlot] = bi->mGraphicBuffer;
- mBufferUseCount[bi->mSlot] = 0;
- }
- mNumBufferAcquired++;
- return OK;
-}
-
-/*
- * Releases an acquired buffer back to the consumer.
- *
- * id: buffer slot to release
- * frameNum: frame number of the frame being released
- * fence: fence of the frame being released
- */
-void GraphicBufferSource::releaseBuffer(
- int id, uint64_t frameNum, const sp<Fence> &fence) {
- ALOGV("releaseBuffer: slot=%d", id);
- mConsumer->releaseBuffer(
- id, frameNum, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
- mNumBufferAcquired--;
-}
-
-// BufferQueue::ConsumerListener callback
-void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
- Mutex::Autolock autoLock(mMutex);
-
- ALOGV("onFrameAvailable exec=%d avail=%zu",
- mExecuting, mNumFramesAvailable);
-
- if (mOMXNode == NULL || mEndOfStreamSent || (mSuspended && mActionQueue.empty())) {
- if (mEndOfStreamSent) {
- // This should only be possible if a new buffer was queued after
- // EOS was signaled, i.e. the app is misbehaving.
-
- ALOGW("onFrameAvailable: EOS is sent, ignoring frame");
- } else {
- ALOGV("onFrameAvailable: suspended, ignoring frame");
- }
-
- BufferItem item;
- status_t err = acquireBuffer(&item);
- if (err == OK) {
- releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
- } else {
- ALOGE("onFrameAvailable: acquireBuffer returned err=%d", err);
- }
- return;
- }
-
- mNumFramesAvailable++;
-
- mRepeatBufferDeferred = false;
- ++mRepeatLastFrameGeneration;
-
- if (mExecuting) {
- fillCodecBuffer_l();
- }
-}
-
-// BufferQueue::ConsumerListener callback
-void GraphicBufferSource::onBuffersReleased() {
- Mutex::Autolock lock(mMutex);
-
- uint64_t slotMask;
- if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
- ALOGW("onBuffersReleased: unable to get released buffer set");
- slotMask = 0xffffffffffffffffULL;
- }
-
- ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
-
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if ((slotMask & 0x01) != 0) {
- // Last buffer (if set) is always acquired even if its use count
- // is 0, because we could have skipped that frame but kept it for
- // repeating. Otherwise a buffer is only acquired if use count>0.
- if (mBufferSlot[i] != NULL &&
- (mBufferUseCount[i] > 0 || mLatestBufferId == i)) {
- ALOGV("releasing acquired buffer: slot=%d, useCount=%d, latest=%d",
- i, mBufferUseCount[i], mLatestBufferId);
- mNumBufferAcquired--;
- }
- if (mLatestBufferId == i) {
- mLatestBufferId = -1;
- }
- mBufferSlot[i] = NULL;
- mBufferUseCount[i] = 0;
- }
- slotMask >>= 1;
- }
-}
-
-// BufferQueue::ConsumerListener callback
-void GraphicBufferSource::onSidebandStreamChanged() {
- ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams");
-}
-
-Status GraphicBufferSource::configure(
- const sp<IOMXNode>& omxNode, int32_t dataSpace) {
- if (omxNode == NULL) {
- return Status::fromServiceSpecificError(BAD_VALUE);
- }
-
- // Do setInputSurface() first, the node will try to enable metadata
- // mode on input, and does necessary error checking. If this fails,
- // we can't use this input surface on the node.
- status_t err = omxNode->setInputSurface(mOmxBufferSource);
- if (err != NO_ERROR) {
- ALOGE("Unable to set input surface: %d", err);
- return Status::fromServiceSpecificError(err);
- }
-
- // use consumer usage bits queried from encoder, but always add
- // HW_VIDEO_ENCODER for backward compatibility.
- uint32_t consumerUsage;
- if (omxNode->getParameter(
- (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
- &consumerUsage, sizeof(consumerUsage)) != OK) {
- consumerUsage = 0;
- }
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- err = omxNode->getParameter(
- OMX_IndexParamPortDefinition, &def, sizeof(def));
- if (err != NO_ERROR) {
- ALOGE("Failed to get port definition: %d", err);
- return Status::fromServiceSpecificError(UNKNOWN_ERROR);
- }
-
- // Call setMaxAcquiredBufferCount without lock.
- // setMaxAcquiredBufferCount could call back to onBuffersReleased
- // if the buffer count change results in releasing of existing buffers,
- // which would lead to deadlock.
- err = mConsumer->setMaxAcquiredBufferCount(def.nBufferCountActual);
- if (err != NO_ERROR) {
- ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
- def.nBufferCountActual, err);
- return Status::fromServiceSpecificError(err);
- }
-
- {
- Mutex::Autolock autoLock(mMutex);
- mOMXNode = omxNode;
-
- err = mConsumer->setDefaultBufferSize(
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight);
- if (err != NO_ERROR) {
- ALOGE("Unable to set BQ default buffer size to %ux%u: %d",
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight,
- err);
- return Status::fromServiceSpecificError(err);
- }
-
- consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
- mConsumer->setConsumerUsageBits(consumerUsage);
-
- // Sets the default buffer data space
- ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumBufferAcquired);
- mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
- mLastDataSpace = (android_dataspace)dataSpace;
-
- mExecuting = false;
- mSuspended = false;
- mEndOfStream = false;
- mEndOfStreamSent = false;
- mPrevOriginalTimeUs = -1ll;
- mSkipFramesBeforeNs = -1ll;
- mRepeatAfterUs = -1ll;
- mRepeatLastFrameGeneration = 0;
- mRepeatLastFrameTimestamp = -1ll;
- mRepeatLastFrameCount = 0;
- mLatestBufferId = -1;
- mLatestBufferFrameNum = 0;
- mLatestBufferFence = Fence::NO_FENCE;
- mRepeatBufferDeferred = false;
- mTimePerCaptureUs = -1ll;
- mTimePerFrameUs = -1ll;
- mPrevCaptureUs = -1ll;
- mPrevFrameUs = -1ll;
- mInputBufferTimeOffsetUs = 0;
- mStopTimeUs = -1;
- mActionQueue.clear();
- }
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::setSuspend(bool suspend, int64_t suspendStartTimeUs) {
- ALOGV("setSuspend=%d at time %lld us", suspend, (long long)suspendStartTimeUs);
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mStopTimeUs != -1) {
- ALOGE("setSuspend failed as STOP action is pending");
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- // Push the action to the queue.
- if (suspendStartTimeUs != -1) {
- // suspendStartTimeUs must be smaller or equal to current systemTime.
- int64_t currentSystemTimeUs = systemTime() / 1000;
- if (suspendStartTimeUs > currentSystemTimeUs) {
- ALOGE("setSuspend failed. %lld is larger than current system time %lld us",
- (long long)suspendStartTimeUs, (long long)currentSystemTimeUs);
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
- if (mLastActionTimeUs != -1 && suspendStartTimeUs < mLastActionTimeUs) {
- ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
- (long long)suspendStartTimeUs, (long long)mLastActionTimeUs);
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
- mLastActionTimeUs = suspendStartTimeUs;
- ActionItem action;
- action.mAction = suspend ? ActionItem::PAUSE : ActionItem::RESUME;
- action.mActionTimeUs = suspendStartTimeUs;
- ALOGV("Push %s action into actionQueue", suspend ? "PAUSE" : "RESUME");
- mActionQueue.push_back(action);
- } else {
- if (suspend) {
- mSuspended = true;
-
- while (mNumFramesAvailable > 0) {
- BufferItem item;
- status_t err = acquireBuffer(&item);
-
- if (err != OK) {
- ALOGE("setSuspend: acquireBuffer returned err=%d", err);
- break;
- }
-
- --mNumFramesAvailable;
-
- releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
- }
- return Status::ok();
- } else {
-
- mSuspended = false;
-
- if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
- if (repeatLatestBuffer_l()) {
- ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
-
- mRepeatBufferDeferred = false;
- } else {
- ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
- }
- }
- }
- }
- return Status::ok();
-}
-
-Status GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
- ALOGV("setRepeatPreviousFrameDelayUs: delayUs=%lld", (long long)repeatAfterUs);
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting || repeatAfterUs <= 0ll) {
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- mRepeatAfterUs = repeatAfterUs;
- return Status::ok();
-}
-
-Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
- Mutex::Autolock autoLock(mMutex);
-
- // timeOffsetUs must be negative for adjustment.
- if (timeOffsetUs >= 0ll) {
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- mInputBufferTimeOffsetUs = timeOffsetUs;
- return Status::ok();
-}
-
-Status GraphicBufferSource::setMaxFps(float maxFps) {
- ALOGV("setMaxFps: maxFps=%lld", (long long)maxFps);
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting) {
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- mFrameDropper = new FrameDropper();
- status_t err = mFrameDropper->setMaxFrameRate(maxFps);
- if (err != OK) {
- mFrameDropper.clear();
- return Status::fromServiceSpecificError(err);
- }
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::setStartTimeUs(int64_t skipFramesBeforeUs) {
- ALOGV("setStartTimeUs: skipFramesBeforeUs=%lld", (long long)skipFramesBeforeUs);
-
- Mutex::Autolock autoLock(mMutex);
-
- mSkipFramesBeforeNs =
- (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
- ALOGV("setStopTimeUs: %lld us", (long long)stopTimeUs);
- Mutex::Autolock autoLock(mMutex);
-
- if (mStopTimeUs != -1) {
- // Ignore if stop time has already been set
- return Status::ok();
- }
-
- // stopTimeUs must be smaller or equal to current systemTime.
- int64_t currentSystemTimeUs = systemTime() / 1000;
- if (stopTimeUs > currentSystemTimeUs) {
- ALOGE("setStopTimeUs failed. %lld is larger than current system time %lld us",
- (long long)stopTimeUs, (long long)currentSystemTimeUs);
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
- if (mLastActionTimeUs != -1 && stopTimeUs < mLastActionTimeUs) {
- ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
- (long long)stopTimeUs, (long long)mLastActionTimeUs);
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
- mLastActionTimeUs = stopTimeUs;
- ActionItem action;
- action.mAction = ActionItem::STOP;
- action.mActionTimeUs = stopTimeUs;
- mActionQueue.push_back(action);
- mStopTimeUs = stopTimeUs;
- return Status::ok();
-}
-
-Status GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
- ALOGV("setTimeLapseConfig: timePerFrameUs=%lld, timePerCaptureUs=%lld",
- (long long)timePerFrameUs, (long long)timePerCaptureUs);
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting || timePerFrameUs <= 0ll || timePerCaptureUs <= 0ll) {
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- mTimePerFrameUs = timePerFrameUs;
- mTimePerCaptureUs = timePerCaptureUs;
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::setColorAspects(int32_t aspectsPacked) {
- Mutex::Autolock autoLock(mMutex);
- mColorAspects = ColorUtils::unpackToColorAspects(aspectsPacked);
- ALOGD("requesting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s))",
- mColorAspects.mRange, asString(mColorAspects.mRange),
- mColorAspects.mPrimaries, asString(mColorAspects.mPrimaries),
- mColorAspects.mMatrixCoeffs, asString(mColorAspects.mMatrixCoeffs),
- mColorAspects.mTransfer, asString(mColorAspects.mTransfer));
-
- return Status::ok();
-}
-
-Status GraphicBufferSource::signalEndOfInputStream() {
- Mutex::Autolock autoLock(mMutex);
- ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d",
- mExecuting, mNumFramesAvailable, mEndOfStream);
-
- if (mEndOfStream) {
- ALOGE("EOS was already signaled");
- return Status::fromStatusT(INVALID_OPERATION);
- }
-
- // Set the end-of-stream flag. If no frames are pending from the
- // BufferQueue, and a codec buffer is available, and we're executing,
- // and there is no stop timestamp, we initiate the EOS from here.
- // Otherwise, we'll let codecBufferEmptied() (or omxExecuting) do it.
- //
- // Note: if there are no pending frames and all codec buffers are
- // available, we *must* submit the EOS from here or we'll just
- // stall since no future events are expected.
- mEndOfStream = true;
-
- if (mStopTimeUs == -1 && mExecuting && mNumFramesAvailable == 0) {
- submitEndOfInputStream_l();
- }
-
- return Status::ok();
-}
-
-void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatRepeatLastFrame:
- {
- Mutex::Autolock autoLock(mMutex);
-
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mRepeatLastFrameGeneration) {
- // stale
- break;
- }
-
- if (!mExecuting || mNumFramesAvailable > 0) {
- break;
- }
-
- bool success = repeatLatestBuffer_l();
-
- if (success) {
- ALOGV("repeatLatestBuffer_l SUCCESS");
- } else {
- ALOGV("repeatLatestBuffer_l FAILURE");
- mRepeatBufferDeferred = true;
- }
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
deleted file mode 100644
index 475548e..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/GraphicBufferSource.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GRAPHIC_BUFFER_SOURCE_H_
-
-#define GRAPHIC_BUFFER_SOURCE_H_
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
-#include <utils/RefBase.h>
-
-#include <VideoAPI.h>
-#include <media/IOMX.h>
-#include <media/OMXFenceParcelable.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/foundation/ALooper.h>
-
-#include <android/BnGraphicBufferSource.h>
-#include <android/BnOMXBufferSource.h>
-
-namespace android {
-
-using ::android::binder::Status;
-
-struct FrameDropper;
-
-/*
- * This class is used to feed OMX codecs from a Surface via BufferQueue.
- *
- * Instances of the class don't run on a dedicated thread. Instead,
- * various events trigger data movement:
- *
- * - Availability of a new frame of data from the BufferQueue (notified
- * via the onFrameAvailable callback).
- * - The return of a codec buffer (via OnEmptyBufferDone).
- * - Application signaling end-of-stream.
- * - Transition to or from "executing" state.
- *
- * Frames of data (and, perhaps, the end-of-stream indication) can arrive
- * before the codec is in the "executing" state, so we need to queue
- * things up until we're ready to go.
- */
-class GraphicBufferSource : public BnGraphicBufferSource,
- public BufferQueue::ConsumerListener {
-public:
- GraphicBufferSource();
-
- virtual ~GraphicBufferSource();
-
- // We can't throw an exception if the constructor fails, so we just set
- // this and require that the caller test the value.
- status_t initCheck() const {
- return mInitCheck;
- }
-
- // Returns the handle to the producer side of the BufferQueue. Buffers
- // queued on this will be received by GraphicBufferSource.
- sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
- return mProducer;
- }
-
- // This is called when OMX transitions to OMX_StateExecuting, which means
- // we can start handing it buffers. If we already have buffers of data
- // sitting in the BufferQueue, this will send them to the codec.
- Status onOmxExecuting();
-
- // This is called when OMX transitions to OMX_StateIdle, indicating that
- // the codec is meant to return all buffers back to the client for them
- // to be freed. Do NOT submit any more buffers to the component.
- Status onOmxIdle();
-
- // This is called when OMX transitions to OMX_StateLoaded, indicating that
- // we are shutting down.
- Status onOmxLoaded();
-
- // A "codec buffer", i.e. a buffer that can be used to pass data into
- // the encoder, has been allocated. (This call does not call back into
- // OMXNodeInstance.)
- Status onInputBufferAdded(int32_t bufferID);
-
- // Called from OnEmptyBufferDone. If we have a BQ buffer available,
- // fill it with a new frame of data; otherwise, just mark it as available.
- Status onInputBufferEmptied(
- int32_t bufferID, const OMXFenceParcelable& fenceParcel);
-
- // Configure the buffer source to be used with an OMX node with the default
- // data space.
- Status configure(const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
-
- // This is called after the last input frame has been submitted or buffer
- // timestamp is greater or equal than stopTimeUs. We need to submit an empty
- // buffer with the EOS flag set. If we don't have a codec buffer ready,
- // we just set the mEndOfStream flag.
- Status signalEndOfInputStream() override;
-
- // If suspend is true, all incoming buffers (including those currently
- // in the BufferQueue) with timestamp larger than timeUs will be discarded
- // until the suspension is lifted. If suspend is false, all incoming buffers
- // including those currently in the BufferQueue) with timestamp larger than
- // timeUs will be processed. timeUs uses SYSTEM_TIME_MONOTONIC time base.
- Status setSuspend(bool suspend, int64_t timeUs) override;
-
- // Specifies the interval after which we requeue the buffer previously
- // queued to the encoder. This is useful in the case of surface flinger
- // providing the input surface if the resulting encoded stream is to
- // be displayed "live". If we were not to push through the extra frame
- // the decoder on the remote end would be unable to decode the latest frame.
- // This API must be called before transitioning the encoder to "executing"
- // state and once this behaviour is specified it cannot be reset.
- Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
-
- // Sets the input buffer timestamp offset.
- // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
- Status setTimeOffsetUs(int64_t timeOffsetUs) override;
-
- // When set, the max frame rate fed to the encoder will be capped at maxFps.
- Status setMaxFps(float maxFps) override;
-
- // Sets the time lapse (or slow motion) parameters.
- // When set, the sample's timestamp will be modified to playback framerate,
- // and capture timestamp will be modified to capture rate.
- Status setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
-
- // Sets the start time us (in system time), samples before which should
- // be dropped and not submitted to encoder
- Status setStartTimeUs(int64_t startTimeUs) override;
-
- // Sets the stop time us (in system time), samples after which should be dropped
- // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
- Status setStopTimeUs(int64_t stopTimeUs) override;
-
- // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
- Status setColorAspects(int32_t aspectsPacked) override;
-
-protected:
- // BufferQueue::ConsumerListener interface, called when a new frame of
- // data is available. If we're executing and a codec buffer is
- // available, we acquire the buffer, copy the GraphicBuffer reference
- // into the codec buffer, and call Empty[This]Buffer. If we're not yet
- // executing or there's no codec buffer available, we just increment
- // mNumFramesAvailable and return.
- void onFrameAvailable(const BufferItem& item) override;
-
- // BufferQueue::ConsumerListener interface, called when the client has
- // released one or more GraphicBuffers. We clear out the appropriate
- // set of mBufferSlot entries.
- void onBuffersReleased() override;
-
- // BufferQueue::ConsumerListener interface, called when the client has
- // changed the sideband stream. GraphicBufferSource doesn't handle sideband
- // streams so this is a no-op (and should never be called).
- void onSidebandStreamChanged() override;
-
-private:
-
- // Keep track of codec input buffers. They may either be available
- // (mGraphicBuffer == NULL) or in use by the codec.
- struct CodecBuffer {
- IOMX::buffer_id mBufferID;
-
- // buffer producer's frame-number for buffer
- uint64_t mFrameNumber;
-
- // buffer producer's buffer slot for buffer
- int mSlot;
-
- sp<GraphicBuffer> mGraphicBuffer;
- };
-
- // Returns the index of an available codec buffer. If none are
- // available, returns -1. Mutex must be held by caller.
- int findAvailableCodecBuffer_l();
-
- // Returns true if a codec buffer is available.
- bool isCodecBufferAvailable_l() {
- return findAvailableCodecBuffer_l() >= 0;
- }
-
- // Finds the mCodecBuffers entry that matches. Returns -1 if not found.
- int findMatchingCodecBuffer_l(IOMX::buffer_id bufferID);
-
- // Fills a codec buffer with a frame from the BufferQueue. This must
- // only be called when we know that a frame of data is ready (i.e. we're
- // in the onFrameAvailable callback, or if we're in codecBufferEmptied
- // and mNumFramesAvailable is nonzero). Returns without doing anything if
- // we don't have a codec buffer available.
- //
- // Returns true if we successfully filled a codec buffer with a BQ buffer.
- bool fillCodecBuffer_l();
-
- // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer
- // reference into the codec buffer, and submits the data to the codec.
- status_t submitBuffer_l(const BufferItem &item, int cbi);
-
- // Submits an empty buffer, with the EOS flag set. Returns without
- // doing anything if we don't have a codec buffer available.
- void submitEndOfInputStream_l();
-
- // Acquire buffer from the consumer
- status_t acquireBuffer(BufferItem *bi);
-
- // Release buffer to the consumer
- void releaseBuffer(int id, uint64_t frameNum, const sp<Fence> &fence);
-
- void setLatestBuffer_l(const BufferItem &item);
- bool repeatLatestBuffer_l();
- bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
-
- // called when the data space of the input buffer changes
- void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
-
- // Lock, covers all member variables.
- mutable Mutex mMutex;
-
- // Used to report constructor failure.
- status_t mInitCheck;
-
- // Pointer back to the IOMXNode that created us. We send buffers here.
- sp<IOMXNode> mOMXNode;
-
- // Set by omxExecuting() / omxIdling().
- bool mExecuting;
-
- bool mSuspended;
-
- // The time to stop sending buffers.
- int64_t mStopTimeUs;
-
- // Last dataspace seen
- android_dataspace mLastDataSpace;
-
- // Our BufferQueue interfaces. mProducer is passed to the producer through
- // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
- // the buffers queued by the producer.
- sp<IGraphicBufferProducer> mProducer;
- sp<IGraphicBufferConsumer> mConsumer;
-
- // Number of frames pending in BufferQueue that haven't yet been
- // forwarded to the codec.
- size_t mNumFramesAvailable;
-
- // Number of frames acquired from consumer (debug only)
- int32_t mNumBufferAcquired;
-
- // Set to true if we want to send end-of-stream after we run out of
- // frames in BufferQueue.
- bool mEndOfStream;
- bool mEndOfStreamSent;
-
- // Cache of GraphicBuffers from the buffer queue. When the codec
- // is done processing a GraphicBuffer, we can use this to map back
- // to a slot number.
- sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
- int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
-
- // Tracks codec buffers.
- Vector<CodecBuffer> mCodecBuffers;
-
- struct ActionItem {
- typedef enum {
- PAUSE,
- RESUME,
- STOP
- } ActionType;
- ActionType mAction;
- int64_t mActionTimeUs;
- };
-
- // Maintain last action timestamp to ensure all the action timestamps are
- // monotonically increasing.
- int64_t mLastActionTimeUs;
-
- // An action queue that queue up all the actions sent to GraphicBufferSource.
- // STOP action should only show up at the end of the list as all the actions
- // after a STOP action will be discarded. mActionQueue is protected by mMutex.
- List<ActionItem> mActionQueue;
-
- ////
- friend struct AHandlerReflector<GraphicBufferSource>;
-
- enum {
- kWhatRepeatLastFrame,
- };
- enum {
- kRepeatLastFrameCount = 10,
- };
-
- int64_t mPrevOriginalTimeUs;
- int64_t mSkipFramesBeforeNs;
-
- sp<FrameDropper> mFrameDropper;
-
- sp<ALooper> mLooper;
- sp<AHandlerReflector<GraphicBufferSource> > mReflector;
-
- int64_t mRepeatAfterUs;
- int32_t mRepeatLastFrameGeneration;
- int64_t mRepeatLastFrameTimestamp;
- int32_t mRepeatLastFrameCount;
-
- int mLatestBufferId;
- uint64_t mLatestBufferFrameNum;
- sp<Fence> mLatestBufferFence;
-
- // The previous buffer should've been repeated but
- // no codec buffer was available at the time.
- bool mRepeatBufferDeferred;
-
- // Time lapse / slow motion configuration
- int64_t mTimePerCaptureUs;
- int64_t mTimePerFrameUs;
- int64_t mPrevCaptureUs;
- int64_t mPrevFrameUs;
-
- int64_t mInputBufferTimeOffsetUs;
-
- ColorAspects mColorAspects;
-
- class OmxBufferSource;
- sp<OmxBufferSource> mOmxBufferSource;
-
- void onMessageReceived(const sp<AMessage> &msg);
-
- DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
-};
-
-} // namespace android
-
-#endif // GRAPHIC_BUFFER_SOURCE_H_