/* * 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: // 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; 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); 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); 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