From: Eino-Ville Talvala Date: Tue, 21 Aug 2012 20:30:45 +0000 (-0700) Subject: Camera2: Replace MediaConsumer with BufferItemConsumer. X-Git-Tag: android-x86-4.4-r1~662^2^2~266 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=30e65e7e2ec01e13e45b5e38552a34d2fbb3f866;p=android-x86%2Fframeworks-av.git Camera2: Replace MediaConsumer with BufferItemConsumer. Get rid of MediaConsumer, which was largely duplicated code, and replace it with the simpler BufferItemConsumer. Bug: 6243944 Change-Id: I242d80c5fe39f2ee581ec8bb46f362997d994b0a --- diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index c14ae2261d..8cccf49294 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -10,8 +10,7 @@ LOCAL_SRC_FILES:= \ CameraService.cpp \ CameraClient.cpp \ Camera2Client.cpp \ - Camera2Device.cpp \ - MediaConsumer.cpp + Camera2Device.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 66d8a5077c..aa30501682 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -920,6 +920,9 @@ void Camera2Client::releaseRecordingFrame(const sp& mem) { Mutex::Autolock icl(mICameraLock); status_t res; if ( checkPid(__FUNCTION__) != OK) return; + + LockedParameters::Key k(mParameters); + // Make sure this is for the current heap ssize_t offset; size_t size; @@ -937,16 +940,36 @@ void Camera2Client::releaseRecordingFrame(const sp& mem) { __FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource); return; } - buffer_handle_t imgBuffer = *(buffer_handle_t*)(data + 4); + + // Release the buffer back to the recording queue + + buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4); + + size_t itemIndex; + for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { + const BufferItemConsumer::BufferItem item = mRecordingBuffers[itemIndex]; + if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT && + item.mGraphicBuffer->handle == imgHandle) { + break; + } + } + if (itemIndex == mRecordingBuffers.size()) { + ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of " + "outstanding buffers", __FUNCTION__, mCameraId, imgHandle); + return; + } + ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId, - imgBuffer); - res = mRecordingConsumer->freeBuffer(imgBuffer); + imgHandle); + + res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); if (res != OK) { ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):" "%s (%d)", - __FUNCTION__, mCameraId, imgBuffer, strerror(-res), res); + __FUNCTION__, mCameraId, imgHandle, strerror(-res), res); return; } + mRecordingBuffers.replaceAt(itemIndex); mRecordingHeapFree++; } @@ -2313,13 +2336,14 @@ void Camera2Client::onRecordingFrameAvailable() { { LockedParameters::Key k(mParameters); - buffer_handle_t imgBuffer; - res = mRecordingConsumer->getNextBuffer(&imgBuffer, ×tamp); + BufferItemConsumer::BufferItem imgBuffer; + res = mRecordingConsumer->acquireBuffer(&imgBuffer); if (res != OK) { ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return; } + timestamp = imgBuffer.mTimestamp; mRecordingFrameCount++; ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount); @@ -2330,7 +2354,7 @@ void Camera2Client::onRecordingFrameAvailable() { ALOGV("%s: Camera %d: Discarding recording image buffers received after " "recording done", __FUNCTION__, mCameraId); - mRecordingConsumer->freeBuffer(imgBuffer); + mRecordingConsumer->releaseBuffer(imgBuffer); return; } @@ -2345,9 +2369,20 @@ void Camera2Client::onRecordingFrameAvailable() { if (mRecordingHeap->mHeap->getSize() == 0) { ALOGE("%s: Camera %d: Unable to allocate memory for recording", __FUNCTION__, mCameraId); - mRecordingConsumer->freeBuffer(imgBuffer); + mRecordingConsumer->releaseBuffer(imgBuffer); return; } + for (size_t i = 0; i < mRecordingBuffers.size(); i++) { + if (mRecordingBuffers[i].mBuf != + BufferItemConsumer::INVALID_BUFFER_SLOT) { + ALOGE("%s: Camera %d: Non-empty recording buffers list!", + __FUNCTION__, mCameraId); + } + } + mRecordingBuffers.clear(); + mRecordingBuffers.setCapacity(mRecordingHeapCount); + mRecordingBuffers.insertAt(0, mRecordingHeapCount); + mRecordingHeapHead = 0; mRecordingHeapFree = mRecordingHeapCount; } @@ -2355,7 +2390,7 @@ void Camera2Client::onRecordingFrameAvailable() { if ( mRecordingHeapFree == 0) { ALOGE("%s: Camera %d: No free recording buffers, dropping frame", __FUNCTION__, mCameraId); - mRecordingConsumer->freeBuffer(imgBuffer); + mRecordingConsumer->releaseBuffer(imgBuffer); return; } @@ -2374,10 +2409,11 @@ void Camera2Client::onRecordingFrameAvailable() { uint8_t *data = (uint8_t*)heap->getBase() + offset; uint32_t type = kMetadataBufferTypeGrallocSource; - memcpy(data, &type, 4); - memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t)); + *((uint32_t*)data) = type; + *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle; ALOGV("%s: Camera %d: Sending out buffer_handle_t %p", - __FUNCTION__, mCameraId, imgBuffer); + __FUNCTION__, mCameraId, imgBuffer.mGraphicBuffer->handle); + mRecordingBuffers.replaceAt(imgBuffer, heapIdx); recordingHeap = mRecordingHeap; } @@ -3530,7 +3566,10 @@ status_t Camera2Client::updateRecordingStream(const Parameters ¶ms) { // Create CPU buffer queue endpoint. We need one more buffer here so that we can // always acquire and free a buffer when the heap is full; otherwise the consumer // will have buffers in flight we'll never clear out. - mRecordingConsumer = new MediaConsumer(mRecordingHeapCount + 1); + mRecordingConsumer = new BufferItemConsumer( + GRALLOC_USAGE_HW_VIDEO_ENCODER, + mRecordingHeapCount + 1, + true); mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this)); mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer")); mRecordingWindow = new SurfaceTextureClient( diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index fa300e70ad..028d45899b 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -23,7 +23,7 @@ #include #include #include -#include "MediaConsumer.h" +#include namespace android { @@ -363,11 +363,11 @@ private: int mRecordingStreamId; int mRecordingFrameCount; - sp mRecordingConsumer; + sp mRecordingConsumer; sp mRecordingWindow; // Simple listener that forwards frame available notifications from // a CPU consumer to the recording notification - class RecordingWaiter: public MediaConsumer::FrameAvailableListener { + class RecordingWaiter: public BufferItemConsumer::FrameAvailableListener { public: RecordingWaiter(Camera2Client *parent) : mParent(parent) {} void onFrameAvailable() { mParent->onRecordingFrameAvailable(); } @@ -380,6 +380,7 @@ private: static const size_t kDefaultRecordingHeapCount = 8; size_t mRecordingHeapCount; + Vector mRecordingBuffers; size_t mRecordingHeapHead, mRecordingHeapFree; // Handle new recording image buffers void onRecordingFrameAvailable(); @@ -442,9 +443,9 @@ private: // Update parameters all requests use, based on mParameters status_t updateRequestCommon(camera_metadata_t *request, const Parameters ¶ms); - // Map from sensor active array pixel coordinates to normalized camera parameter coordinates - // The former are (0,0)-(array width - 1, array height - 1), the latter from - // (-1000,-1000)-(1000,1000) + // Map from sensor active array pixel coordinates to normalized camera + // parameter coordinates. The former are (0,0)-(array width - 1, array height + // - 1), the latter from (-1000,-1000)-(1000,1000) int arrayXToNormalized(int width) const; int arrayYToNormalized(int height) const; diff --git a/services/camera/libcameraservice/MediaConsumer.cpp b/services/camera/libcameraservice/MediaConsumer.cpp deleted file mode 100644 index a5fe302d43..0000000000 --- a/services/camera/libcameraservice/MediaConsumer.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "MediaConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - -#include "MediaConsumer.h" - -#define MC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define MC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define MC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define MC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define MC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -MediaConsumer::MediaConsumer(uint32_t maxLockedBuffers) : - mMaxLockedBuffers(maxLockedBuffers), - mCurrentLockedBuffers(0) -{ - mName = String8::format("mc-unnamed-%d-%d", getpid(), - createProcessUniqueId()); - - mBufferQueue = new BufferQueue(true); - - wp listener; - sp proxy; - listener = static_cast(this); - proxy = new BufferQueue::ProxyConsumerListener(listener); - - status_t err = mBufferQueue->consumerConnect(proxy); - if (err != NO_ERROR) { - ALOGE("MediaConsumer: error connecting to BufferQueue: %s (%d)", - strerror(-err), err); - } else { - mBufferQueue->setSynchronousMode(true); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); - mBufferQueue->setConsumerName(mName); - } -} - -MediaConsumer::~MediaConsumer() -{ - Mutex::Autolock _l(mMutex); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); -} - -void MediaConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mBufferQueue->setConsumerName(name); -} - -status_t MediaConsumer::getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp) { - status_t err; - - if (!buffer) return BAD_VALUE; - if (mCurrentLockedBuffers == mMaxLockedBuffers) { - MC_LOGV("Too many buffers (max %d)", mCurrentLockedBuffers); - return INVALID_OPERATION; - } - - BufferQueue::BufferItem b; - - Mutex::Autolock _l(mMutex); - - err = mBufferQueue->acquireBuffer(&b); - if (err != OK) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - MC_LOGV("No buffer available"); - return BAD_VALUE; - } else { - MC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - return err; - } - } - - int buf = b.mBuf; - - if (b.mGraphicBuffer != NULL) { - mBufferSlot[buf] = b.mGraphicBuffer; - } - - if (b.mFence.get()) { - err = b.mFence->wait(Fence::TIMEOUT_NEVER); - if (err != OK) { - MC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - *buffer = mBufferSlot[buf]->handle; - *timestamp = b.mTimestamp; - - mCurrentLockedBuffers++; - MC_LOGV("getNextBuffer: %d buffers in use", mCurrentLockedBuffers); - return OK; -} - -status_t MediaConsumer::freeBuffer(buffer_handle_t buffer) { - Mutex::Autolock _l(mMutex); - int buf = 0; - status_t err; - - for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) { - if (buffer == mBufferSlot[buf]->handle) break; - } - if (buf == BufferQueue::NUM_BUFFER_SLOTS) { - MC_LOGE("%s: Can't find buffer to free", __FUNCTION__); - return BAD_VALUE; - } - - err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, - Fence::NO_FENCE); - if (err == BufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(buf); - } else if (err != OK) { - MC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__, - buf); - return err; - } - mCurrentLockedBuffers--; - MC_LOGV("freeBuffer: %d buffers in use", mCurrentLockedBuffers); - - return OK; -} - -void MediaConsumer::setFrameAvailableListener( - const sp& listener) { - MC_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - - -void MediaConsumer::onFrameAvailable() { - MC_LOGV("onFrameAvailable"); - sp listener; - { // scope for the lock - Mutex::Autolock _l(mMutex); - listener = mFrameAvailableListener; - } - - if (listener != NULL) { - MC_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void MediaConsumer::onBuffersReleased() { - MC_LOGV("onBuffersReleased"); - - Mutex::Autolock lock(mMutex); - - uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } - -} - -status_t MediaConsumer::freeBufferLocked(int buf) { - status_t err = OK; - - mBufferSlot[buf] = NULL; - return err; -} - -} // namespace android diff --git a/services/camera/libcameraservice/MediaConsumer.h b/services/camera/libcameraservice/MediaConsumer.h deleted file mode 100644 index 3377d94589..0000000000 --- a/services/camera/libcameraservice/MediaConsumer.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2012 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 ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H -#define ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H - -#include - -#include - -#include -#include -#include - -#define ANDROID_GRAPHICS_MEDIACONSUMER_JNI_ID "mMediaConsumer" - -namespace android { - -/** - * MediaConsumer is a BufferQueue consumer endpoint that makes it - * straightforward to bridge Camera 2 to the existing media recording framework. - * This queue is synchronous by default. - * - * TODO: This is a temporary replacement for the full camera->media recording - * path using SurfaceMediaEncoder or equivalent. - */ - -class MediaConsumer: public virtual RefBase, - protected BufferQueue::ConsumerListener -{ - public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. A new frame queued will always trigger the - // callback, whether the queue is empty or not. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - // Create a new media consumer. The maxBuffers parameter specifies - // how many buffers can be locked for user access at the same time. - MediaConsumer(uint32_t maxBuffers); - - virtual ~MediaConsumer(); - - // set the name of the MediaConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer. Returns BAD_VALUE if no - // new buffer is available, and INVALID_OPERATION if the maximum number of - // buffers is already in use. - // - // Only a fixed number of buffers can be available at a time, determined by - // the construction-time maxBuffers parameter. If INVALID_OPERATION is - // returned by getNextBuffer, then old buffers must be returned to the - // queue by calling freeBuffer before more buffers can be acquired. - status_t getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp); - - // Returns a buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be locked at a time, old buffers must - // be released by calling unlockBuffer to ensure new buffers can be acquired by - // lockNextBuffer. - status_t freeBuffer(buffer_handle_t buffer); - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp& listener); - - sp getProducerInterface() const { return mBufferQueue; } - protected: - - // Implementation of the BufferQueue::ConsumerListener interface. These - // calls are used to notify the MediaConsumer of asynchronous events in the - // BufferQueue. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - private: - // Free local buffer state - status_t freeBufferLocked(int buf); - - // Maximum number of buffers that can be locked at a time - uint32_t mMaxLockedBuffers; - - // mName is a string used to identify the SurfaceTexture in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - sp mFrameAvailableListener; - - // Underlying buffer queue - sp mBufferQueue; - - // Array for caching buffers from the buffer queue - sp mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS]; - // Count of currently outstanding buffers - uint32_t mCurrentLockedBuffers; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of MediaConsumer objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; -}; - -} // namespace android - -#endif // ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H