diff options
Diffstat (limited to 'camera/ANativeWindowDisplayAdapter.cpp')
-rw-r--r-- | camera/ANativeWindowDisplayAdapter.cpp | 1269 |
1 files changed, 1269 insertions, 0 deletions
diff --git a/camera/ANativeWindowDisplayAdapter.cpp b/camera/ANativeWindowDisplayAdapter.cpp new file mode 100644 index 0000000..e4a70ae --- /dev/null +++ b/camera/ANativeWindowDisplayAdapter.cpp @@ -0,0 +1,1269 @@ +/* + * 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. + */ + + + + +#define LOG_TAG "CameraHAL" + +#include "ANativeWindowDisplayAdapter.h" +#include <OMX_IVCommon.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicBufferMapper.h> +#include <hal_public.h> + +namespace android { + +///Constant declarations +///@todo Check the time units +const int ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT = 1000; // seconds + +//Suspends buffers after given amount of failed dq's +const int ANativeWindowDisplayAdapter::FAILED_DQS_TO_SUSPEND = 3; + + +OMX_COLOR_FORMATTYPE toOMXPixFormat(const char* parameters_format) +{ + OMX_COLOR_FORMATTYPE pixFormat; + + if ( parameters_format != NULL ) + { + if (strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else + { + CAMHAL_LOGDA("Invalid format, CbYCrY format selected as default"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + } + else { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + return pixFormat; +} + +const char* getPixFormatConstant(const char* parameters_format) +{ + const char* pixFormat; + + if ( parameters_format != NULL ) + { + if (strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGVA("CbYCrY format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420P) == 0) + { + // TODO(XXX): We are treating YV12 the same as YUV420SP + CAMHAL_LOGVA("YUV420SP format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGVA("RGB565 format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_RGB565; + } + else + { + CAMHAL_LOGEA("Invalid format, CbYCrY format selected as default"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + } + else + { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + + return pixFormat; +} + +const size_t getBufSize(const char* parameters_format, int width, int height) +{ + int buf_size; + + if ( parameters_format != NULL ) { + if (strcmp(parameters_format, + (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + buf_size = width * height * 2; + } + else if((strcmp(parameters_format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) || + (strcmp(parameters_format, CameraParameters::PIXEL_FORMAT_YUV420P) == 0)) { + buf_size = width * height * 3 / 2; + } + else if(strcmp(parameters_format, + (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + buf_size = width * height * 2; + } else { + CAMHAL_LOGEA("Invalid format"); + buf_size = 0; + } + } else { + CAMHAL_LOGEA("Preview format is NULL"); + buf_size = 0; + } + + return buf_size; +} +/*--------------------ANativeWindowDisplayAdapter Class STARTS here-----------------------------*/ + + +/** + * Display Adapter class STARTS here.. + */ +ANativeWindowDisplayAdapter::ANativeWindowDisplayAdapter():mDisplayThread(NULL), + mDisplayState(ANativeWindowDisplayAdapter::DISPLAY_INIT), + mDisplayEnabled(false), + mBufferCount(0) + + + +{ + LOG_FUNCTION_NAME; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + mShotToShot = false; + mStartCapture.tv_sec = 0; + mStartCapture.tv_usec = 0; + mStandbyToShot.tv_sec = 0; + mStandbyToShot.tv_usec = 0; + mMeasureStandby = false; +#endif + + mPixelFormat = NULL; + mBufferHandleMap = NULL; + mGrallocHandleMap = NULL; + mOffsetsMap = NULL; + mFrameProvider = NULL; + mANativeWindow = NULL; + + mFrameWidth = 0; + mFrameHeight = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + + mSuspend = false; + mFailedDQs = 0; + + mPaused = false; + mXOff = -1; + mYOff = -1; + mFirstInit = false; + + mFD = -1; + + LOG_FUNCTION_NAME_EXIT; +} + +ANativeWindowDisplayAdapter::~ANativeWindowDisplayAdapter() +{ + Semaphore sem; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + ///If Frame provider exists + if (mFrameProvider) { + // Unregister with the frame provider + mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + delete mFrameProvider; + mFrameProvider = NULL; + } + + ///The ANativeWindow object will get destroyed here + destroy(); + + ///If Display thread exists + if(mDisplayThread.get()) + { + ///Kill the display thread + sem.Create(); + msg.command = DisplayThread::DISPLAY_EXIT; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK - implies that the thread is now started and waiting for frames + sem.Wait(); + + // Exit and cleanup the thread + mDisplayThread->requestExitAndWait(); + + // Delete the display thread + mDisplayThread.clear(); + } + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t ANativeWindowDisplayAdapter::initialize() +{ + LOG_FUNCTION_NAME; + + ///Create the display thread + mDisplayThread = new DisplayThread(this); + if ( !mDisplayThread.get() ) + { + CAMHAL_LOGEA("Couldn't create display thread"); + LOG_FUNCTION_NAME_EXIT; + return NO_MEMORY; + } + + ///Start the display thread + status_t ret = mDisplayThread->run("DisplayThread", PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEA("Couldn't run display thread"); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int ANativeWindowDisplayAdapter::setPreviewWindow(preview_stream_ops_t* window) +{ + LOG_FUNCTION_NAME; + ///Note that Display Adapter cannot work without a valid window object + if ( !window) + { + CAMHAL_LOGEA("NULL window object passed to DisplayAdapter"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + if ( window == mANativeWindow ) { + return ALREADY_EXISTS; + } + + ///Destroy the existing window object, if it exists + destroy(); + + ///Move to new window obj + mANativeWindow = window; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider) +{ + LOG_FUNCTION_NAME; + + // Check for NULL pointer + if ( !frameProvider ) { + CAMHAL_LOGEA("NULL passed for frame provider"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + //Release any previous frame providers + if ( NULL != mFrameProvider ) { + delete mFrameProvider; + } + + /** Dont do anything here, Just save the pointer for use when display is + actually enabled or disabled + */ + mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::setErrorHandler(ErrorNotifier *errorNotifier) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == errorNotifier ) + { + CAMHAL_LOGEA("Invalid Error Notifier reference"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + mErrorNotifier = errorNotifier; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +status_t ANativeWindowDisplayAdapter::setSnapshotTimeRef(struct timeval *refTime) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL != refTime ) + { + Mutex::Autolock lock(mLock); + memcpy(&mStartCapture, refTime, sizeof(struct timeval)); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +#endif + + +int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams) +{ + Semaphore sem; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + if ( mDisplayEnabled ) + { + CAMHAL_LOGDA("Display is already enabled"); + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + } + +#if 0 //TODO: s3d is not part of bringup...will reenable + if (s3dParams) + mOverlay->set_s3d_params(s3dParams->mode, s3dParams->framePacking, + s3dParams->order, s3dParams->subSampling); +#endif + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( NULL != refTime ) + { + Mutex::Autolock lock(mLock); + memcpy(&mStandbyToShot, refTime, sizeof(struct timeval)); + mMeasureStandby = true; + } + +#endif + + //Send START_DISPLAY COMMAND to display thread. Display thread will start and then wait for a message + sem.Create(); + msg.command = DisplayThread::DISPLAY_START; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK - implies that the thread is now started and waiting for frames + sem.Wait(); + + // Register with the frame provider for frames + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + + mDisplayEnabled = true; + mPreviewWidth = width; + mPreviewHeight = height; + + CAMHAL_LOGVB("mPreviewWidth = %d mPreviewHeight = %d", mPreviewWidth, mPreviewHeight); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::disableDisplay(bool cancel_buffer) +{ + status_t ret = NO_ERROR; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + + LOG_FUNCTION_NAME; + + if(!mDisplayEnabled) + { + CAMHAL_LOGDA("Display is already disabled"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + // Unregister with the frame provider here + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + mFrameProvider->removeFramePointers(); + + if ( NULL != mDisplayThread.get() ) + { + //Send STOP_DISPLAY COMMAND to display thread. Display thread will stop and dequeue all messages + // and then wait for message + Semaphore sem; + sem.Create(); + TIUTILS::Message msg; + msg.command = DisplayThread::DISPLAY_STOP; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK for display to be disabled + + sem.Wait(); + + } + + Mutex::Autolock lock(mLock); + { + ///Reset the display enabled flag + mDisplayEnabled = false; + + ///Reset the offset values + mXOff = -1; + mYOff = -1; + + ///Reset the frame width and height values + mFrameWidth =0; + mFrameHeight = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + + if(cancel_buffer) + { + // Return the buffers to ANativeWindow here, the mFramesWithCameraAdapterMap is also cleared inside + returnBuffersToWindow(); + } + else + { + mANativeWindow = NULL; + // Clear the frames with camera adapter map + mFramesWithCameraAdapterMap.clear(); + } + + + } + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + { + Mutex::Autolock lock(mLock); + mPaused = pause; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +void ANativeWindowDisplayAdapter::destroy() +{ + LOG_FUNCTION_NAME; + + ///Check if the display is disabled, if not disable it + if ( mDisplayEnabled ) + { + CAMHAL_LOGDA("WARNING: Calling destroy of Display adapter when display enabled. Disabling display.."); + disableDisplay(false); + } + + mBufferCount = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +// Implementation of inherited interfaces +void* ANativeWindowDisplayAdapter::allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs) +{ + LOG_FUNCTION_NAME; + status_t err; + int i = -1; + const int lnumBufs = numBufs; + mBufferHandleMap = new buffer_handle_t*[lnumBufs]; + mGrallocHandleMap = new IMG_native_handle_t*[lnumBufs]; + int undequeued = 0; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + Rect bounds; + + + if ( NULL == mANativeWindow ) { + return NULL; + } + + // Set gralloc usage bits for window. + err = mANativeWindow->set_usage(mANativeWindow, CAMHAL_GRALLOC_USAGE); + if (err != 0) { + ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return NULL; + } + + CAMHAL_LOGDB("Number of buffers set to ANativeWindow %d", numBufs); + ///Set the number of buffers needed for camera preview + err = mANativeWindow->set_buffer_count(mANativeWindow, numBufs); + if (err != 0) { + ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return NULL; + } + CAMHAL_LOGDB("Configuring %d buffers for ANativeWindow", numBufs); + mBufferCount = numBufs; + + + // Set window geometry + err = mANativeWindow->set_buffers_geometry( + mANativeWindow, + width, + height, + /*toOMXPixFormat(format)*/HAL_PIXEL_FORMAT_TI_NV12); // Gralloc only supports NV12 alloc! + + if (err != 0) { + ALOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return NULL; + } + + ///We just return the buffers from ANativeWindow, if the width and height are same, else (vstab, vnf case) + ///re-allocate buffers using ANativeWindow and then get them + ///@todo - Re-allocate buffers for vnf and vstab using the width, height, format, numBufs etc + if ( mBufferHandleMap == NULL ) + { + CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers"); + LOG_FUNCTION_NAME_EXIT; + return NULL; + } + + mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued); + + for ( i=0; i < mBufferCount; i++ ) + { + IMG_native_handle_t** hndl2hndl; + IMG_native_handle_t* handle; + int stride; // dummy variable to get stride + // TODO(XXX): Do we need to keep stride information in camera hal? + + err = mANativeWindow->dequeue_buffer(mANativeWindow, (buffer_handle_t**) &hndl2hndl, &stride); + + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + goto fail; + } + + handle = *hndl2hndl; + + mBufferHandleMap[i] = (buffer_handle_t*) hndl2hndl; + mGrallocHandleMap[i] = handle; + mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i); + + bytes = getBufSize(format, width, height); + + } + + // lock the initial queueable buffers + bounds.left = 0; + bounds.top = 0; + bounds.right = width; + bounds.bottom = height; + + for( i = 0; i < mBufferCount-undequeued; i++ ) + { + void *y_uv[2]; + + mANativeWindow->lock_buffer(mANativeWindow, mBufferHandleMap[i]); + + mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mFrameProvider->addFramePointers(mGrallocHandleMap[i] , y_uv); + } + + // return the rest of the buffers back to ANativeWindow + for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++) + { + err = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]); + if (err != 0) { + CAMHAL_LOGEB("cancel_buffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + goto fail; + } + mFramesWithCameraAdapterMap.removeItem((int) mGrallocHandleMap[i]); + //LOCK UNLOCK TO GET YUV POINTERS + void *y_uv[2]; + mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mFrameProvider->addFramePointers(mGrallocHandleMap[i] , y_uv); + mapper.unlock((buffer_handle_t) mGrallocHandleMap[i]); + } + + mFirstInit = true; + mPixelFormat = getPixFormatConstant(format); + mFrameWidth = width; + mFrameHeight = height; + + return mGrallocHandleMap; + + fail: + // need to cancel buffers if any were dequeued + for (int start = 0; start < i && i > 0; start++) { + int err = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[start]); + if (err != 0) { + CAMHAL_LOGEB("cancelBuffer failed w/ error 0x%08x", err); + break; + } + mFramesWithCameraAdapterMap.removeItem((int) mGrallocHandleMap[start]); + } + + freeBuffer(mGrallocHandleMap); + + CAMHAL_LOGEA("Error occurred, performing cleanup"); + + if ( NULL != mErrorNotifier.get() ) + { + mErrorNotifier->errorNotify(-ENOMEM); + } + + LOG_FUNCTION_NAME_EXIT; + return NULL; + +} + +uint32_t * ANativeWindowDisplayAdapter::getOffsets() +{ + const int lnumBufs = mBufferCount; + + LOG_FUNCTION_NAME; + + // TODO(XXX): Need to remove getOffsets from the API. No longer needed + + if ( NULL == mANativeWindow ) + { + CAMHAL_LOGEA("mANativeWindow reference is missing"); + goto fail; + } + + if( mBufferHandleMap == NULL) + { + CAMHAL_LOGEA("Buffers not allocated yet!!"); + goto fail; + } + + if(mOffsetsMap == NULL) + { + mOffsetsMap = new uint32_t[lnumBufs]; + for(int i = 0; i < mBufferCount; i++) + { + IMG_native_handle_t* handle = (IMG_native_handle_t*) *(mBufferHandleMap[i]); + mOffsetsMap[i] = 0; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return mOffsetsMap; + + fail: + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if ( NULL != mErrorNotifier.get() ) + { + mErrorNotifier->errorNotify(-ENOSYS); + } + + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +int ANativeWindowDisplayAdapter::maxQueueableBuffers(unsigned int& queueable) +{ + LOG_FUNCTION_NAME; + int ret = NO_ERROR; + int undequeued = 0; + + if(mBufferCount == 0) + { + ret = -ENOSYS; + goto end; + } + + if(!mANativeWindow) + { + ret = -ENOSYS; + goto end; + } + + ret = mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued); + 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!"); + mANativeWindow = NULL; + } + + return -ret; + } + + queueable = mBufferCount - undequeued; + + end: + return ret; + LOG_FUNCTION_NAME_EXIT; +} + +int ANativeWindowDisplayAdapter::getFd() +{ + LOG_FUNCTION_NAME; + + if(mFD == -1) + { + IMG_native_handle_t* handle = (IMG_native_handle_t*) *(mBufferHandleMap[0]); + // TODO: should we dup the fd? not really necessary and another thing for ANativeWindow + // to manage and close... + mFD = dup(handle->fd[0]); + } + + LOG_FUNCTION_NAME_EXIT; + + return mFD; + +} + +status_t ANativeWindowDisplayAdapter::returnBuffersToWindow() +{ + status_t ret = NO_ERROR; + + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + //Give the buffers back to display here - sort of free it + if (mANativeWindow) + for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) { + int value = mFramesWithCameraAdapterMap.valueAt(i); + + // unlock buffer before giving it up + mapper.unlock((buffer_handle_t) mGrallocHandleMap[value]); + + ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[value]); + if ( ENODEV == ret ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + return -ret; + } else if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("cancel_buffer() failed: %s (%d)", + strerror(-ret), + -ret); + return -ret; + } + } + else + ALOGE("mANativeWindow is NULL"); + + ///Clear the frames with camera adapter map + mFramesWithCameraAdapterMap.clear(); + + return ret; + +} + +int ANativeWindowDisplayAdapter::freeBuffer(void* buf) +{ + LOG_FUNCTION_NAME; + + int *buffers = (int *) buf; + status_t ret = NO_ERROR; + + Mutex::Autolock lock(mLock); + + if((int *)mGrallocHandleMap != buffers) + { + CAMHAL_LOGEA("CameraHal passed wrong set of buffers to free!!!"); + if (mGrallocHandleMap != NULL) + delete []mGrallocHandleMap; + mGrallocHandleMap = NULL; + } + + + returnBuffersToWindow(); + + if ( NULL != buf ) + { + delete [] buffers; + mGrallocHandleMap = NULL; + } + + if( mBufferHandleMap != NULL) + { + delete [] mBufferHandleMap; + mBufferHandleMap = NULL; + } + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if( mFD != -1) + { + close(mFD); // close duped handle + mFD = -1; + } + + return NO_ERROR; +} + + +bool ANativeWindowDisplayAdapter::supportsExternalBuffering() +{ + return false; +} + +int ANativeWindowDisplayAdapter::useBuffers(void *bufArr, int num) +{ + return NO_ERROR; +} + +void ANativeWindowDisplayAdapter::displayThread() +{ + bool shouldLive = true; + int timeout = 0; + status_t ret; + + LOG_FUNCTION_NAME; + + while(shouldLive) + { + ret = TIUTILS::MessageQueue::waitForMsg(&mDisplayThread->msgQ() + , &mDisplayQ + , NULL + , ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT); + + if ( !mDisplayThread->msgQ().isEmpty() ) + { + ///Received a message from CameraHal, process it + shouldLive = processHalMsg(); + + } + else if( !mDisplayQ.isEmpty()) + { + if ( mDisplayState== ANativeWindowDisplayAdapter::DISPLAY_INIT ) + { + + ///If display adapter is not started, continue + continue; + + } + else + { + TIUTILS::Message msg; + ///Get the dummy msg from the displayQ + if(mDisplayQ.get(&msg)!=NO_ERROR) + { + CAMHAL_LOGEA("Error in getting message from display Q"); + continue; + } + + // There is a frame from ANativeWindow for us to dequeue + // We dequeue and return the frame back to Camera adapter + if(mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED) + { + handleFrameReturn(); + } + + if (mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_EXITED) + { + ///we exit the thread even though there are frames still to dequeue. They will be dequeued + ///in disableDisplay + shouldLive = false; + } + } + } + } + + LOG_FUNCTION_NAME_EXIT; +} + + +bool ANativeWindowDisplayAdapter::processHalMsg() +{ + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + + mDisplayThread->msgQ().get(&msg); + bool ret = true, invalidCommand = false; + + switch ( msg.command ) + { + + case DisplayThread::DISPLAY_START: + + CAMHAL_LOGDA("Display thread received DISPLAY_START command from Camera HAL"); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STARTED; + + break; + + case DisplayThread::DISPLAY_STOP: + + ///@bug There is no API to disable SF without destroying it + ///@bug Buffers might still be w/ display and will get displayed + ///@remarks Ideal seqyence should be something like this + ///mOverlay->setParameter("enabled", false); + CAMHAL_LOGDA("Display thread received DISPLAY_STOP command from Camera HAL"); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STOPPED; + + break; + + case DisplayThread::DISPLAY_EXIT: + + CAMHAL_LOGDA("Display thread received DISPLAY_EXIT command from Camera HAL."); + CAMHAL_LOGDA("Stopping display thread..."); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_EXITED; + ///Note that the SF can have pending buffers when we disable the display + ///This is normal and the expectation is that they may not be displayed. + ///This is to ensure that the user experience is not impacted + ret = false; + break; + + default: + + CAMHAL_LOGEB("Invalid Display Thread Command 0x%x.", msg.command); + invalidCommand = true; + + break; + } + + ///Signal the semaphore if it is sent as part of the message + if ( ( msg.arg1 ) && ( !invalidCommand ) ) + { + + CAMHAL_LOGDA("+Signalling display semaphore"); + Semaphore &sem = *((Semaphore*)msg.arg1); + + sem.Signal(); + + CAMHAL_LOGDA("-Signalling display semaphore"); + } + + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +status_t ANativeWindowDisplayAdapter::PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame) +{ + status_t ret = NO_ERROR; + uint32_t actualFramesWithDisplay = 0; + android_native_buffer_t *buffer = NULL; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + int i; + + ///@todo Do cropping based on the stabilized frame coordinates + ///@todo Insert logic to drop frames here based on refresh rate of + ///display or rendering rate whichever is lower + ///Queue the buffer to overlay + + if (!mGrallocHandleMap || !dispFrame.mBuffer) { + CAMHAL_LOGEA("NULL sent to PostFrame"); + return -EINVAL; + } + + for ( i = 0; i < mBufferCount; i++ ) + { + if ( ((int) dispFrame.mBuffer ) == (int)mGrallocHandleMap[i] ) + { + break; + } + } + + if ( mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED && + (!mPaused || CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) && + !mSuspend) + { + Mutex::Autolock lock(mLock); + uint32_t xOff = (dispFrame.mOffset% PAGE_SIZE); + uint32_t yOff = (dispFrame.mOffset / PAGE_SIZE); + + // Set crop only if current x and y offsets do not match with frame offsets + if((mXOff!=xOff) || (mYOff!=yOff)) + { + CAMHAL_LOGDB("Offset %d xOff = %d, yOff = %d", dispFrame.mOffset, xOff, yOff); + uint8_t bytesPerPixel; + ///Calculate bytes per pixel based on the pixel format + if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + bytesPerPixel = 2; + } + else if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + bytesPerPixel = 2; + } + else if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + bytesPerPixel = 1; + } + else + { + bytesPerPixel = 1; + } + + CAMHAL_LOGVB(" crop.left = %d crop.top = %d crop.right = %d crop.bottom = %d", + xOff/bytesPerPixel, yOff , (xOff/bytesPerPixel)+mPreviewWidth, yOff+mPreviewHeight); + // We'll ignore any errors here, if the surface is + // already invalid, we'll know soon enough. + mANativeWindow->set_crop(mANativeWindow, xOff/bytesPerPixel, yOff, + (xOff/bytesPerPixel)+mPreviewWidth, yOff+mPreviewHeight); + + ///Update the current x and y offsets + mXOff = xOff; + mYOff = yOff; + } + + // unlock buffer before sending to display + mapper.unlock((buffer_handle_t) mGrallocHandleMap[i]); + ret = mANativeWindow->enqueue_buffer(mANativeWindow, mBufferHandleMap[i]); + if (ret != 0) { + ALOGE("Surface::queueBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer); + + + // HWComposer has not minimum buffer requirement. We should be able to dequeue + // the buffer immediately + TIUTILS::Message msg; + mDisplayQ.put(&msg); + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( mMeasureStandby ) + { + CameraHal::PPM("Standby to first shot: Sensor Change completed - ", &mStandbyToShot); + mMeasureStandby = false; + } + else if (CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) + { + CameraHal::PPM("Shot to snapshot: ", &mStartCapture); + mShotToShot = true; + } + else if ( mShotToShot ) + { + CameraHal::PPM("Shot to shot: ", &mStartCapture); + mShotToShot = false; + } +#endif + + } + else + { + Mutex::Autolock lock(mLock); + + // unlock buffer before giving it up + mapper.unlock((buffer_handle_t) mGrallocHandleMap[i]); + + // cancel buffer and dequeue another one + ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]); + if (ret != 0) { + ALOGE("Surface::queueBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer); + + TIUTILS::Message msg; + mDisplayQ.put(&msg); + ret = NO_ERROR; + } + + return ret; +} + + +bool ANativeWindowDisplayAdapter::handleFrameReturn() +{ + status_t err; + buffer_handle_t* buf; + int i = 0; + int stride; // dummy variable to get stride + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + Rect bounds; + void *y_uv[2]; + + // TODO(XXX): Do we need to keep stride information in camera hal? + + if ( NULL == mANativeWindow ) { + return false; + } + + err = mANativeWindow->dequeue_buffer(mANativeWindow, &buf, &stride); + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return false; + } + + err = mANativeWindow->lock_buffer(mANativeWindow, buf); + if (err != 0) { + CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return false; + } + + for(i = 0; i < mBufferCount; i++) + { + if (mBufferHandleMap[i] == buf) + break; + } + + // lock buffer before sending to FrameProvider for filling + bounds.left = 0; + bounds.top = 0; + bounds.right = mFrameWidth; + bounds.bottom = mFrameHeight; + + int lock_try_count = 0; + while (mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv) < 0){ + if (++lock_try_count > LOCK_BUFFER_TRIES){ + if ( NULL != mErrorNotifier.get() ){ + mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN); + } + return false; + } + CAMHAL_LOGEA("Gralloc Lock FrameReturn Error: Sleeping 15ms"); + usleep(15000); + } + + mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i); + + CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount-1); + mFrameProvider->returnFrame( (void*)mGrallocHandleMap[i], CameraFrame::PREVIEW_FRAME_SYNC); + return true; +} + +void ANativeWindowDisplayAdapter::frameCallbackRelay(CameraFrame* caFrame) +{ + + if ( NULL != caFrame ) + { + if ( NULL != caFrame->mCookie ) + { + ANativeWindowDisplayAdapter *da = (ANativeWindowDisplayAdapter*) caFrame->mCookie; + da->frameCallback(caFrame); + } + else + { + CAMHAL_LOGEB("Invalid Cookie in Camera Frame = %p, Cookie = %p", caFrame, caFrame->mCookie); + } + } + else + { + CAMHAL_LOGEB("Invalid Camera Frame = %p", caFrame); + } + +} + +void ANativeWindowDisplayAdapter::frameCallback(CameraFrame* caFrame) +{ + ///Call queueBuffer of overlay in the context of the callback thread + DisplayFrame df; + df.mBuffer = caFrame->mBuffer; + df.mType = (CameraFrame::FrameType) caFrame->mFrameType; + df.mOffset = caFrame->mOffset; + df.mWidthStride = caFrame->mAlignment; + df.mLength = caFrame->mLength; + df.mWidth = caFrame->mWidth; + df.mHeight = caFrame->mHeight; + PostFrame(df); +} + + +/*--------------------ANativeWindowDisplayAdapter Class ENDS here-----------------------------*/ + +}; + |