diff options
Diffstat (limited to 'camera/ANativeWindowDisplayAdapter.cpp')
-rw-r--r-- | camera/ANativeWindowDisplayAdapter.cpp | 1263 |
1 files changed, 1263 insertions, 0 deletions
diff --git a/camera/ANativeWindowDisplayAdapter.cpp b/camera/ANativeWindowDisplayAdapter.cpp new file mode 100644 index 0000000..396e6d4 --- /dev/null +++ b/camera/ANativeWindowDisplayAdapter.cpp @@ -0,0 +1,1263 @@ +/* + * 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. + */ + +#include "ANativeWindowDisplayAdapter.h" +#include <OMX_IVCommon.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicBufferMapper.h> +#include <hal_public.h> + +namespace Ti { +namespace Camera { + +///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, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + else if(strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else + { + CAMHAL_LOGDA("Invalid format, NV12 format selected as default"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + } + else { + CAMHAL_LOGEA("Preview format is NULL, defaulting to NV12"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + + return pixFormat; +} + +/*--------------------ANativeWindowDisplayAdapter Class STARTS here-----------------------------*/ + + +/** + * Display Adapter class STARTS here.. + */ +ANativeWindowDisplayAdapter::ANativeWindowDisplayAdapter():mDisplayThread(NULL), + mDisplayState(ANativeWindowDisplayAdapter::DISPLAY_INIT), + mDisplayEnabled(false), + mBufferCount(0), + mUseExternalBufferLocking(false) + + + +{ + 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; + mBuffers = 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() +{ + Utils::Semaphore sem; + Utils::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", android::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 = BAD_VALUE; + } + + 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 ) + { + android::AutoMutex 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) +{ + Utils::Semaphore sem; + Utils::Message msg; + + LOG_FUNCTION_NAME; + + if ( mDisplayEnabled ) + { + CAMHAL_LOGDA("Display is already enabled"); + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( NULL != refTime ) + { + android::AutoMutex 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); + mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + + 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; + android::GraphicBufferMapper &mapper = android::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->disableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + 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 + Utils::Semaphore sem; + sem.Create(); + Utils::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(); + + } + + android::AutoMutex lock(mLock); + { + ///Reset the display enabled flag + mDisplayEnabled = false; + + // Reset pause flag since display is being disabled + mPaused = 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; + + { + android::AutoMutex 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 +CameraBuffer* ANativeWindowDisplayAdapter::allocateBufferList(int width, int height, 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(); + android::Rect bounds; + + mBuffers = new CameraBuffer [lnumBufs]; + memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs); + + mFramesType.clear(); + + if ( NULL == mANativeWindow ) { + return NULL; + } + + // Set gralloc usage bits for window. + err = mANativeWindow->set_usage(mANativeWindow, CAMHAL_GRALLOC_USAGE); + if ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::setUsage failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == 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 ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::setBufferCount failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == 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 ( NO_ERROR != err ) { + CAMHAL_LOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == 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 ( mBuffers == NULL ) + { + CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers"); + LOG_FUNCTION_NAME_EXIT; + return NULL; + } + + mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued); + mPixelFormat = CameraHal::getPixelFormatConstant(format); + + 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 = mANativeWindow->dequeue_buffer(mANativeWindow, &handle, &stride); + + if ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::dequeueBuffer failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = 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); + + // Tag remaining preview buffers as preview frames + if ( i >= ( mBufferCount - undequeued ) ) { + mFramesType.add( (int) mBuffers[i].opaque, + CameraFrame::PREVIEW_FRAME_SYNC); + } + + bytes = CameraHal::calculateBufferSize(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]; + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque; + + mANativeWindow->lock_buffer(mANativeWindow, handle); + + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mBuffers[i].mapped = y_uv[0]; + mFrameProvider->addFramePointers(&mBuffers[i], y_uv); + if (mUseExternalBufferLocking) { + mapper.unlock(*handle); + } + } + + // 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; + err = mANativeWindow->cancel_buffer(mANativeWindow, handle); + if ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::cancelBuffer failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + goto fail; + } + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[i].opaque); + //LOCK UNLOCK TO GET YUV POINTERS + void *y_uv[2]; + mapper.lock(*(buffer_handle_t *) mBuffers[i].opaque, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mBuffers[i].mapped = y_uv[0]; + mFrameProvider->addFramePointers(&mBuffers[i], y_uv); + mapper.unlock(*(buffer_handle_t *) mBuffers[i].opaque); + } + + mFirstInit = true; + mFrameWidth = width; + mFrameHeight = height; + + return mBuffers; + + fail: + // need to cancel buffers if any were dequeued + for (int start = 0; start < i && i > 0; start++) { + status_t err = mANativeWindow->cancel_buffer(mANativeWindow, + (buffer_handle_t *) mBuffers[start].opaque); + if ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::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(NO_MEMORY); + } + + LOG_FUNCTION_NAME_EXIT; + return NULL; + +} + +CameraBuffer* ANativeWindowDisplayAdapter::getBufferList(int *numBufs) { + LOG_FUNCTION_NAME; + if (numBufs) *numBufs = -1; + + 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( mBuffers == NULL) + { + CAMHAL_LOGEA("Buffers not allocated yet!!"); + goto fail; + } + + if(mOffsetsMap == NULL) + { + mOffsetsMap = new uint32_t[lnumBufs]; + for(int i = 0; i < mBufferCount; i++) + { + mOffsetsMap[i] = 0; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return mOffsetsMap; + + fail: + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if ( NULL != mErrorNotifier.get() ) { + mErrorNotifier->errorNotify(INVALID_OPERATION); + } + + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +status_t ANativeWindowDisplayAdapter::minUndequeueableBuffers(int& undequeueable) { + LOG_FUNCTION_NAME; + status_t ret = NO_ERROR; + + if(!mANativeWindow) { + ret = INVALID_OPERATION; + goto end; + } + + ret = mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeueable); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("get_min_undequeued_buffer_count failed: %s (%d)", strerror(-ret), -ret); + + if ( NO_INIT == ret ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return ret; + } + + end: + return ret; + LOG_FUNCTION_NAME_EXIT; + +} + +status_t ANativeWindowDisplayAdapter::maxQueueableBuffers(unsigned int& queueable) +{ + LOG_FUNCTION_NAME; + status_t 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 ANativeWindowDisplayAdapter::getFd() +{ + LOG_FUNCTION_NAME; + + if(mFD == -1) + { + buffer_handle_t *handle = (buffer_handle_t *)mBuffers[0].opaque; + IMG_native_handle_t *img = (IMG_native_handle_t *)handle; + // TODO: should we dup the fd? not really necessary and another thing for ANativeWindow + // to manage and close... + + mFD = dup(img->fd[0]); + } + + LOG_FUNCTION_NAME_EXIT; + + return mFD; + +} + +status_t ANativeWindowDisplayAdapter::returnBuffersToWindow() +{ + status_t ret = NO_ERROR; + + android::GraphicBufferMapper &mapper = android::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); + 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; + } + + if (!mUseExternalBufferLocking) { + // unlock buffer before giving it up + mapper.unlock(*handle); + } + + ret = mANativeWindow->cancel_buffer(mANativeWindow, handle); + if ( NO_INIT == ret ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + return ret; + } else if ( NO_ERROR != ret ) { + CAMHAL_LOGE("Surface::cancelBuffer() failed: %s (%d)", + strerror(-ret), + -ret); + return ret; + } + } + else + CAMHAL_LOGE("mANativeWindow is NULL"); + + ///Clear the frames with camera adapter map + mFramesWithCameraAdapterMap.clear(); + + return ret; + +} + +int ANativeWindowDisplayAdapter::freeBufferList(CameraBuffer * buflist) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + + android::AutoMutex lock(mLock); + + if(mBuffers != buflist) + { + CAMHAL_LOGEA("CameraHal passed wrong set of buffers to free!!!"); + if (mBuffers != NULL) + delete []mBuffers; + mBuffers = NULL; + } + + /* FIXME this will probably want the list that was just deleted */ + returnBuffersToWindow(); + + if ( NULL != buflist ) + { + delete [] buflist; + mBuffers = NULL; + } + + if( mBuffers != NULL) + { + delete [] mBuffers; + mBuffers = NULL; + } + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if( mFD != -1) + { + close(mFD); // close duped handle + mFD = -1; + } + + mFramesType.clear(); + + return NO_ERROR; +} + + +bool ANativeWindowDisplayAdapter::supportsExternalBuffering() +{ + return false; +} + +void ANativeWindowDisplayAdapter::displayThread() +{ + bool shouldLive = true; + int timeout = 0; + status_t ret; + + LOG_FUNCTION_NAME; + + while(shouldLive) + { + ret = Utils::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 + { + Utils::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() +{ + Utils::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; + + // flush frame message queue + while ( !mDisplayQ.isEmpty() ) { + Utils::Message message; + mDisplayQ.get(&message); + } + + 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"); + Utils::Semaphore &sem = *((Utils::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; + android::GraphicBufferMapper &mapper = android::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 ( NULL == mANativeWindow ) { + return NO_INIT; + } + + if (!mBuffers || !dispFrame.mBuffer) { + CAMHAL_LOGEA("NULL sent to PostFrame"); + return BAD_VALUE; + } + + for ( i = 0; i < mBufferCount; i++ ) + { + if ( dispFrame.mBuffer == &mBuffers[i] ) + { + break; + } + } + +#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 + + android::AutoMutex lock(mLock); + + mFramesType.add( (int)mBuffers[i].opaque, dispFrame.mType); + + if ( mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED && + (!mPaused || CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) && + !mSuspend) + { + uint32_t xOff, yOff; + + CameraHal::getXYFromOffset(&xOff, &yOff, dispFrame.mOffset, PAGE_SIZE, mPixelFormat); + + // Set crop only if current x and y offsets do not match with frame offsets + if ((mXOff != xOff) || (mYOff != yOff)) { + CAMHAL_LOGDB("offset = %u left = %d top = %d right = %d bottom = %d", + dispFrame.mOffset, xOff, yOff , + xOff + 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, yOff, + xOff + mPreviewWidth, yOff + mPreviewHeight); + + // Update the current x and y offsets + mXOff = xOff; + mYOff = yOff; + } + + { + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque; + if (!mUseExternalBufferLocking) { + // unlock buffer before sending to display + mapper.unlock(*handle); + } + ret = mANativeWindow->enqueue_buffer(mANativeWindow, handle); + } + if ( NO_ERROR != ret ) { + CAMHAL_LOGE("Surface::queueBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) dispFrame.mBuffer->opaque); + + + // HWComposer has not minimum buffer requirement. We should be able to dequeue + // the buffer immediately + Utils::Message msg; + mDisplayQ.put(&msg); + + } + else + { + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque; + if (!mUseExternalBufferLocking) { + // unlock buffer before giving it up + mapper.unlock(*handle); + } + + // cancel buffer and dequeue another one + ret = mANativeWindow->cancel_buffer(mANativeWindow, handle); + if ( NO_ERROR != ret ) { + CAMHAL_LOGE("Surface::cancelBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) dispFrame.mBuffer->opaque); + + Utils::Message msg; + mDisplayQ.put(&msg); + ret = NO_ERROR; + } + + return ret; +} + + +bool ANativeWindowDisplayAdapter::handleFrameReturn() +{ + status_t err; + buffer_handle_t *buf; + int i = 0; + unsigned int k; + int stride; // dummy variable to get stride + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + android::Rect bounds; + CameraFrame::FrameType frameType = CameraFrame::PREVIEW_FRAME_SYNC; + + 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_LOGE("Surface::dequeueBuffer failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return false; + } + + err = mANativeWindow->lock_buffer(mANativeWindow, buf); + if ( NO_ERROR != err ) { + CAMHAL_LOGE("Surface::lockBuffer failed: %s (%d)", strerror(-err), -err); + + if ( NO_INIT == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mANativeWindow = NULL; + } + + return false; + } + + for(i = 0; i < mBufferCount; i++) + { + if (mBuffers[i].opaque == buf) + break; + } + if (i == mBufferCount) { + CAMHAL_LOGEB("Failed to find handle %p", buf); + } + if (!mUseExternalBufferLocking) { + // 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 *) mBuffers[i].opaque, 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); + } + } + + { + android::AutoMutex lock(mLock); + mFramesWithCameraAdapterMap.add((buffer_handle_t *) mBuffers[i].opaque, i); + + for( k = 0; k < mFramesType.size() ; k++) { + if(mFramesType.keyAt(k) == (int)mBuffers[i].opaque) + break; + } + + if ( k == mFramesType.size() ) { + CAMHAL_LOGE("Frame type for preview buffer 0%x not found!!", mBuffers[i].opaque); + return false; + } + + frameType = (CameraFrame::FrameType) mFramesType.valueAt(k); + mFramesType.removeItem((int) mBuffers[i].opaque); + } + + CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount-1); + mFrameProvider->returnFrame(&mBuffers[i], frameType); + + 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); +} + +void ANativeWindowDisplayAdapter::setExternalLocking(bool extBuffLocking) +{ + mUseExternalBufferLocking = extBuffLocking; +} + +/*--------------------ANativeWindowDisplayAdapter Class ENDS here-----------------------------*/ + +} // namespace Camera +} // namespace Ti |