| /* |
| * 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) |
| |
| |
| |
| { |
| 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); |
| } |
| |
| // 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; |
| } |
| |
| // 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; |
| // 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; |
| |
| // 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); |
| } |
| |
| // 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); |
| } |
| |
| |
| /*--------------------ANativeWindowDisplayAdapter Class ENDS here-----------------------------*/ |
| |
| } // namespace Camera |
| } // namespace Ti |