summaryrefslogtreecommitdiffstats
path: root/camera/BufferSourceAdapter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'camera/BufferSourceAdapter.cpp')
-rw-r--r--camera/BufferSourceAdapter.cpp1007
1 files changed, 1007 insertions, 0 deletions
diff --git a/camera/BufferSourceAdapter.cpp b/camera/BufferSourceAdapter.cpp
new file mode 100644
index 0000000..3c4e698
--- /dev/null
+++ b/camera/BufferSourceAdapter.cpp
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * 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.
+ */
+
+#ifdef OMAP_ENHANCEMENT_CPCAM
+
+#include "BufferSourceAdapter.h"
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+#include <hal_public.h>
+
+namespace Ti {
+namespace Camera {
+
+static int getANWFormat(const char* parameters_format)
+{
+ int format = HAL_PIXEL_FORMAT_TI_NV12;
+
+ if (parameters_format != NULL) {
+ if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) {
+ CAMHAL_LOGDA("CbYCrY format selected");
+ format = HAL_PIXEL_FORMAT_TI_UYVY;
+ } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+ CAMHAL_LOGDA("YUV420SP format selected");
+ format = HAL_PIXEL_FORMAT_TI_NV12;
+ } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) {
+ CAMHAL_LOGDA("RGB565 format selected");
+ // TODO(XXX): not defined yet
+ format = -1;
+ } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) {
+ format = HAL_PIXEL_FORMAT_TI_Y16;
+ } else {
+ CAMHAL_LOGDA("Invalid format, NV12 format selected as default");
+ format = HAL_PIXEL_FORMAT_TI_NV12;
+ }
+ }
+
+ return format;
+}
+
+static int getUsageFromANW(int format)
+{
+ int usage = GRALLOC_USAGE_SW_READ_RARELY |
+ GRALLOC_USAGE_SW_WRITE_NEVER;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_Y16:
+ case HAL_PIXEL_FORMAT_TI_UYVY:
+ // This usage flag indicates to gralloc we want the
+ // buffers to come from system heap
+ usage |= GRALLOC_USAGE_PRIVATE_0;
+ break;
+ default:
+ // No special flags needed
+ break;
+ }
+ return usage;
+}
+
+static const char* getFormatFromANW(int format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ // Assuming NV12 1D is RAW or Image frame
+ return android::CameraParameters::PIXEL_FORMAT_YUV420SP;
+ case HAL_PIXEL_FORMAT_TI_Y16:
+ return android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
+ case HAL_PIXEL_FORMAT_TI_UYVY:
+ return android::CameraParameters::PIXEL_FORMAT_YUV422I;
+ default:
+ break;
+ }
+ return android::CameraParameters::PIXEL_FORMAT_YUV420SP;
+}
+
+static CameraFrame::FrameType formatToOutputFrameType(const char* format) {
+ switch (getANWFormat(format)) {
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_Y16:
+ case HAL_PIXEL_FORMAT_TI_UYVY:
+ // Assuming NV12 1D is RAW or Image frame
+ return CameraFrame::RAW_FRAME;
+ default:
+ break;
+ }
+ return CameraFrame::RAW_FRAME;
+}
+
+static int getHeightFromFormat(const char* format, int stride, int size) {
+ CAMHAL_ASSERT((NULL != format) && (0 <= stride) && (0 <= size));
+ switch (getANWFormat(format)) {
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ return (size / (3 * stride)) * 2;
+ case HAL_PIXEL_FORMAT_TI_Y16:
+ case HAL_PIXEL_FORMAT_TI_UYVY:
+ return (size / stride) / 2;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*--------------------BufferSourceAdapter Class STARTS here-----------------------------*/
+
+
+///Constant definitions
+// TODO(XXX): Temporarily increase number of buffers we can allocate from ANW
+// until faux-NPA mode is implemented
+const int BufferSourceAdapter::NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP = 15;
+
+/**
+ * Display Adapter class STARTS here..
+ */
+BufferSourceAdapter::BufferSourceAdapter() : mBufferCount(0)
+{
+ LOG_FUNCTION_NAME;
+
+ mPixelFormat = NULL;
+ mBuffers = NULL;
+ mFrameProvider = NULL;
+ mBufferSource = NULL;
+
+ mFrameWidth = 0;
+ mFrameHeight = 0;
+ mPreviewWidth = 0;
+ mPreviewHeight = 0;
+
+ LOG_FUNCTION_NAME_EXIT;
+}
+
+BufferSourceAdapter::~BufferSourceAdapter()
+{
+ LOG_FUNCTION_NAME;
+
+ freeBufferList(mBuffers);
+
+ android::AutoMutex lock(mLock);
+
+ destroy();
+
+ if (mFrameProvider) {
+ // Unregister with the frame provider
+ mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES);
+ delete mFrameProvider;
+ mFrameProvider = NULL;
+ }
+
+ if (mQueueFrame.get()) {
+ mQueueFrame->requestExit();
+ mQueueFrame.clear();
+ }
+
+ if (mReturnFrame.get()) {
+ mReturnFrame->requestExit();
+ mReturnFrame.clear();
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+}
+
+status_t BufferSourceAdapter::initialize()
+{
+ status_t ret = NO_ERROR;
+
+ LOG_FUNCTION_NAME;
+
+ mReturnFrame.clear();
+ mReturnFrame = new ReturnFrame(this);
+ mReturnFrame->run();
+
+ mQueueFrame.clear();
+ mQueueFrame = new QueueFrame(this);
+ mQueueFrame->run();
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+int BufferSourceAdapter::setPreviewWindow(preview_stream_ops_t *source)
+{
+ LOG_FUNCTION_NAME;
+
+ if (!source) {
+ CAMHAL_LOGEA("NULL window object passed to DisplayAdapter");
+ LOG_FUNCTION_NAME_EXIT;
+ return BAD_VALUE;
+ }
+
+ if (mBufferSource) {
+ char id1[OP_STR_SIZE], id2[OP_STR_SIZE];
+ status_t ret;
+
+ ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1));
+ if (ret != 0) {
+ CAMHAL_LOGE("Surface::getId returned error %d", ret);
+ return ret;
+ }
+
+ ret = extendedOps()->get_id(source, id2, sizeof(id2));
+ if (ret != 0) {
+ CAMHAL_LOGE("Surface::getId returned error %d", ret);
+ return ret;
+ }
+ if ((0 >= strlen(id1)) || (0 >= strlen(id2))) {
+ CAMHAL_LOGE("Cannot set ST without name: id1:\"%s\" id2:\"%s\"",
+ id1, id2);
+ return NOT_ENOUGH_DATA;
+ }
+ if (0 == strcmp(id1, id2)) {
+ return ALREADY_EXISTS;
+ }
+
+ // client has to unset mBufferSource before being able to set a new one
+ return BAD_VALUE;
+ }
+
+ // Move to new source obj
+ mBufferSource = source;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NO_ERROR;
+}
+
+bool BufferSourceAdapter::match(const char * str) {
+ char id1[OP_STR_SIZE];
+ status_t ret;
+
+ ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1));
+
+ if (ret != 0) {
+ CAMHAL_LOGE("Surface::getId returned error %d", ret);
+ }
+
+ return strcmp(id1, str) == 0;
+}
+
+int BufferSourceAdapter::setFrameProvider(FrameNotifier *frameProvider)
+{
+ LOG_FUNCTION_NAME;
+
+ if ( !frameProvider ) {
+ CAMHAL_LOGEA("NULL passed for frame provider");
+ LOG_FUNCTION_NAME_EXIT;
+ return BAD_VALUE;
+ }
+
+ if ( NULL != mFrameProvider ) {
+ delete mFrameProvider;
+ }
+
+ mFrameProvider = new FrameProvider(frameProvider, this, frameCallback);
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NO_ERROR;
+}
+
+int BufferSourceAdapter::setErrorHandler(ErrorNotifier *errorNotifier)
+{
+ status_t ret = NO_ERROR;
+
+ LOG_FUNCTION_NAME;
+
+ if ( NULL == errorNotifier ) {
+ CAMHAL_LOGEA("Invalid Error Notifier reference");
+ return -EINVAL;
+ }
+
+ mErrorNotifier = errorNotifier;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+int BufferSourceAdapter::enableDisplay(int width, int height,
+ struct timeval *refTime)
+{
+ LOG_FUNCTION_NAME;
+ CameraFrame::FrameType frameType;
+
+ if (mFrameProvider == NULL) {
+ // no-op frame provider not set yet
+ return NO_ERROR;
+ }
+
+ if (mBufferSourceDirection == BUFFER_SOURCE_TAP_IN) {
+ // only supporting one type of input frame
+ frameType = CameraFrame::REPROCESS_INPUT_FRAME;
+ } else {
+ frameType = formatToOutputFrameType(mPixelFormat);
+ }
+
+ mFrameProvider->enableFrameNotification(frameType);
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NO_ERROR;
+}
+
+int BufferSourceAdapter::disableDisplay(bool cancel_buffer)
+{
+ LOG_FUNCTION_NAME;
+
+ if (mFrameProvider) mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES);
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NO_ERROR;
+}
+
+status_t BufferSourceAdapter::pauseDisplay(bool pause)
+{
+ status_t ret = NO_ERROR;
+
+ LOG_FUNCTION_NAME;
+
+ // no-op for BufferSourceAdapter
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+
+void BufferSourceAdapter::destroy()
+{
+ LOG_FUNCTION_NAME;
+
+ mBufferCount = 0;
+
+ LOG_FUNCTION_NAME_EXIT;
+}
+
+CameraBuffer* BufferSourceAdapter::allocateBufferList(int width, int dummyHeight, const char* format,
+ int &bytes, int numBufs)
+{
+ LOG_FUNCTION_NAME;
+ status_t err;
+ int i = -1;
+ const int lnumBufs = numBufs;
+ int undequeued = 0;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+
+ mBuffers = new CameraBuffer [lnumBufs];
+ memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
+
+ if ( NULL == mBufferSource ) {
+ return NULL;
+ }
+
+ int pixFormat = getANWFormat(format);
+ int usage = getUsageFromANW(pixFormat);
+ mPixelFormat = CameraHal::getPixelFormatConstant(format);
+
+ // Set gralloc usage bits for window.
+ err = mBufferSource->set_usage(mBufferSource, usage);
+ if (err != 0) {
+ CAMHAL_LOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
+
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+
+ return NULL;
+ }
+
+ CAMHAL_LOGDB("Number of buffers set to BufferSourceAdapter %d", numBufs);
+ // Set the number of buffers needed for this buffer source
+ err = mBufferSource->set_buffer_count(mBufferSource, numBufs);
+ if (err != 0) {
+ CAMHAL_LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err);
+
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+
+ return NULL;
+ }
+
+ CAMHAL_LOGDB("Configuring %d buffers for ANativeWindow", numBufs);
+ mBufferCount = numBufs;
+
+ // re-calculate height depending on stride and size
+ int height = getHeightFromFormat(format, width, bytes);
+
+ // Set window geometry
+ err = mBufferSource->set_buffers_geometry(mBufferSource,
+ width, height,
+ pixFormat);
+
+ if (err != 0) {
+ CAMHAL_LOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err);
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ return NULL;
+ }
+
+ if ( mBuffers == NULL ) {
+ CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers");
+ LOG_FUNCTION_NAME_EXIT;
+ return NULL;
+ }
+
+ mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued);
+
+ for (i = 0; i < mBufferCount; i++ ) {
+ buffer_handle_t *handle;
+ int stride; // dummy variable to get stride
+ // TODO(XXX): Do we need to keep stride information in camera hal?
+
+ err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride);
+
+ if (err != 0) {
+ CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ goto fail;
+ }
+
+ CAMHAL_LOGDB("got handle %p", handle);
+ mBuffers[i].opaque = (void *)handle;
+ mBuffers[i].type = CAMERA_BUFFER_ANW;
+ mBuffers[i].format = mPixelFormat;
+ mFramesWithCameraAdapterMap.add(handle, i);
+
+ bytes = CameraHal::calculateBufferSize(format, width, height);
+ }
+
+ for( i = 0; i < mBufferCount-undequeued; i++ ) {
+ void *y_uv[2];
+ android::Rect bounds(width, height);
+
+ buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque;
+ mBufferSource->lock_buffer(mBufferSource, handle);
+ mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
+ mBuffers[i].mapped = y_uv[0];
+ }
+
+ // return the rest of the buffers back to ANativeWindow
+ for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++) {
+ buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque;
+ void *y_uv[2];
+ android::Rect bounds(width, height);
+
+ mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
+ mBuffers[i].mapped = y_uv[0];
+ mapper.unlock(*handle);
+
+ err = mBufferSource->cancel_buffer(mBufferSource, handle);
+ if (err != 0) {
+ CAMHAL_LOGEB("cancel_buffer failed: %s (%d)", strerror(-err), -err);
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ goto fail;
+ }
+ mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[i].opaque);
+ }
+
+ mFrameWidth = width;
+ mFrameHeight = height;
+ mBufferSourceDirection = BUFFER_SOURCE_TAP_OUT;
+
+ return mBuffers;
+
+ fail:
+ // need to cancel buffers if any were dequeued
+ for (int start = 0; start < i && i > 0; start++) {
+ int err = mBufferSource->cancel_buffer(mBufferSource,
+ (buffer_handle_t *) mBuffers[start].opaque);
+ if (err != 0) {
+ CAMHAL_LOGEB("cancelBuffer failed w/ error 0x%08x", err);
+ break;
+ }
+ mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[start].opaque);
+ }
+
+ freeBufferList(mBuffers);
+
+ CAMHAL_LOGEA("Error occurred, performing cleanup");
+
+ if (NULL != mErrorNotifier.get()) {
+ mErrorNotifier->errorNotify(-ENOMEM);
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+ return NULL;
+
+}
+
+CameraBuffer *BufferSourceAdapter::getBuffers(bool reset) {
+ int undequeued = 0;
+ status_t err;
+ android::Mutex::Autolock lock(mLock);
+
+ if (!mBufferSource || !mBuffers) {
+ CAMHAL_LOGE("Adapter is not set up properly: "
+ "mBufferSource:%p mBuffers:%p",
+ mBufferSource, mBuffers);
+ goto fail;
+ }
+
+ // CameraHal is indicating to us that the state of the mBuffer
+ // might have changed. We might need to check the state of the
+ // buffer list and pass a new one depending on the state of our
+ // surface
+ if (reset) {
+ const int lnumBufs = mBufferCount;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+ android::Rect bounds(mFrameWidth, mFrameHeight);
+ void *y_uv[2];
+ CameraBuffer * newBuffers = NULL;
+ unsigned int index = 0;
+ android::KeyedVector<void*, int> missingIndices;
+
+ newBuffers = new CameraBuffer [lnumBufs];
+ memset (newBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
+
+ // Use this vector to figure out missing indices
+ for (int i = 0; i < mBufferCount; i++) {
+ missingIndices.add(mBuffers[i].opaque, i);
+ }
+
+ // assign buffers that we have already dequeued
+ for (index = 0; index < mFramesWithCameraAdapterMap.size(); index++) {
+ int value = mFramesWithCameraAdapterMap.valueAt(index);
+ newBuffers[index].opaque = mBuffers[value].opaque;
+ newBuffers[index].type = mBuffers[value].type;
+ newBuffers[index].format = mBuffers[value].format;
+ newBuffers[index].mapped = mBuffers[value].mapped;
+ mFramesWithCameraAdapterMap.replaceValueAt(index, index);
+ missingIndices.removeItem(newBuffers[index].opaque);
+ }
+
+ mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued);
+
+ // dequeue the rest of the buffers
+ for (index; index < (unsigned int)(mBufferCount-undequeued); index++) {
+ buffer_handle_t *handle;
+ int stride; // dummy variable to get stride
+
+ err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride);
+ if (err != 0) {
+ CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ goto fail;
+ }
+ newBuffers[index].opaque = (void *)handle;
+ newBuffers[index].type = CAMERA_BUFFER_ANW;
+ newBuffers[index].format = mPixelFormat;
+ mFramesWithCameraAdapterMap.add(handle, index);
+
+ mBufferSource->lock_buffer(mBufferSource, handle);
+ mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
+ newBuffers[index].mapped = y_uv[0];
+ CAMHAL_LOGDB("got handle %p", handle);
+
+ missingIndices.removeItem(newBuffers[index].opaque);
+ }
+
+ // now we need to figure out which buffers aren't dequeued
+ // which are in mBuffers but not newBuffers yet
+ if ((mBufferCount - index) != missingIndices.size()) {
+ CAMHAL_LOGD("Hrmm somethings gone awry. We are missing a different number"
+ " of buffers than we can fill");
+ }
+ for (unsigned int i = 0; i < missingIndices.size(); i++) {
+ int j = missingIndices.valueAt(i);
+
+ CAMHAL_LOGD("Filling at %d", j);
+ newBuffers[index].opaque = mBuffers[j].opaque;
+ newBuffers[index].type = mBuffers[j].type;
+ newBuffers[index].format = mBuffers[j].format;
+ newBuffers[index].mapped = mBuffers[j].mapped;
+ }
+
+ delete [] mBuffers;
+ mBuffers = newBuffers;
+ }
+
+ return mBuffers;
+
+ fail:
+ return NULL;
+}
+
+unsigned int BufferSourceAdapter::getSize() {
+ android::Mutex::Autolock lock(mLock);
+ return CameraHal::calculateBufferSize(mPixelFormat, mFrameWidth, mFrameHeight);
+}
+
+int BufferSourceAdapter::getBufferCount() {
+ int count = -1;
+
+ android::Mutex::Autolock lock(mLock);
+ if (mBufferSource) extendedOps()->get_buffer_count(mBufferSource, &count);
+ return count;
+}
+
+CameraBuffer* BufferSourceAdapter::getBufferList(int *num) {
+ LOG_FUNCTION_NAME;
+ status_t err;
+ const int lnumBufs = 1;
+ int formatSource;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+ buffer_handle_t *handle;
+
+ // TODO(XXX): Only supporting one input buffer at a time right now
+ *num = 1;
+ mBufferCount = *num;
+ mBuffers = new CameraBuffer [lnumBufs];
+ memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
+
+ if ( NULL == mBufferSource ) {
+ return NULL;
+ }
+
+ err = extendedOps()->update_and_get_buffer(mBufferSource,
+ &handle,
+ &mBuffers[0].stride,
+ &mBuffers[0].privateData);
+ if (err != 0) {
+ CAMHAL_LOGEB("update and get buffer failed: %s (%d)", strerror(-err), -err);
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ goto fail;
+ }
+
+ CAMHAL_LOGD("got handle %p", handle);
+ mBuffers[0].opaque = (void *)handle;
+ mBuffers[0].type = CAMERA_BUFFER_ANW;
+ mFramesWithCameraAdapterMap.add(handle, 0);
+
+ err = extendedOps()->get_buffer_dimension(mBufferSource, &mBuffers[0].width, &mBuffers[0].height);
+ err = extendedOps()->get_buffer_format(mBufferSource, &formatSource);
+
+ int t, l, r, b, w, h;
+ err = extendedOps()->get_crop(mBufferSource, &l, &t, &r, &b);
+ err = extendedOps()->get_current_size(mBufferSource, &w, &h);
+
+ // lock buffer
+ {
+ void *y_uv[2];
+ android::Rect bounds(mBuffers[0].width, mBuffers[0].height);
+ mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
+ mBuffers[0].mapped = y_uv[0];
+ }
+
+ mFrameWidth = mBuffers[0].width;
+ mFrameHeight = mBuffers[0].height;
+ mPixelFormat = getFormatFromANW(formatSource);
+
+ mBuffers[0].format = mPixelFormat;
+ mBuffers[0].actual_size = CameraHal::calculateBufferSize(mPixelFormat, w, h);
+ mBuffers[0].offset = t * w + l * CameraHal::getBPP(mPixelFormat);
+ mBufferSourceDirection = BUFFER_SOURCE_TAP_IN;
+
+ return mBuffers;
+
+ fail:
+ // need to cancel buffers if any were dequeued
+ freeBufferList(mBuffers);
+
+ if (NULL != mErrorNotifier.get()) {
+ mErrorNotifier->errorNotify(-ENOMEM);
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+ return NULL;
+}
+
+uint32_t * BufferSourceAdapter::getOffsets()
+{
+ LOG_FUNCTION_NAME;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NULL;
+}
+
+int BufferSourceAdapter::minUndequeueableBuffers(int& undequeueable) {
+ LOG_FUNCTION_NAME;
+ int ret = NO_ERROR;
+
+ if(!mBufferSource)
+ {
+ ret = INVALID_OPERATION;
+ goto end;
+ }
+
+ ret = mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeueable);
+ if ( NO_ERROR != ret ) {
+ CAMHAL_LOGEB("get_min_undequeued_buffer_count failed: %s (%d)", strerror(-ret), -ret);
+ if ( ENODEV == ret ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+ return -ret;
+ }
+
+ end:
+ return ret;
+ LOG_FUNCTION_NAME_EXIT;
+
+}
+
+int BufferSourceAdapter::maxQueueableBuffers(unsigned int& queueable)
+{
+ LOG_FUNCTION_NAME;
+ int ret = NO_ERROR;
+ int undequeued = 0;
+
+ if(mBufferCount == 0) {
+ ret = INVALID_OPERATION;
+ goto end;
+ }
+
+ ret = minUndequeueableBuffers(undequeued);
+ if (ret != NO_ERROR) {
+ goto end;
+ }
+
+ queueable = mBufferCount - undequeued;
+
+ end:
+ return ret;
+ LOG_FUNCTION_NAME_EXIT;
+}
+
+int BufferSourceAdapter::getFd()
+{
+ LOG_FUNCTION_NAME;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return -1;
+
+}
+
+status_t BufferSourceAdapter::returnBuffersToWindow()
+{
+ status_t ret = NO_ERROR;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+
+ //Give the buffers back to display here - sort of free it
+ if (mBufferSource) {
+ for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) {
+ int value = mFramesWithCameraAdapterMap.valueAt(i);
+ buffer_handle_t *handle = (buffer_handle_t *) mBuffers[value].opaque;
+
+ // if buffer index is out of bounds skip
+ if ((value < 0) || (value >= mBufferCount)) {
+ CAMHAL_LOGEA("Potential out bounds access to handle...skipping");
+ continue;
+ }
+
+ // unlock buffer before giving it up
+ mapper.unlock(*handle);
+
+ ret = mBufferSource->cancel_buffer(mBufferSource, handle);
+ if ( ENODEV == ret ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ return -ret;
+ } else if ( NO_ERROR != ret ) {
+ CAMHAL_LOGEB("cancel_buffer() failed: %s (%d)",
+ strerror(-ret),
+ -ret);
+ return -ret;
+ }
+ }
+ } else {
+ CAMHAL_LOGE("mBufferSource is NULL");
+ }
+
+ ///Clear the frames with camera adapter map
+ mFramesWithCameraAdapterMap.clear();
+
+ return ret;
+
+}
+
+int BufferSourceAdapter::freeBufferList(CameraBuffer * buflist)
+{
+ LOG_FUNCTION_NAME;
+
+ status_t ret = NO_ERROR;
+
+ if ( mBuffers != buflist ) {
+ return BAD_VALUE;
+ }
+
+ android::AutoMutex lock(mLock);
+
+ if (mBufferSourceDirection == BUFFER_SOURCE_TAP_OUT) returnBuffersToWindow();
+
+ if( mBuffers != NULL)
+ {
+ delete [] mBuffers;
+ mBuffers = NULL;
+ }
+
+ return NO_ERROR;
+}
+
+
+bool BufferSourceAdapter::supportsExternalBuffering()
+{
+ return false;
+}
+
+void BufferSourceAdapter::addFrame(CameraFrame* frame)
+{
+ if (mQueueFrame.get()) {
+ mQueueFrame->addFrame(frame);
+ }
+}
+
+void BufferSourceAdapter::handleFrameCallback(CameraFrame* frame)
+{
+ status_t ret = NO_ERROR;
+ buffer_handle_t *handle = NULL;
+ int i;
+ uint32_t x, y;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+
+ android::AutoMutex lock(mLock);
+
+ if (!mBuffers || !frame->mBuffer) {
+ CAMHAL_LOGEA("Adapter sent BufferSourceAdapter a NULL frame?");
+ return;
+ }
+
+ for ( i = 0; i < mBufferCount; i++ ) {
+ if (frame->mBuffer == &mBuffers[i]) {
+ break;
+ }
+ }
+
+ if (i >= mBufferCount) {
+ CAMHAL_LOGD("Can't find frame in buffer list");
+ if (frame->mFrameType != CameraFrame::REPROCESS_INPUT_FRAME) {
+ mFrameProvider->returnFrame(frame->mBuffer,
+ static_cast<CameraFrame::FrameType>(frame->mFrameType));
+ }
+ return;
+ }
+
+ handle = (buffer_handle_t *) mBuffers[i].opaque;
+
+ // Handle input buffers
+ // TODO(XXX): Move handling of input buffers out of here if
+ // it becomes more complex
+ if (frame->mFrameType == CameraFrame::REPROCESS_INPUT_FRAME) {
+ CAMHAL_LOGD("Unlock %p (buffer #%d)", handle, i);
+ mapper.unlock(*handle);
+ extendedOps()->release_buffer(mBufferSource, mBuffers[i].privateData);
+ return;
+ }
+
+ CameraHal::getXYFromOffset(&x, &y, frame->mOffset, frame->mAlignment, mPixelFormat);
+ CAMHAL_LOGVB("offset = %u left = %d top = %d right = %d bottom = %d",
+ frame->mOffset, x, y, x + frame->mWidth, y + frame->mHeight);
+ ret = mBufferSource->set_crop(mBufferSource, x, y, x + frame->mWidth, y + frame->mHeight);
+ if (NO_ERROR != ret) {
+ CAMHAL_LOGE("mBufferSource->set_crop returned error %d", ret);
+ goto fail;
+ }
+
+ if ( NULL != frame->mMetaData.get() ) {
+ camera_memory_t *extMeta = frame->mMetaData->getExtendedMetadata();
+ if ( NULL != extMeta ) {
+ camera_metadata_t *metaData = static_cast<camera_metadata_t *> (extMeta->data);
+ metaData->timestamp = frame->mTimestamp;
+ ret = extendedOps()->set_metadata(mBufferSource, extMeta);
+ if (ret != 0) {
+ CAMHAL_LOGE("Surface::set_metadata returned error %d", ret);
+ goto fail;
+ }
+ }
+ }
+
+ // unlock buffer before enqueueing
+ mapper.unlock(*handle);
+
+ ret = mBufferSource->enqueue_buffer(mBufferSource, handle);
+ if (ret != 0) {
+ CAMHAL_LOGE("Surface::queueBuffer returned error %d", ret);
+ goto fail;
+ }
+
+ mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) frame->mBuffer->opaque);
+
+ return;
+
+fail:
+ mFramesWithCameraAdapterMap.clear();
+ mBufferSource = NULL;
+ mReturnFrame->requestExit();
+ mQueueFrame->requestExit();
+}
+
+
+bool BufferSourceAdapter::handleFrameReturn()
+{
+ status_t err;
+ buffer_handle_t *buf;
+ int i = 0;
+ int stride; // dummy variable to get stride
+ CameraFrame::FrameType type;
+ android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
+ void *y_uv[2];
+ android::Rect bounds(mFrameWidth, mFrameHeight);
+
+ android::AutoMutex lock(mLock);
+
+ if ( (NULL == mBufferSource) || (NULL == mBuffers) ) {
+ return false;
+ }
+
+ err = mBufferSource->dequeue_buffer(mBufferSource, &buf, &stride);
+ if (err != 0) {
+ CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
+
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+
+ return false;
+ }
+
+ err = mBufferSource->lock_buffer(mBufferSource, buf);
+ if (err != 0) {
+ CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err);
+
+ if ( ENODEV == err ) {
+ CAMHAL_LOGEA("Preview surface abandoned!");
+ mBufferSource = NULL;
+ }
+
+ return false;
+ }
+
+ mapper.lock(*buf, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
+
+ for(i = 0; i < mBufferCount; i++) {
+ if (mBuffers[i].opaque == buf)
+ break;
+ }
+
+ if (i >= mBufferCount) {
+ CAMHAL_LOGEB("Failed to find handle %p", buf);
+ }
+
+ mFramesWithCameraAdapterMap.add((buffer_handle_t *) mBuffers[i].opaque, i);
+
+ CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount - 1);
+
+ mFrameProvider->returnFrame(&mBuffers[i], formatToOutputFrameType(mPixelFormat));
+ return true;
+}
+
+void BufferSourceAdapter::frameCallback(CameraFrame* caFrame)
+{
+ if ((NULL != caFrame) && (NULL != caFrame->mCookie)) {
+ BufferSourceAdapter *da = (BufferSourceAdapter*) caFrame->mCookie;
+ da->addFrame(caFrame);
+ } else {
+ CAMHAL_LOGEB("Invalid Cookie in Camera Frame = %p, Cookie = %p",
+ caFrame, caFrame ? caFrame->mCookie : NULL);
+ }
+}
+
+/*--------------------BufferSourceAdapter Class ENDS here-----------------------------*/
+
+} // namespace Camera
+} // namespace Ti
+
+#endif