From e0c5a929875a3f858926d7fec7e236d6db1006a3 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sun, 3 Jan 2016 14:19:34 +0100 Subject: Add camera sources in-tree From hardware/ti/omap4 revision e57f2b6. Change-Id: I2e6164fdf6c0e2a2e75aee3bba3fe58a9c470add --- camera/ANativeWindowDisplayAdapter.cpp | 1263 ++++++ camera/Android.mk | 297 ++ camera/AppCallbackNotifier.cpp | 2002 +++++++++ camera/BaseCameraAdapter.cpp | 2744 ++++++++++++ camera/BufferSourceAdapter.cpp | 1007 +++++ camera/CameraHal.cpp | 5012 ++++++++++++++++++++++ camera/CameraHalCommon.cpp | 233 + camera/CameraHalUtilClasses.cpp | 361 ++ camera/CameraHal_Module.cpp | 840 ++++ camera/CameraParameters.cpp | 240 ++ camera/CameraProperties.cpp | 135 + camera/DecoderFactory.cpp | 59 + camera/Decoder_libjpeg.cpp | 301 ++ camera/Encoder_libjpeg.cpp | 549 +++ camera/FrameDecoder.cpp | 204 + camera/MemoryManager.cpp | 237 + camera/NV12_resize.cpp | 290 ++ camera/OMXCameraAdapter/OMX3A.cpp | 2161 ++++++++++ camera/OMXCameraAdapter/OMXAlgo.cpp | 1355 ++++++ camera/OMXCameraAdapter/OMXCameraAdapter.cpp | 4534 +++++++++++++++++++ camera/OMXCameraAdapter/OMXCapabilities.cpp | 2513 +++++++++++ camera/OMXCameraAdapter/OMXCapture.cpp | 2098 +++++++++ camera/OMXCameraAdapter/OMXDCC.cpp | 227 + camera/OMXCameraAdapter/OMXDccDataSave.cpp | 361 ++ camera/OMXCameraAdapter/OMXDefaults.cpp | 87 + camera/OMXCameraAdapter/OMXExif.cpp | 838 ++++ camera/OMXCameraAdapter/OMXFD.cpp | 504 +++ camera/OMXCameraAdapter/OMXFocus.cpp | 892 ++++ camera/OMXCameraAdapter/OMXMetadata.cpp | 181 + camera/OMXCameraAdapter/OMXReprocess.cpp | 382 ++ camera/OMXCameraAdapter/OMXZoom.cpp | 289 ++ camera/OmxFrameDecoder.cpp | 1077 +++++ camera/SensorListener.cpp | 236 + camera/SwFrameDecoder.cpp | 85 + camera/TICameraParameters.cpp | 241 ++ camera/V4LCameraAdapter/V4LCameraAdapter.cpp | 1684 ++++++++ camera/V4LCameraAdapter/V4LCapabilities.cpp | 365 ++ camera/android-api.mk | 39 + camera/inc/ANativeWindowDisplayAdapter.h | 196 + camera/inc/BaseCameraAdapter.h | 308 ++ camera/inc/BufferSourceAdapter.h | 228 + camera/inc/CameraHal.h | 1562 +++++++ camera/inc/CameraProperties.h | 244 ++ camera/inc/Common.h | 65 + camera/inc/DecoderFactory.h | 35 + camera/inc/Decoder_libjpeg.h | 58 + camera/inc/Encoder_libjpeg.h | 226 + camera/inc/FrameDecoder.h | 173 + camera/inc/General3A_Settings.h | 295 ++ camera/inc/NV12_resize.h | 135 + camera/inc/OMXCameraAdapter/OMXCameraAdapter.h | 1235 ++++++ camera/inc/OMXCameraAdapter/OMXDCC.h | 44 + camera/inc/OMXCameraAdapter/OMXSceneModeTables.h | 759 ++++ camera/inc/OmxFrameDecoder.h | 204 + camera/inc/SensorListener.h | 105 + camera/inc/SwFrameDecoder.h | 47 + camera/inc/TICameraParameters.h | 270 ++ camera/inc/V4LCameraAdapter/V4LCameraAdapter.h | 262 ++ camera/inc/VideoMetadata.h | 32 + 59 files changed, 42406 insertions(+) create mode 100644 camera/ANativeWindowDisplayAdapter.cpp create mode 100644 camera/Android.mk create mode 100644 camera/AppCallbackNotifier.cpp create mode 100644 camera/BaseCameraAdapter.cpp create mode 100644 camera/BufferSourceAdapter.cpp create mode 100644 camera/CameraHal.cpp create mode 100644 camera/CameraHalCommon.cpp create mode 100644 camera/CameraHalUtilClasses.cpp create mode 100644 camera/CameraHal_Module.cpp create mode 100644 camera/CameraParameters.cpp create mode 100644 camera/CameraProperties.cpp create mode 100644 camera/DecoderFactory.cpp create mode 100644 camera/Decoder_libjpeg.cpp create mode 100644 camera/Encoder_libjpeg.cpp create mode 100644 camera/FrameDecoder.cpp create mode 100644 camera/MemoryManager.cpp create mode 100644 camera/NV12_resize.cpp create mode 100644 camera/OMXCameraAdapter/OMX3A.cpp create mode 100644 camera/OMXCameraAdapter/OMXAlgo.cpp create mode 100644 camera/OMXCameraAdapter/OMXCameraAdapter.cpp create mode 100644 camera/OMXCameraAdapter/OMXCapabilities.cpp create mode 100644 camera/OMXCameraAdapter/OMXCapture.cpp create mode 100644 camera/OMXCameraAdapter/OMXDCC.cpp create mode 100644 camera/OMXCameraAdapter/OMXDccDataSave.cpp create mode 100644 camera/OMXCameraAdapter/OMXDefaults.cpp create mode 100644 camera/OMXCameraAdapter/OMXExif.cpp create mode 100644 camera/OMXCameraAdapter/OMXFD.cpp create mode 100644 camera/OMXCameraAdapter/OMXFocus.cpp create mode 100644 camera/OMXCameraAdapter/OMXMetadata.cpp create mode 100644 camera/OMXCameraAdapter/OMXReprocess.cpp create mode 100644 camera/OMXCameraAdapter/OMXZoom.cpp create mode 100644 camera/OmxFrameDecoder.cpp create mode 100644 camera/SensorListener.cpp create mode 100644 camera/SwFrameDecoder.cpp create mode 100644 camera/TICameraParameters.cpp create mode 100644 camera/V4LCameraAdapter/V4LCameraAdapter.cpp create mode 100644 camera/V4LCameraAdapter/V4LCapabilities.cpp create mode 100644 camera/android-api.mk create mode 100644 camera/inc/ANativeWindowDisplayAdapter.h create mode 100644 camera/inc/BaseCameraAdapter.h create mode 100644 camera/inc/BufferSourceAdapter.h create mode 100644 camera/inc/CameraHal.h create mode 100644 camera/inc/CameraProperties.h create mode 100644 camera/inc/Common.h create mode 100644 camera/inc/DecoderFactory.h create mode 100644 camera/inc/Decoder_libjpeg.h create mode 100644 camera/inc/Encoder_libjpeg.h create mode 100644 camera/inc/FrameDecoder.h create mode 100644 camera/inc/General3A_Settings.h create mode 100644 camera/inc/NV12_resize.h create mode 100644 camera/inc/OMXCameraAdapter/OMXCameraAdapter.h create mode 100644 camera/inc/OMXCameraAdapter/OMXDCC.h create mode 100644 camera/inc/OMXCameraAdapter/OMXSceneModeTables.h create mode 100644 camera/inc/OmxFrameDecoder.h create mode 100644 camera/inc/SensorListener.h create mode 100644 camera/inc/SwFrameDecoder.h create mode 100644 camera/inc/TICameraParameters.h create mode 100644 camera/inc/V4LCameraAdapter/V4LCameraAdapter.h create mode 100644 camera/inc/VideoMetadata.h (limited to 'camera') 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 +#include +#include +#include + +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 diff --git a/camera/Android.mk b/camera/Android.mk new file mode 100644 index 0000000..1789304 --- /dev/null +++ b/camera/Android.mk @@ -0,0 +1,297 @@ +LOCAL_PATH:= $(call my-dir) +OMAP4_NEXT_FOLDER := hardware/ti/omap4 + +include $(LOCAL_PATH)/android-api.mk + +TI_CAMERAHAL_INTERFACE ?= ALL + +TI_CAMERAHAL_COMMON_CFLAGS := \ + $(ANDROID_API_CFLAGS) \ + -DLOG_TAG=\"CameraHal\" \ + -DCOPY_IMAGE_BUFFER \ + -fno-short-enums + +ifdef TI_CAMERAHAL_DEBUG_ENABLED + # Enable CameraHAL debug logs + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_DEBUG +endif + +ifdef TI_CAMERAHAL_VERBOSE_DEBUG_ENABLED + # Enable CameraHAL verbose debug logs + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_DEBUG_VERBOSE +endif + +ifdef TI_CAMERAHAL_DEBUG_FUNCTION_NAMES + # Enable CameraHAL function enter/exit logging + TI_CAMERAHAL_COMMON_CFLAGS += -DTI_UTILS_FUNCTION_LOGGER_ENABLE +endif + +ifdef TI_CAMERAHAL_DEBUG_TIMESTAMPS + # Enable timestamp logging + TI_CAMERAHAL_COMMON_CFLAGS += -DTI_UTILS_DEBUG_USE_TIMESTAMPS +endif + +ifndef TI_CAMERAHAL_DONT_USE_RAW_IMAGE_SAVING + # Enabled saving RAW images to file + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_USE_RAW_IMAGE_SAVING +endif + +ifdef TI_CAMERAHAL_PROFILING + # Enable OMX Camera component profiling + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_OMX_PROFILING +endif + +ifdef TI_CAMERAHAL_MAX_CAMERAS_SUPPORTED + TI_CAMERAHAL_COMMON_CFLAGS += -DMAX_CAMERAS_SUPPORTED=$(TI_CAMERAHAL_MAX_CAMERAS_SUPPORTED) +endif + +ifdef TI_CAMERAHAL_TREAT_FRONT_AS_BACK + TI_CAMERAHAL_COMMON_CFLAGS += -DTREAT_FRONT_AS_BACK +endif + +ifeq ($(findstring omap5, $(TARGET_BOARD_PLATFORM)),omap5) + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_OMAP5_CAPTURE_MODES +endif + +ifeq ($(ENHANCED_DOMX),true) + TI_CAMERAHAL_COMMON_CFLAGS += -DENHANCED_DOMX +endif + +ifdef ARCH_ARM_HAVE_NEON + TI_CAMERAHAL_COMMON_CFLAGS += -DARCH_ARM_HAVE_NEON +endif + +ifeq ($(BOARD_VENDOR),motorola-omap4) + TI_CAMERAHAL_COMMON_CFLAGS += -DMOTOROLA_CAMERA +endif + +ifeq ($(TARGET_BOOTLOADER_BOARD_NAME),piranha) + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_PIRANHA +endif + +ifeq ($(TARGET_BOOTLOADER_BOARD_NAME),tuna) + TI_CAMERAHAL_COMMON_CFLAGS += -DCAMERAHAL_TUNA +endif + +TI_CAMERAHAL_OMX_CFLAGS := -DOMX_CAMERA_ADAPTER +TI_CAMERAHAL_USB_CFLAGS := -DV4L_CAMERA_ADAPTER + + +TI_CAMERAHAL_COMMON_INCLUDES := \ + $(OMAP4_NEXT_FOLDER)/include \ + $(OMAP4_NEXT_FOLDER)/hwc \ + external/jpeg \ + external/jhead \ + $(OMAP4_NEXT_FOLDER)/libtiutils \ + $(LOCAL_PATH)/inc \ + system/media/camera/include + +ifdef ANDROID_API_JB_OR_LATER +TI_CAMERAHAL_COMMON_INCLUDES += \ + frameworks/native/include/media/hardware +else +TI_CAMERAHAL_COMMON_INCLUDES += \ + frameworks/base/include/media/stagefright +endif + +TI_CAMERAHAL_OMX_INCLUDES := \ + frameworks/native/include/media/openmax \ + $(DOMX_PATH)/mm_osal/inc \ + $(DOMX_PATH)/omx_core/inc \ + $(LOCAL_PATH)/inc/OMXCameraAdapter + +TI_CAMERAHAL_USB_INCLUDES := \ + $(LOCAL_PATH)/inc/V4LCameraAdapter + + +TI_CAMERAHAL_COMMON_SRC := \ + CameraHal_Module.cpp \ + CameraHal.cpp \ + CameraHalUtilClasses.cpp \ + AppCallbackNotifier.cpp \ + ANativeWindowDisplayAdapter.cpp \ + BufferSourceAdapter.cpp \ + CameraProperties.cpp \ + BaseCameraAdapter.cpp \ + MemoryManager.cpp \ + Encoder_libjpeg.cpp \ + Decoder_libjpeg.cpp \ + SensorListener.cpp \ + NV12_resize.cpp \ + CameraParameters.cpp \ + TICameraParameters.cpp \ + CameraHalCommon.cpp \ + FrameDecoder.cpp \ + SwFrameDecoder.cpp \ + OmxFrameDecoder.cpp \ + DecoderFactory.cpp + +TI_CAMERAHAL_OMX_SRC := \ + OMXCameraAdapter/OMX3A.cpp \ + OMXCameraAdapter/OMXAlgo.cpp \ + OMXCameraAdapter/OMXCameraAdapter.cpp \ + OMXCameraAdapter/OMXCapabilities.cpp \ + OMXCameraAdapter/OMXCapture.cpp \ + OMXCameraAdapter/OMXReprocess.cpp \ + OMXCameraAdapter/OMXDefaults.cpp \ + OMXCameraAdapter/OMXExif.cpp \ + OMXCameraAdapter/OMXFD.cpp \ + OMXCameraAdapter/OMXFocus.cpp \ + OMXCameraAdapter/OMXMetadata.cpp \ + OMXCameraAdapter/OMXZoom.cpp \ + OMXCameraAdapter/OMXDccDataSave.cpp + +ifdef TI_CAMERAHAL_USES_LEGACY_DOMX_DCC +TI_CAMERAHAL_OMX_CFLAGS += -DUSES_LEGACY_DOMX_DCC +else +TI_CAMERAHAL_OMX_SRC += OMXCameraAdapter/OMXDCC.cpp +endif + +TI_CAMERAHAL_USB_SRC := \ + V4LCameraAdapter/V4LCameraAdapter.cpp \ + V4LCameraAdapter/V4LCapabilities.cpp + + +TI_CAMERAHAL_EXIF_LIBRARY := libexif +# libexif is now libjhead in later API levels. + +ifdef ANDROID_API_KK_OR_LATER +ifdef ANDROID_API_LP_OR_LATER + TI_CAMERAHAL_EXIF_LIBRARY := libjhead +else ifneq ($(filter 4.4.3 4.4.4,$(PLATFORM_VERSION)),) + # Only 4.4.3 and 4.4.4 KK use libjhead + TI_CAMERAHAL_EXIF_LIBRARY := libjhead +endif +endif + +TI_CAMERAHAL_COMMON_SHARED_LIBRARIES := \ + libui \ + libbinder \ + libutils \ + libcutils \ + liblog \ + libtiutils \ + libcamera_client \ + libgui \ + libjpeg \ + $(TI_CAMERAHAL_EXIF_LIBRARY) + +ifdef ANDROID_API_JB_MR1_OR_LATER +TI_CAMERAHAL_COMMON_SHARED_LIBRARIES += \ + libion_ti +TI_CAMERAHAL_COMMON_CFLAGS += -DUSE_LIBION_TI +else +TI_CAMERAHAL_COMMON_SHARED_LIBRARIES += \ + libion +endif + +TI_CAMERAHAL_OMX_SHARED_LIBRARIES := \ + libmm_osal \ + libOMX_Core \ + libdomx + + +ifdef OMAP_ENHANCEMENT_CPCAM +TI_CAMERAHAL_COMMON_STATIC_LIBRARIES += \ + libcpcamcamera_client +endif + + +ifeq ($(TI_CAMERAHAL_INTERFACE),OMX) +# ==================== +# OMX Camera Adapter +# -------------------- + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(TI_CAMERAHAL_COMMON_SRC) \ + $(TI_CAMERAHAL_OMX_SRC) + +LOCAL_C_INCLUDES := \ + $(TI_CAMERAHAL_COMMON_INCLUDES) \ + $(TI_CAMERAHAL_OMX_INCLUDES) + +LOCAL_SHARED_LIBRARIES := \ + $(TI_CAMERAHAL_COMMON_SHARED_LIBRARIES) \ + $(TI_CAMERAHAL_OMX_SHARED_LIBRARIES) + +LOCAL_STATIC_LIBRARIES := $(TI_CAMERAHAL_COMMON_STATIC_LIBRARIES) + +LOCAL_CFLAGS := \ + $(TI_CAMERAHAL_COMMON_CFLAGS) \ + $(TI_CAMERAHAL_OMX_CFLAGS) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE := camera.tuna +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +else ifeq ($(TI_CAMERAHAL_INTERFACE),USB) +# ==================== +# USB Camera Adapter +# -------------------- + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(TI_CAMERAHAL_COMMON_SRC) \ + $(TI_CAMERAHAL_USB_SRC) + +LOCAL_C_INCLUDES := \ + $(TI_CAMERAHAL_COMMON_INCLUDES) \ + $(TI_CAMERAHAL_USB_INCLUDES) + +LOCAL_SHARED_LIBRARIES := \ + $(TI_CAMERAHAL_COMMON_SHARED_LIBRARIES) + +LOCAL_STATIC_LIBRARIES := $(TI_CAMERAHAL_COMMON_STATIC_LIBRARIES) + +LOCAL_CFLAGS := \ + $(TI_CAMERAHAL_COMMON_CFLAGS) \ + $(TI_CAMERAHAL_USB_CFLAGS) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE := camera.tuna +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +else ifeq ($(TI_CAMERAHAL_INTERFACE),ALL) +# ===================== +# ALL Camera Adapters +# --------------------- + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(TI_CAMERAHAL_COMMON_SRC) \ + $(TI_CAMERAHAL_OMX_SRC) \ + $(TI_CAMERAHAL_USB_SRC) + +LOCAL_C_INCLUDES := \ + $(TI_CAMERAHAL_COMMON_INCLUDES) \ + $(TI_CAMERAHAL_OMX_INCLUDES) \ + $(TI_CAMERAHAL_USB_INCLUDES) + +LOCAL_SHARED_LIBRARIES := \ + $(TI_CAMERAHAL_COMMON_SHARED_LIBRARIES) \ + $(TI_CAMERAHAL_OMX_SHARED_LIBRARIES) + +LOCAL_STATIC_LIBRARIES := $(TI_CAMERAHAL_COMMON_STATIC_LIBRARIES) + +LOCAL_CFLAGS := \ + $(TI_CAMERAHAL_COMMON_CFLAGS) \ + $(TI_CAMERAHAL_OMX_CFLAGS) \ + $(TI_CAMERAHAL_USB_CFLAGS) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE := camera.tuna +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + +endif + +$(clear-android-api-vars) diff --git a/camera/AppCallbackNotifier.cpp b/camera/AppCallbackNotifier.cpp new file mode 100644 index 0000000..8bc10b1 --- /dev/null +++ b/camera/AppCallbackNotifier.cpp @@ -0,0 +1,2002 @@ +/* + * 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 "CameraHal.h" +#include "VideoMetadata.h" +#include "Encoder_libjpeg.h" +#include +#include +#include +#include "NV12_resize.h" +#include "TICameraParameters.h" + +namespace Ti { +namespace Camera { + +const int AppCallbackNotifier::NOTIFIER_TIMEOUT = -1; +android::KeyedVector > gEncoderQueue; + +void AppCallbackNotifierEncoderCallback(void* main_jpeg, + void* thumb_jpeg, + CameraFrame::FrameType type, + void* cookie1, + void* cookie2, + void* cookie3, + void* cookie4, + bool canceled) +{ + if (cookie1 && !canceled) { + AppCallbackNotifier* cb = (AppCallbackNotifier*) cookie1; + cb->EncoderDoneCb(main_jpeg, thumb_jpeg, type, cookie2, cookie3, cookie4); + } + + if (main_jpeg) { + free(main_jpeg); + } + + if (thumb_jpeg) { + if (((Encoder_libjpeg::params *) thumb_jpeg)->dst) { + free(((Encoder_libjpeg::params *) thumb_jpeg)->dst); + } + free(thumb_jpeg); + } +} + +/*--------------------NotificationHandler Class STARTS here-----------------------------*/ + +void AppCallbackNotifier::EncoderDoneCb(void* main_jpeg, void* thumb_jpeg, CameraFrame::FrameType type, void* cookie1, void* cookie2, void *cookie3) +{ + camera_memory_t* encoded_mem = NULL; + Encoder_libjpeg::params *main_param = NULL, *thumb_param = NULL; + size_t jpeg_size; + uint8_t* src = NULL; + CameraBuffer *camera_buffer; + android::sp encoder = NULL; + + LOG_FUNCTION_NAME; + + camera_memory_t* picture = NULL; + + { + android::AutoMutex lock(mLock); + + if (!main_jpeg) { + goto exit; + } + + encoded_mem = (camera_memory_t*) cookie1; + main_param = (Encoder_libjpeg::params *) main_jpeg; + jpeg_size = main_param->jpeg_size; + camera_buffer = (CameraBuffer *)cookie3; + src = main_param->src; + + if(encoded_mem && encoded_mem->data && (jpeg_size > 0)) { + if (cookie2) { + ExifElementsTable* exif = (ExifElementsTable*) cookie2; + Section_t* exif_section = NULL; + + exif->insertExifToJpeg((unsigned char*) encoded_mem->data, jpeg_size); + + if(thumb_jpeg) { + thumb_param = (Encoder_libjpeg::params *) thumb_jpeg; + exif->insertExifThumbnailImage((const char*)thumb_param->dst, + (int)thumb_param->jpeg_size); + } + + exif_section = FindSection(M_EXIF); + + if (exif_section) { + picture = mRequestMemory(-1, jpeg_size + exif_section->Size, 1, NULL); + if (picture && picture->data) { + exif->saveJpeg((unsigned char*) picture->data, jpeg_size + exif_section->Size); + } + } + delete exif; + cookie2 = NULL; + } else { + picture = mRequestMemory(-1, jpeg_size, 1, NULL); + if (picture && picture->data) { + memcpy(picture->data, encoded_mem->data, jpeg_size); + } + } + } + } // scope for mutex lock + + if (!mRawAvailable) { + dummyRaw(); + } else { + mRawAvailable = false; + } + + // Send the callback to the application only if the notifier is started and the message is enabled + if(picture && (mNotifierState==AppCallbackNotifier::NOTIFIER_STARTED) && + (mCameraHal->msgTypeEnabled(CAMERA_MSG_COMPRESSED_IMAGE))) + { + android::AutoMutex lock(mBurstLock); + +#ifdef OMAP_ENHANCEMENT_BURST_CAPTURE + if ( mBurst ) + { + mDataCb(CAMERA_MSG_COMPRESSED_BURST_IMAGE, picture, 0, NULL, mCallbackCookie); + + } + else +#endif + { + mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, picture, 0, NULL, mCallbackCookie); + } + } + + exit: + + if (picture) { + picture->release(picture); + } + + if (mNotifierState == AppCallbackNotifier::NOTIFIER_STARTED) { + if (encoded_mem) { + encoded_mem->release(encoded_mem); + } + if (cookie2) { + delete (ExifElementsTable*) cookie2; + } + encoder = gEncoderQueue.valueFor(src); + if (encoder.get()) { + gEncoderQueue.removeItem(src); + encoder.clear(); + } + mFrameProvider->returnFrame(camera_buffer, type); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + * NotificationHandler class + */ + +///Initialization function for AppCallbackNotifier +status_t AppCallbackNotifier::initialize() +{ + LOG_FUNCTION_NAME; + + mPreviewMemory = 0; + + mMeasurementEnabled = false; + + mNotifierState = NOTIFIER_STOPPED; + + ///Create the app notifier thread + mNotificationThread = new NotificationThread(this); + if(!mNotificationThread.get()) + { + CAMHAL_LOGEA("Couldn't create Notification thread"); + return NO_MEMORY; + } + + ///Start the display thread + status_t ret = mNotificationThread->run("NotificationThread", android::PRIORITY_URGENT_DISPLAY); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEA("Couldn't run NotificationThread"); + mNotificationThread.clear(); + return ret; + } + + mUseMetaDataBufferMode = true; + mRawAvailable = false; + + mRecording = false; + mPreviewing = false; + mExternalLocking = false; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void AppCallbackNotifier::setCallbacks(CameraHal* cameraHal, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME; + + mCameraHal = cameraHal; + mNotifyCb = notify_cb; + mDataCb = data_cb; + mDataCbTimestamp = data_cb_timestamp; + mRequestMemory = get_memory; + mCallbackCookie = user; + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setMeasurements(bool enable) +{ + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME; + + mMeasurementEnabled = enable; + + if ( enable ) + { + mFrameProvider->enableFrameNotification(CameraFrame::FRAME_DATA_SYNC); + } + + LOG_FUNCTION_NAME_EXIT; +} + + +//All sub-components of Camera HAL call this whenever any error happens +void AppCallbackNotifier::errorNotify(int error) +{ + LOG_FUNCTION_NAME; + + CAMHAL_LOGEB("AppCallbackNotifier received error %d", error); + + // If it is a fatal error abort here! + // If TILER is Out of memory we notify Mediaserver so that Memory is cleared and we can restart usecase + if((error == CAMERA_ERROR_FATAL) || (error == CAMERA_ERROR_HARD) || (error == -ENOMEM)) + { + //We kill media server if we encounter these errors as there is + //no point continuing and apps also don't handle errors other + //than media server death always. + abort(); + return; + } + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ERROR) ) ) + { + CAMHAL_LOGEB("AppCallbackNotifier mNotifyCb %d", error); + mNotifyCb(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0, mCallbackCookie); + } + + LOG_FUNCTION_NAME_EXIT; +} + +bool AppCallbackNotifier::notificationThread() +{ + bool shouldLive = true; + status_t ret; + + LOG_FUNCTION_NAME; + + //CAMHAL_LOGDA("Notification Thread waiting for message"); + ret = Utils::MessageQueue::waitForMsg(&mNotificationThread->msgQ(), + &mEventQ, + &mFrameQ, + AppCallbackNotifier::NOTIFIER_TIMEOUT); + + //CAMHAL_LOGDA("Notification Thread received message"); + + if (mNotificationThread->msgQ().hasMsg()) { + ///Received a message from CameraHal, process it + CAMHAL_LOGDA("Notification Thread received message from Camera HAL"); + shouldLive = processMessage(); + if(!shouldLive) { + CAMHAL_LOGDA("Notification Thread exiting."); + return shouldLive; + } + } + + if(mEventQ.hasMsg()) { + ///Received an event from one of the event providers + CAMHAL_LOGDA("Notification Thread received an event from event provider (CameraAdapter)"); + notifyEvent(); + } + + if(mFrameQ.hasMsg()) { + ///Received a frame from one of the frame providers + //CAMHAL_LOGDA("Notification Thread received a frame from frame provider (CameraAdapter)"); + notifyFrame(); + } + + LOG_FUNCTION_NAME_EXIT; + return shouldLive; +} + +void AppCallbackNotifier::notifyEvent() +{ + ///Receive and send the event notifications to app + Utils::Message msg; + LOG_FUNCTION_NAME; + { + android::AutoMutex lock(mLock); + if ( !mEventQ.hasMsg() ) { + return; + } else { + mEventQ.get(&msg); + } + } + bool ret = true; + CameraHalEvent *evt = NULL; + CameraHalEvent::FocusEventData *focusEvtData; + CameraHalEvent::ZoomEventData *zoomEvtData; + CameraHalEvent::MetaEventData metaEvtData; + + if(mNotifierState != AppCallbackNotifier::NOTIFIER_STARTED) + { + return; + } + + switch(msg.command) + { + case AppCallbackNotifier::NOTIFIER_CMD_PROCESS_EVENT: + + evt = ( CameraHalEvent * ) msg.arg1; + + if ( NULL == evt ) + { + CAMHAL_LOGEA("Invalid CameraHalEvent"); + return; + } + + switch(evt->mEventType) + { + case CameraHalEvent::EVENT_SHUTTER: + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_SHUTTER) ) ) + { + mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie); + } + mRawAvailable = false; + + break; + + case CameraHalEvent::EVENT_FOCUS_LOCKED: + case CameraHalEvent::EVENT_FOCUS_ERROR: + if ( mCameraHal && mNotifyCb ) { + focusEvtData = &evt->mEventData->focusEvent; + + switch ( focusEvtData->focusStatus ) { + case CameraHalEvent::FOCUS_STATUS_SUCCESS: + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS) ) { + mCameraHal->disableMsgType(CAMERA_MSG_FOCUS); + mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie); + } + break; + + case CameraHalEvent::FOCUS_STATUS_FAIL: + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS) ) { + mCameraHal->disableMsgType(CAMERA_MSG_FOCUS); + mNotifyCb(CAMERA_MSG_FOCUS, false, 0, mCallbackCookie); + } + break; + +#ifdef ANDROID_API_JB_OR_LATER + case CameraHalEvent::FOCUS_STATUS_PENDING: + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS_MOVE) ) { + mNotifyCb(CAMERA_MSG_FOCUS_MOVE, true, 0, mCallbackCookie); + } + break; + + case CameraHalEvent::FOCUS_STATUS_DONE: + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS_MOVE) ) { + mNotifyCb(CAMERA_MSG_FOCUS_MOVE, false, 0, mCallbackCookie); + } + break; +#endif + } + } + + break; + + case CameraHalEvent::EVENT_ZOOM_INDEX_REACHED: + + zoomEvtData = &evt->mEventData->zoomEvent; + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ZOOM) ) ) + { + mNotifyCb(CAMERA_MSG_ZOOM, zoomEvtData->currentZoomIndex, zoomEvtData->targetZoomIndexReached, mCallbackCookie); + } + + break; + + case CameraHalEvent::EVENT_METADATA: + + metaEvtData = evt->mEventData->metadataEvent; + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_METADATA) ) ) + { + // WA for an issue inside CameraService + camera_memory_t *tmpBuffer = mRequestMemory(-1, 1, 1, NULL); + + mDataCb(CAMERA_MSG_PREVIEW_METADATA, + tmpBuffer, + 0, + metaEvtData->getMetadataResult(), + mCallbackCookie); + + metaEvtData.clear(); + + if ( NULL != tmpBuffer ) { + tmpBuffer->release(tmpBuffer); + } + + } + + break; + + case CameraHalEvent::ALL_EVENTS: + break; + default: + break; + } + + break; + } + + if ( NULL != evt ) + { + delete evt; + } + + + LOG_FUNCTION_NAME_EXIT; + +} + +static void alignYV12(int width, + int height, + size_t &yStride, + size_t &uvStride, + size_t &ySize, + size_t &uvSize, + size_t &size) +{ + yStride = ( width + 0xF ) & ~0xF; + uvStride = ( yStride / 2 + 0xF ) & ~0xF; + ySize = yStride * height; + uvSize = uvStride * height / 2; + size = ySize + uvSize * 2; +} + +static void copy2Dto1D(void *dst, + void *src, + int width, + int height, + size_t stride, + uint32_t offset, + unsigned int bytesPerPixel, + size_t length, + const char *pixelFormat) +{ + unsigned int alignedRow, row; + unsigned char *bufferDst, *bufferSrc; + unsigned char *bufferDstEnd, *bufferSrcEnd; + uint16_t *bufferSrc_UV; + + unsigned int *y_uv = (unsigned int *)src; + + CAMHAL_LOGVB("copy2Dto1D() y= %p ; uv=%p.",y_uv[0], y_uv[1]); + CAMHAL_LOGVB("pixelFormat = %s; offset=%d",pixelFormat,offset); + + if (pixelFormat!=NULL) { + if (strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + bytesPerPixel = 2; + bufferSrc = ( unsigned char * ) y_uv[0] + offset; + uint32_t xOff = offset % stride; + uint32_t yOff = offset / stride; + uint8_t *bufferSrcUV = ((uint8_t*)y_uv[1] + (stride/2)*yOff + xOff); + uint8_t *bufferSrcUVEven = bufferSrcUV; + + uint8_t *bufferDstY = ( uint8_t * ) dst; + uint8_t *bufferDstU = bufferDstY + 1; + uint8_t *bufferDstV = bufferDstY + 3; + + // going to convert from NV12 here and return + for ( int i = 0 ; i < height; i ++ ) { + for ( int j = 0 ; j < width / 2 ; j++ ) { + + // Y + *bufferDstY = *bufferSrc; + bufferSrc++; + bufferDstY += 2; + + *bufferDstY = *bufferSrc; + bufferSrc++; + bufferDstY += 2; + + // V + *bufferDstV = *(bufferSrcUV + 1); + bufferDstV += 4; + + // U + *bufferDstU = *bufferSrcUV; + bufferDstU += 4; + + bufferSrcUV += 2; + } + if ( i % 2 ) { + bufferSrcUV += ( stride - width); + bufferSrcUVEven = bufferSrcUV; + } else { + bufferSrcUV = bufferSrcUVEven; + } + bufferSrc += ( stride - width); + } + + return; + } else if (strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + bytesPerPixel = 1; + bufferDst = ( unsigned char * ) dst; + bufferDstEnd = ( unsigned char * ) dst + width*height*bytesPerPixel; + bufferSrc = ( unsigned char * ) y_uv[0] + offset; + bufferSrcEnd = ( unsigned char * ) ( ( size_t ) y_uv[0] + length + offset); + row = width*bytesPerPixel; + alignedRow = stride-width; + int stride_bytes = stride / 8; + uint32_t xOff = offset % stride; + uint32_t yOff = offset / stride; + + // going to convert from NV12 here and return + // Step 1: Y plane: iterate through each row and copy + for ( int i = 0 ; i < height ; i++) { + memcpy(bufferDst, bufferSrc, row); + bufferSrc += stride; + bufferDst += row; + if ( ( bufferSrc > bufferSrcEnd ) || ( bufferDst > bufferDstEnd ) ) { + break; + } + } + + bufferSrc_UV = ( uint16_t * ) ((uint8_t*)y_uv[1] + (stride/2)*yOff + xOff); + + if (strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + uint16_t *bufferDst_UV; + + // Step 2: UV plane: convert NV12 to NV21 by swapping U & V + bufferDst_UV = (uint16_t *) (((uint8_t*)dst)+row*height); + +#ifdef ARCH_ARM_HAVE_NEON + for (int i = 0 ; i < height/2 ; i++, bufferSrc_UV += alignedRow/2) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #32 \n\t" + " blt 1f \n\t" + "0: @ 32 byte swap \n\t" + " sub %[n], %[n], #32 \n\t" + " vld2.8 {q0, q1} , [%[src]]! \n\t" + " vswp q0, q1 \n\t" + " cmp %[n], #32 \n\t" + " vst2.8 {q0,q1},[%[dst]]! \n\t" + " bge 0b \n\t" + "1: @ Is there enough data? \n\t" + " cmp %[n], #16 \n\t" + " blt 3f \n\t" + "2: @ 16 byte swap \n\t" + " sub %[n], %[n], #16 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " vswp d0, d1 \n\t" + " cmp %[n], #16 \n\t" + " vst2.8 {d0,d1},[%[dst]]! \n\t" + " bge 2b \n\t" + "3: @ Is there enough data? \n\t" + " cmp %[n], #8 \n\t" + " blt 5f \n\t" + "4: @ 8 byte swap \n\t" + " sub %[n], %[n], #8 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " vswp d0, d1 \n\t" + " cmp %[n], #8 \n\t" + " vst2.8 {d0[0],d1[0]},[%[dst]]! \n\t" + " bge 4b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst] "+r" (bufferDst_UV), [src] "+r" (bufferSrc_UV), [n] "+r" (n) + : [src_stride] "r" (stride_bytes) + : "cc", "memory", "q0", "q1" + ); + } +#else + for ( int i = 0; i < height/2; ++i ) { + for ( int j = 0; j < width/2; ++j ) { + bufferDst_UV[j] = (bufferSrc_UV[j] >> 8) | (bufferSrc_UV[j] << 8); + } + bufferSrc_UV += stride/bytesPerPixel/2; + bufferDst_UV += width/2; + } +#endif + } else if (strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + // Step 2: UV plane: convert NV12 to YV12 by de-interleaving U & V + // TODO(XXX): This version of CameraHal assumes NV12 format it set at + // camera adapter to support YV12. Need to address for + // USBCamera + + size_t yStride, uvStride, ySize, uvSize, size; + alignYV12(width, height, yStride, uvStride, ySize, uvSize, size); + + uint16_t *bufferDst_V = (uint16_t *) (((uint8_t*)dst) + ySize); + uint16_t *bufferDst_U = (uint16_t *) (((uint8_t*)dst) + ySize + uvSize); + +#ifdef ARCH_ARM_HAVE_NEON + int inc = (uvStride - width/2)/2; + + for (int i = 0 ; i < height/2 ; i++, bufferSrc_UV += alignedRow/2) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #32 \n\t" + " blt 1f \n\t" + "0: @ 32 byte swap \n\t" + " sub %[n], %[n], #32 \n\t" + " vld2.8 {q0, q1} , [%[src]]! \n\t" + " cmp %[n], #32 \n\t" + " vst1.8 {q1},[%[dst_v]]! \n\t" + " vst1.8 {q0},[%[dst_u]]! \n\t" + " bge 0b \n\t" + "1: @ Is there enough data? \n\t" + " cmp %[n], #16 \n\t" + " blt 3f \n\t" + "2: @ 16 byte swap \n\t" + " sub %[n], %[n], #16 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " cmp %[n], #16 \n\t" + " vst1.8 {d1},[%[dst_v]]! \n\t" + " vst1.8 {d0},[%[dst_u]]! \n\t" + " bge 2b \n\t" + "3: @ Is there enough data? \n\t" + " cmp %[n], #8 \n\t" + " blt 5f \n\t" + "4: @ 8 byte swap \n\t" + " sub %[n], %[n], #8 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " cmp %[n], #8 \n\t" + " vst1.8 {d1[0]},[%[dst_v]]! \n\t" + " vst1.8 {d0[0]},[%[dst_u]]! \n\t" + " bge 4b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst_u] "+r" (bufferDst_U), [dst_v] "+r" (bufferDst_V), + [src] "+r" (bufferSrc_UV), [n] "+r" (n) + : [src_stride] "r" (stride_bytes) + : "cc", "memory", "q0", "q1" + ); + + bufferDst_U += inc; + bufferDst_V += inc; + } +#else + uint8_t * udst = reinterpret_cast(bufferDst_V); + uint8_t * vdst = reinterpret_cast(bufferDst_U); + + for ( int i = 0; i < height/2; ++i ) { + for ( int j = 0; j < width/2; ++j ) { + udst[j] = bufferSrc_UV[j] >> 8; + vdst[j] = bufferSrc_UV[j] & 0x00ff; + } + bufferSrc_UV += stride/bytesPerPixel/2; + udst += width/2; + vdst += width/2; + } +#endif + } + return ; + + } else if(strcmp(pixelFormat, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + bytesPerPixel = 2; + } + } + + bufferDst = ( unsigned char * ) dst; + bufferSrc = ( unsigned char * ) y_uv[0]; + row = width*bytesPerPixel; + alignedRow = ( row + ( stride -1 ) ) & ( ~ ( stride -1 ) ); + + //iterate through each row + for ( int i = 0 ; i < height ; i++, bufferSrc += alignedRow, bufferDst += row) { + memcpy(bufferDst, bufferSrc, row); + } +} + +static void copyCroppedNV12(CameraFrame* frame, unsigned char *dst) +{ + unsigned int stride, width, height; + uint32_t offset, uvoffset; + size_t size; + + CAMHAL_ASSERT(frame && dst); + + offset = frame->mOffset; + stride = frame->mAlignment; + width = frame->mWidth; + height = frame->mHeight; + size = frame->mLength; + unsigned const char *src = (unsigned char *) frame->mBuffer->mapped; + + // offset to beginning of uv plane + uvoffset = (offset + size) * 2 / 3; + // offset to beginning of valid region of uv plane + uvoffset += (offset - (offset % stride)) / 2 + (offset % stride); + + // start of valid luma region + unsigned const char *luma = src + offset; + // start of valid chroma region + unsigned const char *chroma = src + uvoffset; + + // copy luma and chroma line x line + for (unsigned int i = 0; i < height; i++) { + memcpy(dst, luma, width); + luma += stride; + dst += width; + } + for (unsigned int i = 0; i < height / 2; i++) { + memcpy(dst, chroma, width); + chroma += stride; + dst += width; + } +} + +void AppCallbackNotifier::copyAndSendPictureFrame(CameraFrame* frame, int32_t msgType) +{ + camera_memory_t* picture = NULL; + void *dest = NULL, *src = NULL; + + // scope for lock + if (mCameraHal->msgTypeEnabled(msgType)) { + android::AutoMutex lock(mLock); + + if(mNotifierState != AppCallbackNotifier::NOTIFIER_STARTED) { + goto exit; + } + + if (frame->mBuffer->format && + (strcmp(frame->mBuffer->format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) && + (frame->mAlignment != frame->mWidth) && + ( msgType == CAMERA_MSG_RAW_IMAGE )) { + size_t size; + + size = CameraHal::calculateBufferSize(frame->mBuffer->format, frame->mWidth, frame->mHeight); + picture = mRequestMemory(-1, size, 1, NULL); + if (picture && picture->data) { + copyCroppedNV12(frame, (unsigned char*) picture->data); + } + } else { + picture = mRequestMemory(-1, frame->mLength, 1, NULL); + + if (NULL != picture) { + dest = picture->data; + if (NULL != dest) { + src = (void *) ((unsigned int) frame->mBuffer->mapped + frame->mOffset); + memcpy(dest, src, frame->mLength); + } + } + } + } + + exit: + mFrameProvider->returnFrame(frame->mBuffer, (CameraFrame::FrameType) frame->mFrameType); + + if(picture) { + if((mNotifierState == AppCallbackNotifier::NOTIFIER_STARTED) && + mCameraHal->msgTypeEnabled(msgType)) { + mDataCb(msgType, picture, 0, NULL, mCallbackCookie); + } + picture->release(picture); + } +} + +void AppCallbackNotifier::lockBufferAndUpdatePtrs(CameraFrame* frame) +{ + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + android::Rect bounds; + + bounds.left = 0; + bounds.top = 0; + bounds.right = frame->mWidth; + bounds.bottom = frame->mHeight; + void *y_uv[2]; + buffer_handle_t *handle = reinterpret_cast(frame->mBuffer->opaque); + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + frame->mBuffer->mapped = y_uv[0]; + frame->mYuv[0] = reinterpret_cast(frame->mBuffer->mapped); + frame->mYuv[1] = frame->mYuv[0] + (frame->mLength + frame->mOffset)*2/3; +} + +void AppCallbackNotifier::unlockBufferAndUpdatePtrs(CameraFrame* frame) +{ + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + buffer_handle_t *handle = reinterpret_cast(frame->mBuffer->opaque); + mapper.unlock(*handle); + frame->mBuffer->mapped = NULL; + frame->mYuv[0] = NULL; + frame->mYuv[1] = NULL; +} + +void AppCallbackNotifier::setExternalLocking(bool extBuffLocking) +{ + mExternalLocking = extBuffLocking; +} + +void AppCallbackNotifier::copyAndSendPreviewFrame(CameraFrame* frame, int32_t msgType) +{ + camera_memory_t* picture = NULL; + CameraBuffer * dest = NULL; + + // scope for lock + { + android::AutoMutex lock(mLock); + + if(mNotifierState != AppCallbackNotifier::NOTIFIER_STARTED) { + goto exit; + } + + if (!mPreviewMemory || !frame->mBuffer) { + CAMHAL_LOGDA("Error! One of the buffer is NULL"); + goto exit; + } + + dest = &mPreviewBuffers[mPreviewBufCount]; + if (mExternalLocking) { + lockBufferAndUpdatePtrs(frame); + } + CAMHAL_LOGVB("%d:copy2Dto1D(%p, %p, %d, %d, %d, %d, %d,%s)", + __LINE__, + dest, + frame->mBuffer, + mPreviewWidth, + mPreviewHeight, + mPreviewStride, + 2, + frame->mLength, + mPreviewPixelFormat); + + /* FIXME map dest */ + if ( NULL != dest && dest->mapped != NULL ) { + // data sync frames don't need conversion + if (CameraFrame::FRAME_DATA_SYNC == frame->mFrameType) { + if ( (mPreviewMemory->size / MAX_BUFFERS) >= frame->mLength ) { + memcpy(dest->mapped, (void*) frame->mBuffer->mapped, frame->mLength); + } else { + memset(dest->mapped, 0, (mPreviewMemory->size / MAX_BUFFERS)); + } + } else { + if ((NULL == frame->mYuv[0]) || (NULL == frame->mYuv[1])){ + CAMHAL_LOGEA("Error! One of the YUV Pointer is NULL"); + goto exit; + } + else{ + copy2Dto1D(dest->mapped, + frame->mYuv, + mPreviewWidth, + mPreviewHeight, + mPreviewStride, + frame->mOffset, + 2, + frame->mLength, + mPreviewPixelFormat); + } + } + } + } + + exit: + mFrameProvider->returnFrame(frame->mBuffer, (CameraFrame::FrameType) frame->mFrameType); + + if((mNotifierState == AppCallbackNotifier::NOTIFIER_STARTED) && + mCameraHal->msgTypeEnabled(msgType) && + (dest != NULL) && (dest->mapped != NULL)) { + android::AutoMutex locker(mLock); + if ( mPreviewMemory ) + mDataCb(msgType, mPreviewMemory, mPreviewBufCount, NULL, mCallbackCookie); + } + + if (mExternalLocking) { + unlockBufferAndUpdatePtrs(frame); + } + + // increment for next buffer + mPreviewBufCount = (mPreviewBufCount + 1) % AppCallbackNotifier::MAX_BUFFERS; +} + +status_t AppCallbackNotifier::dummyRaw() +{ + LOG_FUNCTION_NAME; + + if ( NULL == mRequestMemory ) { + CAMHAL_LOGEA("Can't allocate memory for dummy raw callback!"); + return NO_INIT; + } + + if ( ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( NULL != mNotifyCb ) ){ + + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE) ) { + camera_memory_t *dummyRaw = mRequestMemory(-1, 1, 1, NULL); + + if ( NULL == dummyRaw ) { + CAMHAL_LOGEA("Dummy raw buffer allocation failed!"); + return NO_MEMORY; + } + + mDataCb(CAMERA_MSG_RAW_IMAGE, dummyRaw, 0, NULL, mCallbackCookie); + + dummyRaw->release(dummyRaw); + } else if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY) ) { + mNotifyCb(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCallbackCookie); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +void AppCallbackNotifier::notifyFrame() +{ + ///Receive and send the frame notifications to app + Utils::Message msg; + CameraFrame *frame; + android::MemoryHeapBase *heap; + android::MemoryBase *buffer = NULL; + android::sp memBase; + void *buf = NULL; + + LOG_FUNCTION_NAME; + + { + android::AutoMutex lock(mLock); + if(!mFrameQ.isEmpty()) { + mFrameQ.get(&msg); + } else { + return; + } + } + + bool ret = true; + + frame = NULL; + switch(msg.command) + { + case AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME: + + frame = (CameraFrame *) msg.arg1; + if(!frame) + { + break; + } + + if ( (CameraFrame::RAW_FRAME == frame->mFrameType )&& + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( NULL != mNotifyCb ) ) + { + + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE) ) + { +#ifdef COPY_IMAGE_BUFFER + copyAndSendPictureFrame(frame, CAMERA_MSG_RAW_IMAGE); +#else + //TODO: Find a way to map a Tiler buffer to a MemoryHeapBase +#endif + } + else { + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY) ) { + mNotifyCb(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCallbackCookie); + } + mFrameProvider->returnFrame(frame->mBuffer, + (CameraFrame::FrameType) frame->mFrameType); + } + + mRawAvailable = true; + + } + else if ( (CameraFrame::IMAGE_FRAME == frame->mFrameType) && + (NULL != mCameraHal) && + (NULL != mDataCb) && + (CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG & frame->mQuirks) ) + { + + int encode_quality = 100, tn_quality = 100; + int tn_width, tn_height; + unsigned int current_snapshot = 0; + Encoder_libjpeg::params *main_jpeg = NULL, *tn_jpeg = NULL; + void* exif_data = NULL; + const char *previewFormat = NULL; + camera_memory_t* raw_picture = mRequestMemory(-1, frame->mLength, 1, NULL); + + if(raw_picture) { + buf = raw_picture->data; + } + + android::CameraParameters parameters; + char *params = mCameraHal->getParameters(); + const android::String8 strParams(params); + parameters.unflatten(strParams); + + encode_quality = parameters.getInt(android::CameraParameters::KEY_JPEG_QUALITY); + if (encode_quality < 0 || encode_quality > 100) { + encode_quality = 100; + } + + tn_quality = parameters.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + if (tn_quality < 0 || tn_quality > 100) { + tn_quality = 100; + } + + if (CameraFrame::HAS_EXIF_DATA & frame->mQuirks) { + exif_data = frame->mCookie2; + } + + main_jpeg = (Encoder_libjpeg::params*) + malloc(sizeof(Encoder_libjpeg::params)); + + // Video snapshot with LDCNSF on adds a few bytes start offset + // and a few bytes on every line. They must be skipped. + int rightCrop = frame->mAlignment/2 - frame->mWidth; + + CAMHAL_LOGDB("Video snapshot right crop = %d", rightCrop); + CAMHAL_LOGDB("Video snapshot offset = %d", frame->mOffset); + + if (main_jpeg) { + main_jpeg->src = (uint8_t *)frame->mBuffer->mapped; + main_jpeg->src_size = frame->mLength; + main_jpeg->dst = (uint8_t*) buf; + main_jpeg->dst_size = frame->mLength; + main_jpeg->quality = encode_quality; + main_jpeg->in_width = frame->mAlignment/2; // use stride here + main_jpeg->in_height = frame->mHeight; + main_jpeg->out_width = frame->mAlignment/2; + main_jpeg->out_height = frame->mHeight; + main_jpeg->right_crop = rightCrop; + main_jpeg->start_offset = frame->mOffset; + if ( CameraFrame::FORMAT_YUV422I_UYVY & frame->mQuirks) { + main_jpeg->format = TICameraParameters::PIXEL_FORMAT_YUV422I_UYVY; + } + else { //if ( CameraFrame::FORMAT_YUV422I_YUYV & frame->mQuirks) + main_jpeg->format = android::CameraParameters::PIXEL_FORMAT_YUV422I; + } + } + + tn_width = parameters.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + tn_height = parameters.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + previewFormat = parameters.getPreviewFormat(); + + if ((tn_width > 0) && (tn_height > 0) && ( NULL != previewFormat )) { + tn_jpeg = (Encoder_libjpeg::params*) + malloc(sizeof(Encoder_libjpeg::params)); + // if malloc fails just keep going and encode main jpeg + if (!tn_jpeg) { + tn_jpeg = NULL; + } + } + + if (tn_jpeg) { + int width, height; + parameters.getPreviewSize(&width,&height); + current_snapshot = (mPreviewBufCount + MAX_BUFFERS - 1) % MAX_BUFFERS; + tn_jpeg->src = (uint8_t *)mPreviewBuffers[current_snapshot].mapped; + tn_jpeg->src_size = mPreviewMemory->size / MAX_BUFFERS; + tn_jpeg->dst_size = CameraHal::calculateBufferSize(previewFormat, + tn_width, + tn_height); + tn_jpeg->dst = (uint8_t*) malloc(tn_jpeg->dst_size); + tn_jpeg->quality = tn_quality; + tn_jpeg->in_width = width; + tn_jpeg->in_height = height; + tn_jpeg->out_width = tn_width; + tn_jpeg->out_height = tn_height; + tn_jpeg->right_crop = 0; + tn_jpeg->start_offset = 0; + tn_jpeg->format = android::CameraParameters::PIXEL_FORMAT_YUV420SP;; + } + + android::sp encoder = new Encoder_libjpeg(main_jpeg, + tn_jpeg, + AppCallbackNotifierEncoderCallback, + (CameraFrame::FrameType)frame->mFrameType, + this, + raw_picture, + exif_data, frame->mBuffer); + gEncoderQueue.add(frame->mBuffer->mapped, encoder); + encoder->run(); + encoder.clear(); + if (params != NULL) + { + mCameraHal->putParameters(params); + } + } + else if ( ( CameraFrame::IMAGE_FRAME == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) ) + { + + // CTS, MTS requirements: Every 'takePicture()' call + // who registers a raw callback should receive one + // as well. This is not always the case with + // CameraAdapters though. + if (!mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE)) { + dummyRaw(); + } else { + mRawAvailable = false; + } + +#ifdef COPY_IMAGE_BUFFER + { + android::AutoMutex lock(mBurstLock); +#ifdef OMAP_ENHANCEMENT_BURST_CAPTURE + if ( mBurst ) + { + copyAndSendPictureFrame(frame, CAMERA_MSG_COMPRESSED_BURST_IMAGE); + } + else +#endif + { + copyAndSendPictureFrame(frame, CAMERA_MSG_COMPRESSED_IMAGE); + } + } +#else + //TODO: Find a way to map a Tiler buffer to a MemoryHeapBase +#endif + } + else if ( ( CameraFrame::VIDEO_FRAME_SYNC == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_VIDEO_FRAME) ) ) + { + android::AutoMutex locker(mRecordingLock); + if(mRecording) + { + if(mUseMetaDataBufferMode) + { + camera_memory_t *videoMedatadaBufferMemory = + mVideoMetadataBufferMemoryMap.valueFor(frame->mBuffer->opaque); + video_metadata_t *videoMetadataBuffer = (video_metadata_t *) videoMedatadaBufferMemory->data; + + if( (NULL == videoMedatadaBufferMemory) || (NULL == videoMetadataBuffer) || (NULL == frame->mBuffer) ) + { + CAMHAL_LOGEA("Error! One of the video buffers is NULL"); + break; + } + + if ( mUseVideoBuffers ) + { + CameraBuffer *vBuf = mVideoMap.valueFor(frame->mBuffer->opaque); + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + android::Rect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.right = mVideoWidth; + bounds.bottom = mVideoHeight; + if (mExternalLocking) { + lockBufferAndUpdatePtrs(frame); + } + void *y_uv[2]; + mapper.lock((buffer_handle_t)vBuf, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + y_uv[1] = y_uv[0] + mVideoHeight*4096; + + structConvImage input = {frame->mWidth, + frame->mHeight, + 4096, + IC_FORMAT_YCbCr420_lp, + (mmByte *)frame->mYuv[0], + (mmByte *)frame->mYuv[1], + frame->mOffset}; + + structConvImage output = {mVideoWidth, + mVideoHeight, + 4096, + IC_FORMAT_YCbCr420_lp, + (mmByte *)y_uv[0], + (mmByte *)y_uv[1], + 0}; + + VT_resizeFrame_Video_opt2_lp(&input, &output, NULL, 0); + mapper.unlock((buffer_handle_t)vBuf->opaque); + if (mExternalLocking) { + unlockBufferAndUpdatePtrs(frame); + } + videoMetadataBuffer->metadataBufferType = (int) android::kMetadataBufferTypeCameraSource; + /* FIXME remove cast */ + videoMetadataBuffer->handle = (void *)vBuf->opaque; + videoMetadataBuffer->offset = 0; + } + else + { + videoMetadataBuffer->metadataBufferType = (int) android::kMetadataBufferTypeCameraSource; + videoMetadataBuffer->handle = camera_buffer_get_omx_ptr(frame->mBuffer); + videoMetadataBuffer->offset = frame->mOffset; + } + + CAMHAL_LOGVB("mDataCbTimestamp : frame->mBuffer=0x%x, videoMetadataBuffer=0x%x, videoMedatadaBufferMemory=0x%x", + frame->mBuffer->opaque, videoMetadataBuffer, videoMedatadaBufferMemory); + + mDataCbTimestamp(frame->mTimestamp, CAMERA_MSG_VIDEO_FRAME, + videoMedatadaBufferMemory, 0, mCallbackCookie); + } + else + { + //TODO: Need to revisit this, should ideally be mapping the TILER buffer using mRequestMemory + camera_memory_t* fakebuf = mRequestMemory(-1, sizeof(buffer_handle_t), 1, NULL); + if( (NULL == fakebuf) || ( NULL == fakebuf->data) || ( NULL == frame->mBuffer)) + { + CAMHAL_LOGEA("Error! One of the video buffers is NULL"); + break; + } + if (mExternalLocking) { + lockBufferAndUpdatePtrs(frame); + } + *reinterpret_cast(fakebuf->data) = reinterpret_cast(frame->mBuffer->mapped); + mDataCbTimestamp(frame->mTimestamp, CAMERA_MSG_VIDEO_FRAME, fakebuf, 0, mCallbackCookie); + fakebuf->release(fakebuf); + if (mExternalLocking) { + unlockBufferAndUpdatePtrs(frame); + } + } + } + } + else if(( CameraFrame::SNAPSHOT_FRAME == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( NULL != mNotifyCb)) { + //When enabled, measurement data is sent instead of video data + if ( !mMeasurementEnabled ) { + copyAndSendPreviewFrame(frame, CAMERA_MSG_POSTVIEW_FRAME); + } else { + mFrameProvider->returnFrame(frame->mBuffer, + (CameraFrame::FrameType) frame->mFrameType); + } + } + else if ( ( CameraFrame::PREVIEW_FRAME_SYNC== frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) ) { + //When enabled, measurement data is sent instead of video data + if ( !mMeasurementEnabled ) { + copyAndSendPreviewFrame(frame, CAMERA_MSG_PREVIEW_FRAME); + } else { + mFrameProvider->returnFrame(frame->mBuffer, + (CameraFrame::FrameType) frame->mFrameType); + } + } + else if ( ( CameraFrame::FRAME_DATA_SYNC == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) ) { + copyAndSendPreviewFrame(frame, CAMERA_MSG_PREVIEW_FRAME); + } else { + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + CAMHAL_LOGDB("Frame type 0x%x is still unsupported!", frame->mFrameType); + } + + break; + + default: + + break; + + }; + +exit: + + if ( NULL != frame ) + { + delete frame; + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::frameCallbackRelay(CameraFrame* caFrame) +{ + LOG_FUNCTION_NAME; + AppCallbackNotifier *appcbn = (AppCallbackNotifier*) (caFrame->mCookie); + appcbn->frameCallback(caFrame); + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::frameCallback(CameraFrame* caFrame) +{ + ///Post the event to the event queue of AppCallbackNotifier + Utils::Message msg; + CameraFrame *frame; + + LOG_FUNCTION_NAME; + + if ( NULL != caFrame ) + { + + frame = new CameraFrame(*caFrame); + if ( NULL != frame ) + { + msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME; + msg.arg1 = frame; + mFrameQ.put(&msg); + } + else + { + CAMHAL_LOGEA("Not enough resources to allocate CameraFrame"); + } + + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::flushAndReturnFrames() +{ + LOG_FUNCTION_NAME; + + Utils::Message msg; + CameraFrame *frame; + + android::AutoMutex lock(mLock); + while (!mFrameQ.isEmpty()) { + mFrameQ.get(&msg); + frame = (CameraFrame*) msg.arg1; + if (frame) { + mFrameProvider->returnFrame(frame->mBuffer, + (CameraFrame::FrameType) frame->mFrameType); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::eventCallbackRelay(CameraHalEvent* chEvt) +{ + LOG_FUNCTION_NAME; + AppCallbackNotifier *appcbn = (AppCallbackNotifier*) (chEvt->mCookie); + appcbn->eventCallback(chEvt); + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::eventCallback(CameraHalEvent* chEvt) +{ + + ///Post the event to the event queue of AppCallbackNotifier + Utils::Message msg; + CameraHalEvent *event; + + + LOG_FUNCTION_NAME; + + if ( NULL != chEvt ) + { + + event = new CameraHalEvent(*chEvt); + if ( NULL != event ) + { + msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_EVENT; + msg.arg1 = event; + { + android::AutoMutex lock(mLock); + mEventQ.put(&msg); + } + } + else + { + CAMHAL_LOGEA("Not enough resources to allocate CameraHalEvent"); + } + + } + + LOG_FUNCTION_NAME_EXIT; +} + + +void AppCallbackNotifier::flushEventQueue() +{ + + { + android::AutoMutex lock(mLock); + mEventQ.clear(); + } +} + + +bool AppCallbackNotifier::processMessage() +{ + ///Retrieve the command from the command queue and process it + Utils::Message msg; + + LOG_FUNCTION_NAME; + + CAMHAL_LOGDA("+Msg get..."); + mNotificationThread->msgQ().get(&msg); + CAMHAL_LOGDA("-Msg get..."); + bool ret = true; + + switch(msg.command) + { + case NotificationThread::NOTIFIER_EXIT: + { + CAMHAL_LOGD("Received NOTIFIER_EXIT command from Camera HAL"); + mNotifierState = AppCallbackNotifier::NOTIFIER_EXITED; + ret = false; + break; + } + default: + { + CAMHAL_LOGEA("Error: ProcessMsg() command from Camera HAL"); + break; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; + + +} + +AppCallbackNotifier::~AppCallbackNotifier() +{ + LOG_FUNCTION_NAME; + + ///Stop app callback notifier if not already stopped + stop(); + + ///Unregister with the frame provider + if ( NULL != mFrameProvider ) + { + mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + } + + //unregister with the event provider + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + } + + Utils::Message msg = {0,0,0,0,0,0}; + msg.command = NotificationThread::NOTIFIER_EXIT; + + ///Post the message to display thread + mNotificationThread->msgQ().put(&msg); + + //Exit and cleanup the thread + mNotificationThread->requestExit(); + mNotificationThread->join(); + + //Delete the display thread + mNotificationThread.clear(); + + + ///Free the event and frame providers + if ( NULL != mEventProvider ) + { + ///Deleting the event provider + CAMHAL_LOGDA("Stopping Event Provider"); + delete mEventProvider; + mEventProvider = NULL; + } + + if ( NULL != mFrameProvider ) + { + ///Deleting the frame provider + CAMHAL_LOGDA("Stopping Frame Provider"); + delete mFrameProvider; + mFrameProvider = NULL; + } + + releaseSharedVideoBuffers(); + + LOG_FUNCTION_NAME_EXIT; +} + +//Free all video heaps and buffers +void AppCallbackNotifier::releaseSharedVideoBuffers() +{ + LOG_FUNCTION_NAME; + + if(mUseMetaDataBufferMode) + { + camera_memory_t* videoMedatadaBufferMemory; + for (unsigned int i = 0; i < mVideoMetadataBufferMemoryMap.size(); i++) + { + videoMedatadaBufferMemory = mVideoMetadataBufferMemoryMap.valueAt(i); + if(NULL != videoMedatadaBufferMemory) + { + videoMedatadaBufferMemory->release(videoMedatadaBufferMemory); + CAMHAL_LOGDB("Released videoMedatadaBufferMemory=%p", videoMedatadaBufferMemory); + } + } + + mVideoMetadataBufferMemoryMap.clear(); + mVideoMetadataBufferReverseMap.clear(); + if (mUseVideoBuffers) + { + mVideoMap.clear(); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setEventProvider(int32_t eventMask, MessageNotifier * eventNotifier) +{ + + LOG_FUNCTION_NAME; + ///@remarks There is no NULL check here. We will check + ///for NULL when we get start command from CameraHal + ///@Remarks Currently only one event provider (CameraAdapter) is supported + ///@todo Have an array of event providers for each event bitmask + mEventProvider = new EventProvider(eventNotifier, this, eventCallbackRelay); + if ( NULL == mEventProvider ) + { + CAMHAL_LOGEA("Error in creating EventProvider"); + } + else + { + mEventProvider->enableEventNotification(eventMask); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier) +{ + LOG_FUNCTION_NAME; + ///@remarks There is no NULL check here. We will check + ///for NULL when we get the start command from CameraAdapter + mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay); + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Error in creating FrameProvider"); + } + else + { + //Register only for captured images and RAW for now + //TODO: Register for and handle all types of frames + mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME); + mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t AppCallbackNotifier::startPreviewCallbacks(android::CameraParameters ¶ms, CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count) +{ + unsigned int *bufArr; + int size = 0; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to start video recording without FrameProvider"); + return -EINVAL; + } + + if ( mPreviewing ) + { + CAMHAL_LOGDA("+Already previewing"); + return NO_INIT; + } + + int w,h; + ///Get preview size + params.getPreviewSize(&w, &h); + + // save preview pixel format, size and stride + mPreviewWidth = w; + mPreviewHeight = h; + mPreviewStride = 4096; + mPreviewPixelFormat = CameraHal::getPixelFormatConstant(params.getPreviewFormat()); + size = CameraHal::calculateBufferSize(mPreviewPixelFormat, w, h); + + mPreviewMemory = mRequestMemory(-1, size, AppCallbackNotifier::MAX_BUFFERS, NULL); + if (!mPreviewMemory) { + return NO_MEMORY; + } + + for (int i=0; i < AppCallbackNotifier::MAX_BUFFERS; i++) { + mPreviewBuffers[i].type = CAMERA_BUFFER_MEMORY; + mPreviewBuffers[i].opaque = (unsigned char*) mPreviewMemory->data + (i*size); + mPreviewBuffers[i].mapped = mPreviewBuffers[i].opaque; + } + + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME ) ) { + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_POSTVIEW_FRAME) ) { + mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + } + + mPreviewBufCount = 0; + + mPreviewing = true; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +void AppCallbackNotifier::setBurst(bool burst) +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mBurstLock); + + mBurst = burst; + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::useVideoBuffers(bool useVideoBuffers) +{ + LOG_FUNCTION_NAME; + + mUseVideoBuffers = useVideoBuffers; + + LOG_FUNCTION_NAME_EXIT; +} + +bool AppCallbackNotifier::getUesVideoBuffers() +{ + return mUseVideoBuffers; +} + +void AppCallbackNotifier::setVideoRes(int width, int height) +{ + LOG_FUNCTION_NAME; + + mVideoWidth = width; + mVideoHeight = height; + + LOG_FUNCTION_NAME_EXIT; +} + +status_t AppCallbackNotifier::stopPreviewCallbacks() +{ + LOG_FUNCTION_NAME; + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop preview callbacks without FrameProvider"); + return -EINVAL; + } + + if ( !mPreviewing ) + { + return NO_INIT; + } + + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + mFrameProvider->disableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + + { + android::AutoMutex lock(mLock); + mPreviewMemory->release(mPreviewMemory); + mPreviewMemory = 0; + } + + mPreviewing = false; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::useMetaDataBufferMode(bool enable) +{ + mUseMetaDataBufferMode = enable; + + return NO_ERROR; +} + + +status_t AppCallbackNotifier::startRecording() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mRecordingLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to start video recording without FrameProvider"); + ret = -1; + } + + if(mRecording) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + mFrameProvider->enableFrameNotification(CameraFrame::VIDEO_FRAME_SYNC); + } + + mRecording = true; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//Allocate metadata buffers for video recording +status_t AppCallbackNotifier::initSharedVideoBuffers(CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count, CameraBuffer *vidBufs) +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + if(mUseMetaDataBufferMode) + { + camera_memory_t* videoMedatadaBufferMemory = NULL; + + if(NULL == buffers) + { + CAMHAL_LOGEA("Error! Video buffers are NULL"); + return BAD_VALUE; + } + + for (uint32_t i = 0; i < count; i++) + { + videoMedatadaBufferMemory = mRequestMemory(-1, sizeof(video_metadata_t), 1, NULL); + if((NULL == videoMedatadaBufferMemory) || (NULL == videoMedatadaBufferMemory->data)) + { + CAMHAL_LOGEA("Error! Could not allocate memory for Video Metadata Buffers"); + return NO_MEMORY; + } + + // FIXME remove cast + mVideoMetadataBufferMemoryMap.add((void *)buffers[i].opaque, videoMedatadaBufferMemory); + mVideoMetadataBufferReverseMap.add(videoMedatadaBufferMemory->data, &buffers[i]); + CAMHAL_LOGDB("buffers[%d]=%p, videoMedatadaBufferMemory=%p, videoMedatadaBufferMemory->data=%p", + i, &buffers[i], videoMedatadaBufferMemory, videoMedatadaBufferMemory->data); + + if (vidBufs != NULL) + { + //ASSERT(buffers[i].type == CAMERA_BUFFER_GRALLOC); + // FIXME remove cast + mVideoMap.add((void *)buffers[i].opaque, &vidBufs[i]); + CAMHAL_LOGVB("buffers[%d]=%p, vBuffArr[%d]=%p", i, &buffers[i], i, &vidBufs[i]); + } + } + } + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::stopRecording() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mRecordingLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop video recording without FrameProvider"); + ret = -1; + } + + if(!mRecording) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + mFrameProvider->disableFrameNotification(CameraFrame::VIDEO_FRAME_SYNC); + } + + ///Release the shared video buffers + releaseSharedVideoBuffers(); + + mRecording = false; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::releaseRecordingFrame(const void* mem) +{ + status_t ret = NO_ERROR; + CameraBuffer *frame = NULL; + + LOG_FUNCTION_NAME; + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop video recording without FrameProvider"); + ret = -1; + } + + if ( NULL == mem ) + { + CAMHAL_LOGEA("Video Frame released is invalid"); + ret = -1; + } + + if( NO_ERROR != ret ) + { + return ret; + } + + if(mUseMetaDataBufferMode) + { + video_metadata_t *videoMetadataBuffer = (video_metadata_t *) mem ; + /* FIXME remove cast */ + frame = mVideoMetadataBufferReverseMap.valueFor(videoMetadataBuffer); + CAMHAL_LOGVB("Releasing frame with videoMetadataBuffer=0x%x, videoMetadataBuffer->handle=0x%x & frame handle=0x%x\n", + videoMetadataBuffer, videoMetadataBuffer->handle, frame); + } + else + { + /* FIXME this won't work */ + frame = (CameraBuffer *)(void*)(*((uint32_t *)mem)); + } + + if ( NO_ERROR == ret ) + { + ret = mFrameProvider->returnFrame(frame, CameraFrame::VIDEO_FRAME_SYNC); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::enableMsgType(int32_t msgType) +{ + if( msgType & CAMERA_MSG_PREVIEW_FRAME ) { + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + if( msgType & CAMERA_MSG_POSTVIEW_FRAME ) { + mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + } + + if(msgType & CAMERA_MSG_RAW_IMAGE) { + mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME); + } + + return NO_ERROR; +} + +status_t AppCallbackNotifier::disableMsgType(int32_t msgType) +{ + if( msgType & CAMERA_MSG_PREVIEW_FRAME ) { + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + if( msgType & CAMERA_MSG_POSTVIEW_FRAME ) { + mFrameProvider->disableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + } + + if(msgType & CAMERA_MSG_RAW_IMAGE) { + mFrameProvider->disableFrameNotification(CameraFrame::RAW_FRAME); + } + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::start() +{ + LOG_FUNCTION_NAME; + if(mNotifierState==AppCallbackNotifier::NOTIFIER_STARTED) + { + CAMHAL_LOGDA("AppCallbackNotifier already running"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + ///Check whether initial conditions are met for us to start + ///A frame provider should be available, if not return error + if(!mFrameProvider) + { + ///AppCallbackNotifier not properly initialized + CAMHAL_LOGEA("AppCallbackNotifier not properly initialized - Frame provider is NULL"); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + ///At least one event notifier should be available, if not return error + ///@todo Modify here when there is an array of event providers + if(!mEventProvider) + { + CAMHAL_LOGEA("AppCallbackNotifier not properly initialized - Event provider is NULL"); + LOG_FUNCTION_NAME_EXIT; + ///AppCallbackNotifier not properly initialized + return NO_INIT; + } + + mNotifierState = AppCallbackNotifier::NOTIFIER_STARTED; + CAMHAL_LOGDA(" --> AppCallbackNotifier NOTIFIER_STARTED \n"); + + gEncoderQueue.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::stop() +{ + LOG_FUNCTION_NAME; + + if(mNotifierState!=AppCallbackNotifier::NOTIFIER_STARTED) + { + CAMHAL_LOGDA("AppCallbackNotifier already in stopped state"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + { + android::AutoMutex lock(mLock); + + mNotifierState = AppCallbackNotifier::NOTIFIER_STOPPED; + CAMHAL_LOGDA(" --> AppCallbackNotifier NOTIFIER_STOPPED \n"); + } + + while(!gEncoderQueue.isEmpty()) { + android::sp encoder = gEncoderQueue.valueAt(0); + camera_memory_t* encoded_mem = NULL; + ExifElementsTable* exif = NULL; + + if(encoder.get()) { + encoder->cancel(); + + encoder->getCookies(NULL, (void**) &encoded_mem, (void**) &exif); + if (encoded_mem) { + encoded_mem->release(encoded_mem); + } + if (exif) { + delete exif; + } + + encoder.clear(); + } + gEncoderQueue.removeItemsAt(0); + } + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + + +/*--------------------NotificationHandler Class ENDS here-----------------------------*/ + + + +} // namespace Camera +} // namespace Ti diff --git a/camera/BaseCameraAdapter.cpp b/camera/BaseCameraAdapter.cpp new file mode 100644 index 0000000..dafefb0 --- /dev/null +++ b/camera/BaseCameraAdapter.cpp @@ -0,0 +1,2744 @@ +/* + * 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 "BaseCameraAdapter.h" + +const int EVENT_MASK = 0xffff; + +namespace Ti { +namespace Camera { + +const LUT cameraCommandsUserToHAL[] = { + { "CAMERA_START_PREVIEW", CameraAdapter::CAMERA_START_PREVIEW }, + { "CAMERA_STOP_PREVIEW", CameraAdapter::CAMERA_STOP_PREVIEW }, + { "CAMERA_START_VIDEO", CameraAdapter::CAMERA_START_VIDEO }, + { "CAMERA_STOP_VIDEO", CameraAdapter::CAMERA_STOP_VIDEO }, + { "CAMERA_START_IMAGE_CAPTURE", CameraAdapter::CAMERA_START_IMAGE_CAPTURE }, + { "CAMERA_STOP_IMAGE_CAPTURE", CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE }, + { "CAMERA_PERFORM_AUTOFOCUS", CameraAdapter::CAMERA_PERFORM_AUTOFOCUS }, + { "CAMERA_CANCEL_AUTOFOCUS", CameraAdapter::CAMERA_CANCEL_AUTOFOCUS }, + { "CAMERA_PREVIEW_FLUSH_BUFFERS", CameraAdapter::CAMERA_PREVIEW_FLUSH_BUFFERS }, + { "CAMERA_START_SMOOTH_ZOOM", CameraAdapter::CAMERA_START_SMOOTH_ZOOM }, + { "CAMERA_STOP_SMOOTH_ZOOM", CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM }, + { "CAMERA_USE_BUFFERS_PREVIEW", CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW }, + { "CAMERA_SET_TIMEOUT", CameraAdapter::CAMERA_SET_TIMEOUT }, + { "CAMERA_CANCEL_TIMEOUT", CameraAdapter::CAMERA_CANCEL_TIMEOUT }, + { "CAMERA_START_BRACKET_CAPTURE", CameraAdapter::CAMERA_START_BRACKET_CAPTURE }, + { "CAMERA_STOP_BRACKET_CAPTURE", CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE }, + { "CAMERA_QUERY_RESOLUTION_PREVIEW", CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW }, + { "CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE", CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE }, + { "CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA", CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA }, + { "CAMERA_USE_BUFFERS_IMAGE_CAPTURE", CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE }, + { "CAMERA_USE_BUFFERS_PREVIEW_DATA", CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA }, + { "CAMERA_TIMEOUT_EXPIRED", CameraAdapter::CAMERA_TIMEOUT_EXPIRED }, + { "CAMERA_START_FD", CameraAdapter::CAMERA_START_FD }, + { "CAMERA_STOP_FD", CameraAdapter::CAMERA_STOP_FD }, + { "CAMERA_SWITCH_TO_EXECUTING", CameraAdapter::CAMERA_SWITCH_TO_EXECUTING }, + { "CAMERA_USE_BUFFERS_VIDEO_CAPTURE", CameraAdapter::CAMERA_USE_BUFFERS_VIDEO_CAPTURE }, +#ifdef OMAP_ENHANCEMENT_CPCAM + { "CAMERA_USE_BUFFERS_REPROCESS", CameraAdapter::CAMERA_USE_BUFFERS_REPROCESS }, + { "CAMERA_START_REPROCESS", CameraAdapter::CAMERA_START_REPROCESS }, +#endif +}; + +const LUTtypeHAL CamCommandsLUT = { + sizeof(cameraCommandsUserToHAL)/sizeof(cameraCommandsUserToHAL[0]), + cameraCommandsUserToHAL +}; + +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +BaseCameraAdapter::BaseCameraAdapter() +{ + mReleaseImageBuffersCallback = NULL; + mEndImageCaptureCallback = NULL; + mErrorNotifier = NULL; + mEndCaptureData = NULL; + mReleaseData = NULL; + mRecording = false; + + mPreviewBuffers = NULL; + mPreviewBufferCount = 0; + mPreviewBuffersLength = 0; + + mVideoBuffers = NULL; + mVideoBuffersCount = 0; + mVideoBuffersLength = 0; + + mCaptureBuffers = NULL; + mCaptureBuffersCount = 0; + mCaptureBuffersLength = 0; + + mPreviewDataBuffers = NULL; + mPreviewDataBuffersCount = 0; + mPreviewDataBuffersLength = 0; + + mAdapterState = INTIALIZED_STATE; + + mSharedAllocator = NULL; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + mStartFocus.tv_sec = 0; + mStartFocus.tv_usec = 0; + mStartCapture.tv_sec = 0; + mStartCapture.tv_usec = 0; +#endif + +} + +BaseCameraAdapter::~BaseCameraAdapter() +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mSubscriberLock); + + mFrameSubscribers.clear(); + mImageSubscribers.clear(); + mRawSubscribers.clear(); + mVideoSubscribers.clear(); + mVideoInSubscribers.clear(); + mFocusSubscribers.clear(); + mShutterSubscribers.clear(); + mZoomSubscribers.clear(); + mSnapshotSubscribers.clear(); + mMetadataSubscribers.clear(); + + LOG_FUNCTION_NAME_EXIT; +} + +status_t BaseCameraAdapter::registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mReleaseImageBuffersCallback = callback; + mReleaseData = user_data; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::registerEndCaptureCallback(end_image_capture_callback callback, void *user_data) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mEndImageCaptureCallback= callback; + mEndCaptureData = user_data; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::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; +} + +void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie) +{ + android::AutoMutex lock(mSubscriberLock); + + LOG_FUNCTION_NAME; + + int32_t frameMsg = ((msgs >> MessageNotifier::FRAME_BIT_FIELD_POSITION) & EVENT_MASK); + int32_t eventMsg = ((msgs >> MessageNotifier::EVENT_BIT_FIELD_POSITION) & EVENT_MASK); + + if ( frameMsg != 0 ) + { + CAMHAL_LOGVB("Frame message type id=0x%x subscription request", frameMsg); + switch ( frameMsg ) + { + case CameraFrame::PREVIEW_FRAME_SYNC: + mFrameSubscribers.add((int) cookie, callback); + break; + case CameraFrame::FRAME_DATA_SYNC: + mFrameDataSubscribers.add((int) cookie, callback); + break; + case CameraFrame::SNAPSHOT_FRAME: + mSnapshotSubscribers.add((int) cookie, callback); + break; + case CameraFrame::IMAGE_FRAME: + mImageSubscribers.add((int) cookie, callback); + break; + case CameraFrame::RAW_FRAME: + mRawSubscribers.add((int) cookie, callback); + break; + case CameraFrame::VIDEO_FRAME_SYNC: + mVideoSubscribers.add((int) cookie, callback); + break; + case CameraFrame::REPROCESS_INPUT_FRAME: + mVideoInSubscribers.add((int) cookie, callback); + break; + default: + CAMHAL_LOGEA("Frame message type id=0x%x subscription no supported yet!", frameMsg); + break; + } + } + + if ( eventMsg != 0) + { + CAMHAL_LOGVB("Event message type id=0x%x subscription request", eventMsg); + if ( CameraHalEvent::ALL_EVENTS == eventMsg ) + { + mFocusSubscribers.add((int) cookie, eventCb); + mShutterSubscribers.add((int) cookie, eventCb); + mZoomSubscribers.add((int) cookie, eventCb); + mMetadataSubscribers.add((int) cookie, eventCb); + } + else + { + CAMHAL_LOGEA("Event message type id=0x%x subscription no supported yet!", eventMsg); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void BaseCameraAdapter::disableMsgType(int32_t msgs, void* cookie) +{ + android::AutoMutex lock(mSubscriberLock); + + LOG_FUNCTION_NAME; + + int32_t frameMsg = ((msgs >> MessageNotifier::FRAME_BIT_FIELD_POSITION) & EVENT_MASK); + int32_t eventMsg = ((msgs >> MessageNotifier::EVENT_BIT_FIELD_POSITION) & EVENT_MASK); + + if ( frameMsg != 0 ) + { + CAMHAL_LOGVB("Frame message type id=0x%x remove subscription request", frameMsg); + switch ( frameMsg ) + { + case CameraFrame::PREVIEW_FRAME_SYNC: + mFrameSubscribers.removeItem((int) cookie); + break; + case CameraFrame::FRAME_DATA_SYNC: + mFrameDataSubscribers.removeItem((int) cookie); + break; + case CameraFrame::SNAPSHOT_FRAME: + mSnapshotSubscribers.removeItem((int) cookie); + break; + case CameraFrame::IMAGE_FRAME: + mImageSubscribers.removeItem((int) cookie); + break; + case CameraFrame::RAW_FRAME: + mRawSubscribers.removeItem((int) cookie); + break; + case CameraFrame::VIDEO_FRAME_SYNC: + mVideoSubscribers.removeItem((int) cookie); + break; + case CameraFrame::REPROCESS_INPUT_FRAME: + mVideoInSubscribers.removeItem((int) cookie); + break; + case CameraFrame::ALL_FRAMES: + mFrameSubscribers.removeItem((int) cookie); + mFrameDataSubscribers.removeItem((int) cookie); + mSnapshotSubscribers.removeItem((int) cookie); + mImageSubscribers.removeItem((int) cookie); + mRawSubscribers.removeItem((int) cookie); + mVideoSubscribers.removeItem((int) cookie); + mVideoInSubscribers.removeItem((int) cookie); + break; + default: + CAMHAL_LOGEA("Frame message type id=0x%x subscription remove not supported yet!", frameMsg); + break; + } + } + + if ( eventMsg != 0 ) + { + CAMHAL_LOGVB("Event message type id=0x%x remove subscription request", eventMsg); + if ( CameraHalEvent::ALL_EVENTS == eventMsg) + { + //TODO: Process case by case + mFocusSubscribers.removeItem((int) cookie); + mShutterSubscribers.removeItem((int) cookie); + mZoomSubscribers.removeItem((int) cookie); + mMetadataSubscribers.removeItem((int) cookie); + } + else + { + CAMHAL_LOGEA("Event message type id=0x%x subscription remove not supported yet!", eventMsg); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void BaseCameraAdapter::addFramePointers(CameraBuffer *frameBuf, void *buf) +{ + unsigned int *pBuf = (unsigned int *)buf; + android::AutoMutex lock(mSubscriberLock); + + if ((frameBuf != NULL) && ( pBuf != NULL) ) + { + CameraFrame *frame = new CameraFrame; + frame->mBuffer = frameBuf; + frame->mYuv[0] = pBuf[0]; + frame->mYuv[1] = pBuf[1]; + mFrameQueue.add(frameBuf, frame); + + CAMHAL_LOGVB("Adding Frame=0x%x Y=0x%x UV=0x%x", frame->mBuffer, frame->mYuv[0], frame->mYuv[1]); + } +} + +void BaseCameraAdapter::removeFramePointers() +{ + android::AutoMutex lock(mSubscriberLock); + + int size = mFrameQueue.size(); + CAMHAL_LOGVB("Removing %d Frames = ", size); + for (int i = 0; i < size; i++) + { + CameraFrame *frame = (CameraFrame *)mFrameQueue.valueAt(i); + CAMHAL_LOGVB("Free Frame=0x%x Y=0x%x UV=0x%x", frame->mBuffer, frame->mYuv[0], frame->mYuv[1]); + delete frame; + } + mFrameQueue.clear(); +} + +void BaseCameraAdapter::returnFrame(CameraBuffer * frameBuf, CameraFrame::FrameType frameType) +{ + status_t res = NO_ERROR; + size_t subscriberCount = 0; + int refCount = -1; + + if ( NULL == frameBuf ) + { + CAMHAL_LOGEA("Invalid frameBuf"); + return; + } + + if ( NO_ERROR == res) + { + android::AutoMutex lock(mReturnFrameLock); + + refCount = getFrameRefCountByType(frameBuf, frameType); + + if(frameType == CameraFrame::PREVIEW_FRAME_SYNC) + { + mFramesWithDisplay--; + } + else if(frameType == CameraFrame::VIDEO_FRAME_SYNC) + { + mFramesWithEncoder--; + } + + if ( 0 < refCount ) + { + + refCount--; + setFrameRefCountByType(frameBuf, frameType, refCount); + + if (mRecording) { + refCount += getFrameRefCount(frameBuf); + } + + } + else + { + CAMHAL_LOGDA("Frame returned when ref count is already zero!!"); + return; + } + } + + CAMHAL_LOGVB("REFCOUNT 0x%x %d", frameBuf, refCount); + + if ( NO_ERROR == res ) + { + //check if someone is holding this buffer + if ( 0 == refCount ) + { +#ifdef CAMERAHAL_DEBUG + { + android::AutoMutex locker(mBuffersWithDucatiLock); + if((mBuffersWithDucati.indexOfKey((int)camera_buffer_get_omx_ptr(frameBuf)) >= 0) && + ((CameraFrame::PREVIEW_FRAME_SYNC == frameType) || + (CameraFrame::SNAPSHOT_FRAME == frameType))) + { + CAMHAL_LOGE("Buffer already with Ducati!! 0x%x", frameBuf); + for(int i=0;imBuffers; + mPreviewBuffersLength = desc->mLength; + mPreviewBuffersAvailable.clear(); + mSnapshotBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) + { + mPreviewBuffersAvailable.add(&mPreviewBuffers[i], 0); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) + { + mPreviewBuffersAvailable.add(&mPreviewBuffers[i], 1); + } + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_PREVIEW, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA: + CAMHAL_LOGDA("Use buffers for preview data"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) + { + CAMHAL_LOGEA("Invalid preview data buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + android::AutoMutex lock(mPreviewDataBufferLock); + mPreviewDataBuffers = desc->mBuffers; + mPreviewDataBuffersLength = desc->mLength; + mPreviewDataBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) + { + mPreviewDataBuffersAvailable.add(&mPreviewDataBuffers[i], 0); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) + { + mPreviewDataBuffersAvailable.add(&mPreviewDataBuffers[i], 1); + } + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_MEASUREMENT, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDA("Use buffers for image capture"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) + { + CAMHAL_LOGEA("Invalid capture buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + android::AutoMutex lock(mCaptureBufferLock); + mCaptureBuffers = desc->mBuffers; + mCaptureBuffersLength = desc->mLength; + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_IMAGE_CAPTURE, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + +#ifdef OMAP_ENHANCEMENT_CPCAM + case CameraAdapter::CAMERA_USE_BUFFERS_REPROCESS: + CAMHAL_LOGDA("Use buffers for reprocessing"); + desc = (BuffersDescriptor *) value1; + + if (NULL == desc) { + CAMHAL_LOGEA("Invalid capture buffers!"); + return -EINVAL; + } + + if (ret == NO_ERROR) { + ret = setState(operation); + } + + if (ret == NO_ERROR) { + android::AutoMutex lock(mVideoInBufferLock); + mVideoInBuffers = desc->mBuffers; + mVideoInBuffersAvailable.clear(); + for (uint32_t i = 0 ; i < desc->mMaxQueueable ; i++) { + mVideoInBuffersAvailable.add(&mVideoInBuffers[i], 0); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) { + mVideoInBuffersAvailable.add(&mVideoInBuffers[i], 1); + } + ret = useBuffers(CameraAdapter::CAMERA_REPROCESS, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) { + ret = commitState(); + } else { + ret |= rollbackState(); + } + + break; +#endif + + case CameraAdapter::CAMERA_START_SMOOTH_ZOOM: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startSmoothZoom(value1); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopSmoothZoom(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_PREVIEW: + { + + CAMHAL_LOGDA("Start Preview"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startPreview(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_PREVIEW: + { + + CAMHAL_LOGDA("Stop Preview"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopPreview(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_VIDEO: + { + + CAMHAL_LOGDA("Start video recording"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startVideoCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_VIDEO: + { + + CAMHAL_LOGDA("Stop video recording"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopVideoCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_IMAGE_CAPTURE: + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value1; + if ( NULL != refTimestamp ) + { + memcpy( &mStartCapture, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = takePicture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopImageCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_BRACKET_CAPTURE: + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value2; + if ( NULL != refTimestamp ) + { + memcpy( &mStartCapture, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startBracketing(value1); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopBracketing(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_PERFORM_AUTOFOCUS: + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value1; + if ( NULL != refTimestamp ) + { + memcpy( &mStartFocus, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = autoFocus(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_CANCEL_AUTOFOCUS: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = cancelAutoFocus(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getFrameSize(frame->mWidth, frame->mHeight); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getPictureBufferSize(*frame, value2); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getFrameDataSize(frame->mLength, value2); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_START_FD: + + ret = startFaceDetection(); + + break; + + case CameraAdapter::CAMERA_STOP_FD: + + ret = stopFaceDetection(); + + break; + + case CameraAdapter::CAMERA_USE_BUFFERS_VIDEO_CAPTURE: + + CAMHAL_LOGDA("Use buffers for video (RAW + JPEG) capture"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) { + CAMHAL_LOGEA("Invalid capture buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) { + android::AutoMutex lock(mVideoBufferLock); + mVideoBuffers = desc->mBuffers; + mVideoBuffersLength = desc->mLength; + mVideoBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) { + mVideoBuffersAvailable.add(&mVideoBuffers[i], 1); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) { + mVideoBuffersAvailable.add(&mVideoBuffers[i], 1); + } + } + + if ( NULL != desc ) { + ret = useBuffers(CameraAdapter::CAMERA_VIDEO, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) { + ret = commitState(); + } else { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_SWITCH_TO_EXECUTING: + ret = switchToExecuting(); + break; + +#ifdef OMAP_ENHANCEMENT_VTC + case CameraAdapter::CAMERA_SETUP_TUNNEL: + ret = setupTunnel(value1, value2, value3, value4); + break; + + case CameraAdapter::CAMERA_DESTROY_TUNNEL: + ret = destroyTunnel(); + break; +#endif + + case CameraAdapter::CAMERA_PREVIEW_INITIALIZATION: + ret = cameraPreviewInitialization(); + break; + + default: + CAMHAL_LOGEB("Command 0x%x unsupported!", operation); + break; + }; + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t BaseCameraAdapter::notifyFocusSubscribers(CameraHalEvent::FocusStatus status) +{ + event_callback eventCb; + CameraHalEvent focusEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mFocusSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No Focus Subscribers!"); + return NO_INIT; + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + if (status == CameraHalEvent::FOCUS_STATUS_PENDING) { + gettimeofday(&mStartFocus, NULL); + } else { + //dump the AF latency + CameraHal::PPM("Focus finished in: ", &mStartFocus); + } +#endif + + focusEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == focusEvent.mEventData.get() ) { + return -ENOMEM; + } + + focusEvent.mEventType = CameraHalEvent::EVENT_FOCUS_LOCKED; + focusEvent.mEventData->focusEvent.focusStatus = status; + + for (unsigned int i = 0 ; i < mFocusSubscribers.size(); i++ ) + { + focusEvent.mCookie = (void *) mFocusSubscribers.keyAt(i); + eventCb = (event_callback) mFocusSubscribers.valueAt(i); + eventCb ( &focusEvent ); + } + + focusEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::notifyShutterSubscribers() +{ + CameraHalEvent shutterEvent; + event_callback eventCb; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mShutterSubscribers.size() == 0 ) + { + CAMHAL_LOGEA("No shutter Subscribers!"); + return NO_INIT; + } + + shutterEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == shutterEvent.mEventData.get() ) { + return -ENOMEM; + } + + shutterEvent.mEventType = CameraHalEvent::EVENT_SHUTTER; + shutterEvent.mEventData->shutterEvent.shutterClosed = true; + + for (unsigned int i = 0 ; i < mShutterSubscribers.size() ; i++ ) { + shutterEvent.mCookie = ( void * ) mShutterSubscribers.keyAt(i); + eventCb = ( event_callback ) mShutterSubscribers.valueAt(i); + + CAMHAL_LOGD("Sending shutter callback"); + + eventCb ( &shutterEvent ); + } + + shutterEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::notifyZoomSubscribers(int zoomIdx, bool targetReached) +{ + event_callback eventCb; + CameraHalEvent zoomEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mZoomSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No zoom Subscribers!"); + return NO_INIT; + } + + zoomEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == zoomEvent.mEventData.get() ) { + return -ENOMEM; + } + + zoomEvent.mEventType = CameraHalEvent::EVENT_ZOOM_INDEX_REACHED; + zoomEvent.mEventData->zoomEvent.currentZoomIndex = zoomIdx; + zoomEvent.mEventData->zoomEvent.targetZoomIndexReached = targetReached; + + for (unsigned int i = 0 ; i < mZoomSubscribers.size(); i++ ) { + zoomEvent.mCookie = (void *) mZoomSubscribers.keyAt(i); + eventCb = (event_callback) mZoomSubscribers.valueAt(i); + + eventCb ( &zoomEvent ); + } + + zoomEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::notifyMetadataSubscribers(android::sp &meta) +{ + event_callback eventCb; + CameraHalEvent metaEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mMetadataSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No preview metadata subscribers!"); + return NO_INIT; + } + + metaEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == metaEvent.mEventData.get() ) { + return -ENOMEM; + } + + metaEvent.mEventType = CameraHalEvent::EVENT_METADATA; + metaEvent.mEventData->metadataEvent = meta; + + for (unsigned int i = 0 ; i < mMetadataSubscribers.size(); i++ ) { + metaEvent.mCookie = (void *) mMetadataSubscribers.keyAt(i); + eventCb = (event_callback) mMetadataSubscribers.valueAt(i); + + eventCb ( &metaEvent ); + } + + metaEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame) +{ + status_t ret = NO_ERROR; + unsigned int mask; + + if ( NULL == frame ) + { + CAMHAL_LOGEA("Invalid CameraFrame"); + return -EINVAL; + } + + for( mask = 1; mask < CameraFrame::ALL_FRAMES; mask <<= 1){ + if( mask & frame->mFrameMask ){ + switch( mask ){ + + case CameraFrame::IMAGE_FRAME: + { +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + CameraHal::PPM("Shot to Jpeg: ", &mStartCapture); +#endif + ret = __sendFrameToSubscribers(frame, &mImageSubscribers, CameraFrame::IMAGE_FRAME); + } + break; + case CameraFrame::RAW_FRAME: + { + ret = __sendFrameToSubscribers(frame, &mRawSubscribers, CameraFrame::RAW_FRAME); + } + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + { + ret = __sendFrameToSubscribers(frame, &mFrameSubscribers, CameraFrame::PREVIEW_FRAME_SYNC); + } + break; + case CameraFrame::SNAPSHOT_FRAME: + { + ret = __sendFrameToSubscribers(frame, &mSnapshotSubscribers, CameraFrame::SNAPSHOT_FRAME); + } + break; + case CameraFrame::VIDEO_FRAME_SYNC: + { + ret = __sendFrameToSubscribers(frame, &mVideoSubscribers, CameraFrame::VIDEO_FRAME_SYNC); + } + break; + case CameraFrame::FRAME_DATA_SYNC: + { + ret = __sendFrameToSubscribers(frame, &mFrameDataSubscribers, CameraFrame::FRAME_DATA_SYNC); + } + break; + case CameraFrame::REPROCESS_INPUT_FRAME: + { + ret = __sendFrameToSubscribers(frame, &mVideoInSubscribers, CameraFrame::REPROCESS_INPUT_FRAME); + } + break; + default: + CAMHAL_LOGEB("FRAMETYPE NOT SUPPORTED 0x%x", mask); + break; + }//SWITCH + frame->mFrameMask &= ~mask; + + if (ret != NO_ERROR) { + goto EXIT; + } + }//IF + }//FOR + + EXIT: + return ret; +} + +status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame, + android::KeyedVector *subscribers, + CameraFrame::FrameType frameType) +{ + size_t refCount = 0; + status_t ret = NO_ERROR; + frame_callback callback = NULL; + + frame->mFrameType = frameType; + + if ( (frameType == CameraFrame::PREVIEW_FRAME_SYNC) || + (frameType == CameraFrame::VIDEO_FRAME_SYNC) || + (frameType == CameraFrame::SNAPSHOT_FRAME) ){ + if (mFrameQueue.size() > 0){ + CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(frame->mBuffer); + frame->mYuv[0] = lframe->mYuv[0]; + frame->mYuv[1] = frame->mYuv[0] + (frame->mLength + frame->mOffset)*2/3; + } + else{ + CAMHAL_LOGDA("Empty Frame Queue"); + return -EINVAL; + } + } + + if (NULL != subscribers) { + refCount = getFrameRefCountByType(frame->mBuffer, frameType); + + if (refCount == 0) { + CAMHAL_LOGDA("Invalid ref count of 0"); + return -EINVAL; + } + + if (refCount > subscribers->size()) { + CAMHAL_LOGEB("Invalid ref count for frame type: 0x%x", frameType); + return -EINVAL; + } + + CAMHAL_LOGVB("Type of Frame: 0x%x address: 0x%x refCount start %d", + frame->mFrameType, + ( uint32_t ) frame->mBuffer, + refCount); + + for ( unsigned int i = 0 ; i < refCount; i++ ) { + frame->mCookie = ( void * ) subscribers->keyAt(i); + callback = (frame_callback) subscribers->valueAt(i); + + if (!callback) { + CAMHAL_LOGEB("callback not set for frame type: 0x%x", frameType); + return -EINVAL; + } + + callback(frame); + } + } else { + CAMHAL_LOGEA("Subscribers is null??"); + return -EINVAL; + } + + return ret; +} + +int BaseCameraAdapter::setInitFrameRefCount(CameraBuffer * buf, unsigned int mask) +{ + int ret = NO_ERROR; + unsigned int lmask; + + LOG_FUNCTION_NAME; + + if (buf == NULL) + { + return -EINVAL; + } + + for( lmask = 1; lmask < CameraFrame::ALL_FRAMES; lmask <<= 1){ + if( lmask & mask ){ + switch( lmask ){ + + case CameraFrame::IMAGE_FRAME: + { + setFrameRefCountByType(buf, CameraFrame::IMAGE_FRAME, (int) mImageSubscribers.size()); + } + break; + case CameraFrame::RAW_FRAME: + { + setFrameRefCountByType(buf, CameraFrame::RAW_FRAME, mRawSubscribers.size()); + } + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + { + setFrameRefCountByType(buf, CameraFrame::PREVIEW_FRAME_SYNC, mFrameSubscribers.size()); + } + break; + case CameraFrame::SNAPSHOT_FRAME: + { + setFrameRefCountByType(buf, CameraFrame::SNAPSHOT_FRAME, mSnapshotSubscribers.size()); + } + break; + case CameraFrame::VIDEO_FRAME_SYNC: + { + setFrameRefCountByType(buf,CameraFrame::VIDEO_FRAME_SYNC, mVideoSubscribers.size()); + } + break; + case CameraFrame::FRAME_DATA_SYNC: + { + setFrameRefCountByType(buf, CameraFrame::FRAME_DATA_SYNC, mFrameDataSubscribers.size()); + } + break; + case CameraFrame::REPROCESS_INPUT_FRAME: + { + setFrameRefCountByType(buf,CameraFrame::REPROCESS_INPUT_FRAME, mVideoInSubscribers.size()); + } + break; + default: + CAMHAL_LOGEB("FRAMETYPE NOT SUPPORTED 0x%x", lmask); + break; + }//SWITCH + mask &= ~lmask; + }//IF + }//FOR + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +int BaseCameraAdapter::getFrameRefCount(CameraBuffer * frameBuf) +{ + int res = 0, refCnt = 0; + + for (unsigned int frameType = 1; frameType < CameraFrame::ALL_FRAMES; frameType <<= 1) { + refCnt = getFrameRefCountByType(frameBuf, static_cast(frameType)); + if (refCnt > 0) res += refCnt; + } + return res; +} + +int BaseCameraAdapter::getFrameRefCountByType(CameraBuffer * frameBuf, CameraFrame::FrameType frameType) +{ + int res = -1; + ssize_t index = NAME_NOT_FOUND; + + LOG_FUNCTION_NAME; + + switch (frameType) { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + { + android::AutoMutex lock(mCaptureBufferLock); + index = mCaptureBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mCaptureBuffersAvailable[index]; + } + break; + } + case CameraFrame::SNAPSHOT_FRAME: + { + android::AutoMutex lock(mSnapshotBufferLock); + index = mSnapshotBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mSnapshotBuffersAvailable[index]; + } + break; + } + case CameraFrame::PREVIEW_FRAME_SYNC: + { + android::AutoMutex lock(mPreviewBufferLock); + index = mPreviewBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mPreviewBuffersAvailable[index]; + } + break; + } + case CameraFrame::FRAME_DATA_SYNC: + { + android::AutoMutex lock(mPreviewDataBufferLock); + index = mPreviewDataBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mPreviewDataBuffersAvailable[index]; + } + break; + } + case CameraFrame::VIDEO_FRAME_SYNC: + { + android::AutoMutex lock(mVideoBufferLock); + index = mVideoBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mVideoBuffersAvailable[index]; + } + break; + } + case CameraFrame::REPROCESS_INPUT_FRAME: + { + android::AutoMutex lock(mVideoInBufferLock); + index = mVideoInBuffersAvailable.indexOfKey(frameBuf); + if (index != NAME_NOT_FOUND) { + res = mVideoInBuffersAvailable[index]; + } + break; + } + default: + break; + } + + LOG_FUNCTION_NAME_EXIT; + + return res; +} + +void BaseCameraAdapter::setFrameRefCountByType(CameraBuffer * frameBuf, CameraFrame::FrameType frameType, int refCount) +{ + + LOG_FUNCTION_NAME; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + { + android::AutoMutex lock(mCaptureBufferLock); + mCaptureBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + case CameraFrame::SNAPSHOT_FRAME: + { + android::AutoMutex lock(mSnapshotBufferLock); + mSnapshotBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + { + android::AutoMutex lock(mPreviewBufferLock); + mPreviewBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + case CameraFrame::FRAME_DATA_SYNC: + { + android::AutoMutex lock(mPreviewDataBufferLock); + mPreviewDataBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + case CameraFrame::VIDEO_FRAME_SYNC: + { + android::AutoMutex lock(mVideoBufferLock); + mVideoBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + case CameraFrame::REPROCESS_INPUT_FRAME: { + android::AutoMutex lock(mVideoInBufferLock); + mVideoInBuffersAvailable.replaceValueFor(frameBuf, refCount); + } + break; + default: + break; + }; + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t BaseCameraAdapter::startVideoCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mVideoBufferLock); + + //If the capture is already ongoing, return from here. + if ( mRecording ) + { + ret = NO_INIT; + } + + + if ( NO_ERROR == ret ) + { + + mVideoBuffersAvailable.clear(); + + for ( unsigned int i = 0 ; i < mPreviewBuffersAvailable.size() ; i++ ) + { + mVideoBuffersAvailable.add(mPreviewBuffersAvailable.keyAt(i), 0); + } + + mRecording = true; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopVideoCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( !mRecording ) + { + ret = NO_INIT; + } + + if ( NO_ERROR == ret ) + { + for ( unsigned int i = 0 ; i < mVideoBuffersAvailable.size() ; i++ ) + { + CameraBuffer *frameBuf = mVideoBuffersAvailable.keyAt(i); + if( getFrameRefCountByType(frameBuf, CameraFrame::VIDEO_FRAME_SYNC) > 0) + { + returnFrame(frameBuf, CameraFrame::VIDEO_FRAME_SYNC); + } + } + + mRecording = false; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//-----------------Stub implementation of the interface ------------------------------ + +status_t BaseCameraAdapter::takePicture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopImageCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startBracketing(int range) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::autoFocus() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + notifyFocusSubscribers(CameraHalEvent::FOCUS_STATUS_FAIL); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::cancelAutoFocus() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startSmoothZoom(int targetIdx) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopSmoothZoom() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::useBuffers(CameraMode mode, CameraBuffer* bufArr, int num, size_t length, unsigned int queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::fillThisBuffer(CameraBuffer * frameBuf, CameraFrame::FrameType frameType) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startFaceDetection() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopFaceDetection() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::switchToExecuting() +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +const char* BaseCameraAdapter::getLUTvalue_translateHAL(int Value, LUTtypeHAL LUT) { + int LUTsize = LUT.size; + for(int i = 0; i < LUTsize; i++) + if( LUT.Table[i].halDefinition == Value ) + return LUT.Table[i].userDefinition; + + return NULL; +} + +status_t BaseCameraAdapter::setupTunnel(uint32_t SliceHeight, uint32_t EncoderHandle, uint32_t width, uint32_t height) { + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t BaseCameraAdapter::destroyTunnel() { + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t BaseCameraAdapter::cameraPreviewInitialization() { + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t BaseCameraAdapter::setState(CameraCommands operation) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + const char *printState = getLUTvalue_translateHAL(operation, CamCommandsLUT); + + mLock.lock(); + + switch ( mAdapterState ) + { + + case INTIALIZED_STATE: + + switch ( operation ) + { + + case CAMERA_USE_BUFFERS_PREVIEW: + CAMHAL_LOGDB("Adapter state switch INTIALIZED_STATE->LOADED_PREVIEW_STATE event = %s", + printState); + mNextState = LOADED_PREVIEW_STATE; + break; + + //These events don't change the current state + case CAMERA_QUERY_RESOLUTION_PREVIEW: + case CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + CAMHAL_LOGDB("Adapter state switch INTIALIZED_STATE->INTIALIZED_STATE event = %s", + printState); + mNextState = INTIALIZED_STATE; + break; + case CAMERA_STOP_BRACKET_CAPTURE: + case CAMERA_STOP_IMAGE_CAPTURE: + ret = INVALID_OPERATION; + break; + case CAMERA_CANCEL_AUTOFOCUS: + ret = INVALID_OPERATION; + break; + + default: + CAMHAL_LOGEB("Adapter state switch INTIALIZED_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case LOADED_PREVIEW_STATE: + + switch ( operation ) + { + + case CAMERA_START_PREVIEW: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_STOP_PREVIEW: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW_STATE->INTIALIZED_STATE event = 0x%x", + operation); + mNextState = INTIALIZED_STATE; + break; + + //These events don't change the current state + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + case CAMERA_USE_BUFFERS_PREVIEW_DATA: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW_STATE->LOADED_PREVIEW_STATE event = %s", + printState); + mNextState = LOADED_PREVIEW_STATE; + break; + + default: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case PREVIEW_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_PREVIEW: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->INTIALIZED_STATE event = %s", + printState); + mNextState = INTIALIZED_STATE; + break; + + case CAMERA_PERFORM_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->AF_STATE event = %s", + printState); + mNextState = AF_STATE; + break; + + case CAMERA_START_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->ZOOM_STATE event = %s", + printState); + mNextState = ZOOM_STATE; + break; + + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->LOADED_CAPTURE_STATE event = %s", + printState); + mNextState = LOADED_CAPTURE_STATE; + break; + +#ifdef OMAP_ENHANCEMENT_CPCAM + case CAMERA_USE_BUFFERS_REPROCESS: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->LOADED_REPROCESS_STATE event = %s", + printState); + mNextState = LOADED_REPROCESS_STATE; + break; +#endif + + case CAMERA_START_VIDEO: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->VIDEO_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + case CAMERA_CANCEL_AUTOFOCUS: + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch PREVIEW_ACTIVE->PREVIEW_ACTIVE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_STOP_IMAGE_CAPTURE: + case CAMERA_STOP_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch PREVIEW_ACTIVE->PREVIEW_ACTIVE event = %s", + printState); + ret = INVALID_OPERATION; + break; + + default: + CAMHAL_LOGEB("Adapter state switch PREVIEW_ACTIVE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + +#ifdef OMAP_ENHANCEMENT_CPCAM + case LOADED_REPROCESS_STATE: + switch (operation) { + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_REPROCESS_STATE->LOADED_REPROCESS_CAPTURE_STATE event = %s", + printState); + mNextState = LOADED_REPROCESS_CAPTURE_STATE; + break; + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_REPROCESS_STATE->LOADED_REPROCESS_STATE event = %s", + printState); + mNextState = LOADED_REPROCESS_STATE; + break; + default: + CAMHAL_LOGEB("Adapter state switch LOADED_REPROCESS_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + } + + break; + + case LOADED_REPROCESS_CAPTURE_STATE: + switch (operation) { + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_REPROCESS_CAPTURE_STATE->REPROCESS_STATE event = %s", + printState); + mNextState = REPROCESS_STATE; + break; + default: + CAMHAL_LOGEB("Adapter state switch LOADED_REPROCESS_CAPTURE_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + } + break; +#endif + + case LOADED_CAPTURE_STATE: + + switch ( operation ) + { + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->CAPTURE_STATE event = %s", + printState); + mNextState = CAPTURE_STATE; + break; + + case CAMERA_START_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->BRACKETING_STATE event = %s", + printState); + mNextState = BRACKETING_STATE; + break; + + case CAMERA_USE_BUFFERS_VIDEO_CAPTURE: + //Hadnle this state for raw capture path. + //Just need to keep the same state. + //The next CAMERA_START_IMAGE_CAPTURE command will assign the mNextState. + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->LOADED_CAPTURE_STATE event = %s", + printState); + break; + + default: + CAMHAL_LOGEB("Adapter state switch LOADED_CAPTURE_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case CAPTURE_STATE: + + switch ( operation ) + { + case CAMERA_STOP_IMAGE_CAPTURE: + case CAMERA_STOP_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch CAPTURE_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch CAPTURE_STATE->CAPTURE_STATE event = %s", + printState); + mNextState = CAPTURE_STATE; + break; + +#ifdef OMAP_ENHANCEMENT_CPCAM + case CAMERA_USE_BUFFERS_REPROCESS: + CAMHAL_LOGDB("Adapter state switch CAPTURE_STATE->->LOADED_REPROCESS_STATE event = %s", + printState); + mNextState = LOADED_REPROCESS_STATE; + break; +#endif + + default: + CAMHAL_LOGEB("Adapter state switch CAPTURE_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case BRACKETING_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_IMAGE_CAPTURE: + case CAMERA_STOP_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch BRACKETING_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch BRACKETING_STATE->CAPTURE_STATE event = %s", + printState); + mNextState = CAPTURE_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch BRACKETING_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case AF_STATE: + + switch ( operation ) + { + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch AF_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch AF_STATE->CAPTURE_STATE event = 0x%x", + operation); + mNextState = CAPTURE_STATE; + break; + + case CAMERA_START_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch AF_STATE->AF_ZOOM_STATE event = %s", + printState); + mNextState = AF_ZOOM_STATE; + break; + + case CAMERA_START_VIDEO: + CAMHAL_LOGDB("Adapter state switch AF_STATE->VIDEO_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch AF_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch AF_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = ZOOM_STATE; + break; + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch ZOOM_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_PERFORM_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch ZOOM_STATE->AF_ZOOM_STATE event = %s", + printState); + mNextState = AF_ZOOM_STATE; + break; + + case CAMERA_START_VIDEO: + CAMHAL_LOGDB("Adapter state switch ZOOM_STATE->VIDEO_ZOOM_STATE event = %s", + printState); + mNextState = VIDEO_ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch ZOOM_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_VIDEO: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_PERFORM_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->VIDEO_AF_STATE event = %s", + printState); + mNextState = VIDEO_AF_STATE; + break; + + case CAMERA_START_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->VIDEO_ZOOM_STATE event = %s", + printState); + mNextState = VIDEO_ZOOM_STATE; + break; + + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->VIDEO_LOADED_CAPTURE_STATE event = %s", + printState); + mNextState = VIDEO_LOADED_CAPTURE_STATE; + break; + + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->VIDEO_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch VIDEO_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_AF_STATE: + + switch ( operation ) + { + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch VIDEO_AF_STATE->VIDEO_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch VIDEO_AF_STATE->VIDEO_LOADED_CAPTURE_STATE event = %s", + printState); + mNextState = VIDEO_LOADED_CAPTURE_STATE; + break; + + //This event doesn't change the current state + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch VIDEO_AF_STATE->VIDEO_AF_STATE event = %s", + printState); + mNextState = VIDEO_AF_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch VIDEO_AF_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_LOADED_CAPTURE_STATE: + + switch ( operation ) + { + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->CAPTURE_STATE event = %s", + printState); + mNextState = VIDEO_CAPTURE_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch LOADED_CAPTURE_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_CAPTURE_STATE: + + switch ( operation ) + { + case CAMERA_STOP_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch CAPTURE_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch CAPTURE_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case AF_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch AF_ZOOM_STATE->AF_STATE event = %s", + printState); + mNextState = AF_STATE; + break; + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch AF_ZOOM_STATE->ZOOM_STATE event = %s", + printState); + mNextState = ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch AF_ZOOM_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch VIDEO_ZOOM_STATE->VIDEO_STATE event = %s", + printState); + mNextState = VIDEO_STATE; + break; + + case CAMERA_STOP_VIDEO: + CAMHAL_LOGDB("Adapter state switch VIDEO_ZOOM_STATE->ZOOM_STATE event = %s", + printState); + mNextState = ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch VIDEO_ZOOM_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + + case BRACKETING_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch BRACKETING_ZOOM_STATE->BRACKETING_STATE event = %s", + printState); + mNextState = BRACKETING_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch BRACKETING_ZOOM_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; + +#ifdef OMAP_ENHANCEMENT_CPCAM + case REPROCESS_STATE: + switch (operation) { + case CAMERA_STOP_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch REPROCESS_STATE->PREVIEW_STATE event = %s", + printState); + mNextState = PREVIEW_STATE; + break; + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch REPROCESS_STATE->REPROCESS_STATE event = %s", + printState); + mNextState = REPROCESS_STATE; + break; + case CAMERA_USE_BUFFERS_REPROCESS: + CAMHAL_LOGDB("Adapter state switch REPROCESS_STATE->REPROCESS_STATE event = %s", + printState); + mNextState = LOADED_REPROCESS_STATE; + break; + + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch REPROCESS_STATE->LOADED_CAPTURE_STATE event = %s", + printState); + mNextState = LOADED_CAPTURE_STATE; + break; + default: + CAMHAL_LOGEB("Adapter state switch REPROCESS_STATE Invalid Op! event = %s", + printState); + ret = INVALID_OPERATION; + break; + + } + + break; +#endif + + + default: + CAMHAL_LOGEA("Invalid Adapter state!"); + ret = INVALID_OPERATION; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::rollbackToInitializedState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + while ((getState() != INTIALIZED_STATE) && (ret == NO_ERROR)) { + ret = rollbackToPreviousState(); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::rollbackToPreviousState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + CameraAdapter::AdapterState currentState = getState(); + + switch (currentState) { + case INTIALIZED_STATE: + return NO_ERROR; + + case PREVIEW_STATE: + ret = sendCommand(CAMERA_STOP_PREVIEW); + break; + + case CAPTURE_STATE: +#ifdef OMAP_ENHANCEMENT_CPCAM + case REPROCESS_STATE: +#endif + ret = sendCommand(CAMERA_STOP_IMAGE_CAPTURE); + break; + + case BRACKETING_STATE: + ret = sendCommand(CAMERA_STOP_BRACKET_CAPTURE); + break; + + case AF_STATE: + ret = sendCommand(CAMERA_CANCEL_AUTOFOCUS); + break; + + case ZOOM_STATE: + ret = sendCommand(CAMERA_STOP_SMOOTH_ZOOM); + break; + + case VIDEO_STATE: + ret = sendCommand(CAMERA_STOP_VIDEO); + break; + + case VIDEO_AF_STATE: + ret = sendCommand(CAMERA_CANCEL_AUTOFOCUS); + break; + + case VIDEO_CAPTURE_STATE: + ret = sendCommand(CAMERA_STOP_IMAGE_CAPTURE); + break; + + case AF_ZOOM_STATE: + ret = sendCommand(CAMERA_STOP_SMOOTH_ZOOM); + break; + + case VIDEO_ZOOM_STATE: + ret = sendCommand(CAMERA_STOP_SMOOTH_ZOOM); + break; + + case BRACKETING_ZOOM_STATE: + ret = sendCommand(CAMERA_STOP_SMOOTH_ZOOM); + break; + + default: + CAMHAL_LOGEA("Invalid Adapter state!"); + ret = INVALID_OPERATION; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//State transition finished successfully. +//Commit the state and unlock the adapter state. +status_t BaseCameraAdapter::commitState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mAdapterState = mNextState; + + mLock.unlock(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::rollbackState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mNextState = mAdapterState; + + mLock.unlock(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// getNextState() and getState() +// publicly exposed functions to retrieve the adapter states +// please notice that these functions are locked +CameraAdapter::AdapterState BaseCameraAdapter::getState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME_EXIT; + + return mAdapterState; +} + +CameraAdapter::AdapterState BaseCameraAdapter::getNextState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME_EXIT; + + return mNextState; +} + +// getNextState() and getState() +// internal protected functions to retrieve the adapter states +// please notice that these functions are NOT locked to help +// internal functions query state in the middle of state +// transition +status_t BaseCameraAdapter::getState(AdapterState &state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + state = mAdapterState; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getNextState(AdapterState &state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + state = mNextState; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void BaseCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; +} + +//----------------------------------------------------------------------------- + +extern "C" status_t OMXCameraAdapter_Capabilities( + CameraProperties::Properties * const properties_array, + const int starting_camera, const int max_camera, int & supportedCameras); +extern "C" status_t V4LCameraAdapter_Capabilities( + CameraProperties::Properties * const properties_array, + const int starting_camera, const int max_camera, int & supportedCameras); + +extern "C" status_t CameraAdapter_Capabilities( + CameraProperties::Properties * const properties_array, + const int starting_camera, const int max_camera, int & supportedCameras) +{ + + status_t ret = NO_ERROR; + status_t err = NO_ERROR; + int num_cameras_supported = 0; + + LOG_FUNCTION_NAME; + + supportedCameras = 0; +#ifdef OMX_CAMERA_ADAPTER + //Query OMX cameras + err = OMXCameraAdapter_Capabilities( properties_array, starting_camera, + max_camera, supportedCameras); + if(err != NO_ERROR) { + CAMHAL_LOGEA("error while getting OMXCameraAdapter capabilities"); + ret = UNKNOWN_ERROR; + } +#endif +#ifdef V4L_CAMERA_ADAPTER + //Query V4L cameras + err = V4LCameraAdapter_Capabilities( properties_array, (const int) supportedCameras, + max_camera, num_cameras_supported); + if(err != NO_ERROR) { + CAMHAL_LOGEA("error while getting V4LCameraAdapter capabilities"); + ret = UNKNOWN_ERROR; + } +#endif + + supportedCameras += num_cameras_supported; + CAMHAL_LOGEB("supportedCameras= %d\n", supportedCameras); + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +//----------------------------------------------------------------------------- + +} // namespace Camera +} // namespace Ti + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ + diff --git a/camera/BufferSourceAdapter.cpp b/camera/BufferSourceAdapter.cpp new file mode 100644 index 0000000..3c4e698 --- /dev/null +++ b/camera/BufferSourceAdapter.cpp @@ -0,0 +1,1007 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef OMAP_ENHANCEMENT_CPCAM + +#include "BufferSourceAdapter.h" +#include +#include +#include + +namespace Ti { +namespace Camera { + +static int getANWFormat(const char* parameters_format) +{ + int format = HAL_PIXEL_FORMAT_TI_NV12; + + if (parameters_format != NULL) { + if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + CAMHAL_LOGDA("CbYCrY format selected"); + format = HAL_PIXEL_FORMAT_TI_UYVY; + } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + CAMHAL_LOGDA("YUV420SP format selected"); + format = HAL_PIXEL_FORMAT_TI_NV12; + } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + CAMHAL_LOGDA("RGB565 format selected"); + // TODO(XXX): not defined yet + format = -1; + } else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) { + format = HAL_PIXEL_FORMAT_TI_Y16; + } else { + CAMHAL_LOGDA("Invalid format, NV12 format selected as default"); + format = HAL_PIXEL_FORMAT_TI_NV12; + } + } + + return format; +} + +static int getUsageFromANW(int format) +{ + int usage = GRALLOC_USAGE_SW_READ_RARELY | + GRALLOC_USAGE_SW_WRITE_NEVER; + + switch (format) { + case HAL_PIXEL_FORMAT_TI_NV12: + case HAL_PIXEL_FORMAT_TI_Y16: + case HAL_PIXEL_FORMAT_TI_UYVY: + // This usage flag indicates to gralloc we want the + // buffers to come from system heap + usage |= GRALLOC_USAGE_PRIVATE_0; + break; + default: + // No special flags needed + break; + } + return usage; +} + +static const char* getFormatFromANW(int format) +{ + switch (format) { + case HAL_PIXEL_FORMAT_TI_NV12: + // Assuming NV12 1D is RAW or Image frame + return android::CameraParameters::PIXEL_FORMAT_YUV420SP; + case HAL_PIXEL_FORMAT_TI_Y16: + return android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB; + case HAL_PIXEL_FORMAT_TI_UYVY: + return android::CameraParameters::PIXEL_FORMAT_YUV422I; + default: + break; + } + return android::CameraParameters::PIXEL_FORMAT_YUV420SP; +} + +static CameraFrame::FrameType formatToOutputFrameType(const char* format) { + switch (getANWFormat(format)) { + case HAL_PIXEL_FORMAT_TI_NV12: + case HAL_PIXEL_FORMAT_TI_Y16: + case HAL_PIXEL_FORMAT_TI_UYVY: + // Assuming NV12 1D is RAW or Image frame + return CameraFrame::RAW_FRAME; + default: + break; + } + return CameraFrame::RAW_FRAME; +} + +static int getHeightFromFormat(const char* format, int stride, int size) { + CAMHAL_ASSERT((NULL != format) && (0 <= stride) && (0 <= size)); + switch (getANWFormat(format)) { + case HAL_PIXEL_FORMAT_TI_NV12: + return (size / (3 * stride)) * 2; + case HAL_PIXEL_FORMAT_TI_Y16: + case HAL_PIXEL_FORMAT_TI_UYVY: + return (size / stride) / 2; + default: + break; + } + return 0; +} + +/*--------------------BufferSourceAdapter Class STARTS here-----------------------------*/ + + +///Constant definitions +// TODO(XXX): Temporarily increase number of buffers we can allocate from ANW +// until faux-NPA mode is implemented +const int BufferSourceAdapter::NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP = 15; + +/** + * Display Adapter class STARTS here.. + */ +BufferSourceAdapter::BufferSourceAdapter() : mBufferCount(0) +{ + LOG_FUNCTION_NAME; + + mPixelFormat = NULL; + mBuffers = NULL; + mFrameProvider = NULL; + mBufferSource = NULL; + + mFrameWidth = 0; + mFrameHeight = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +BufferSourceAdapter::~BufferSourceAdapter() +{ + LOG_FUNCTION_NAME; + + freeBufferList(mBuffers); + + android::AutoMutex lock(mLock); + + destroy(); + + if (mFrameProvider) { + // Unregister with the frame provider + mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + delete mFrameProvider; + mFrameProvider = NULL; + } + + if (mQueueFrame.get()) { + mQueueFrame->requestExit(); + mQueueFrame.clear(); + } + + if (mReturnFrame.get()) { + mReturnFrame->requestExit(); + mReturnFrame.clear(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t BufferSourceAdapter::initialize() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mReturnFrame.clear(); + mReturnFrame = new ReturnFrame(this); + mReturnFrame->run(); + + mQueueFrame.clear(); + mQueueFrame = new QueueFrame(this); + mQueueFrame->run(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int BufferSourceAdapter::setPreviewWindow(preview_stream_ops_t *source) +{ + LOG_FUNCTION_NAME; + + if (!source) { + CAMHAL_LOGEA("NULL window object passed to DisplayAdapter"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + if (mBufferSource) { + char id1[OP_STR_SIZE], id2[OP_STR_SIZE]; + status_t ret; + + ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1)); + if (ret != 0) { + CAMHAL_LOGE("Surface::getId returned error %d", ret); + return ret; + } + + ret = extendedOps()->get_id(source, id2, sizeof(id2)); + if (ret != 0) { + CAMHAL_LOGE("Surface::getId returned error %d", ret); + return ret; + } + if ((0 >= strlen(id1)) || (0 >= strlen(id2))) { + CAMHAL_LOGE("Cannot set ST without name: id1:\"%s\" id2:\"%s\"", + id1, id2); + return NOT_ENOUGH_DATA; + } + if (0 == strcmp(id1, id2)) { + return ALREADY_EXISTS; + } + + // client has to unset mBufferSource before being able to set a new one + return BAD_VALUE; + } + + // Move to new source obj + mBufferSource = source; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +bool BufferSourceAdapter::match(const char * str) { + char id1[OP_STR_SIZE]; + status_t ret; + + ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1)); + + if (ret != 0) { + CAMHAL_LOGE("Surface::getId returned error %d", ret); + } + + return strcmp(id1, str) == 0; +} + +int BufferSourceAdapter::setFrameProvider(FrameNotifier *frameProvider) +{ + LOG_FUNCTION_NAME; + + if ( !frameProvider ) { + CAMHAL_LOGEA("NULL passed for frame provider"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + if ( NULL != mFrameProvider ) { + delete mFrameProvider; + } + + mFrameProvider = new FrameProvider(frameProvider, this, frameCallback); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int BufferSourceAdapter::setErrorHandler(ErrorNotifier *errorNotifier) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == errorNotifier ) { + CAMHAL_LOGEA("Invalid Error Notifier reference"); + return -EINVAL; + } + + mErrorNotifier = errorNotifier; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int BufferSourceAdapter::enableDisplay(int width, int height, + struct timeval *refTime) +{ + LOG_FUNCTION_NAME; + CameraFrame::FrameType frameType; + + if (mFrameProvider == NULL) { + // no-op frame provider not set yet + return NO_ERROR; + } + + if (mBufferSourceDirection == BUFFER_SOURCE_TAP_IN) { + // only supporting one type of input frame + frameType = CameraFrame::REPROCESS_INPUT_FRAME; + } else { + frameType = formatToOutputFrameType(mPixelFormat); + } + + mFrameProvider->enableFrameNotification(frameType); + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int BufferSourceAdapter::disableDisplay(bool cancel_buffer) +{ + LOG_FUNCTION_NAME; + + if (mFrameProvider) mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t BufferSourceAdapter::pauseDisplay(bool pause) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + // no-op for BufferSourceAdapter + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +void BufferSourceAdapter::destroy() +{ + LOG_FUNCTION_NAME; + + mBufferCount = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +CameraBuffer* BufferSourceAdapter::allocateBufferList(int width, int dummyHeight, const char* format, + int &bytes, int numBufs) +{ + LOG_FUNCTION_NAME; + status_t err; + int i = -1; + const int lnumBufs = numBufs; + int undequeued = 0; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + + mBuffers = new CameraBuffer [lnumBufs]; + memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs); + + if ( NULL == mBufferSource ) { + return NULL; + } + + int pixFormat = getANWFormat(format); + int usage = getUsageFromANW(pixFormat); + mPixelFormat = CameraHal::getPixelFormatConstant(format); + + // Set gralloc usage bits for window. + err = mBufferSource->set_usage(mBufferSource, usage); + if (err != 0) { + CAMHAL_LOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + + return NULL; + } + + CAMHAL_LOGDB("Number of buffers set to BufferSourceAdapter %d", numBufs); + // Set the number of buffers needed for this buffer source + err = mBufferSource->set_buffer_count(mBufferSource, numBufs); + if (err != 0) { + CAMHAL_LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + + return NULL; + } + + CAMHAL_LOGDB("Configuring %d buffers for ANativeWindow", numBufs); + mBufferCount = numBufs; + + // re-calculate height depending on stride and size + int height = getHeightFromFormat(format, width, bytes); + + // Set window geometry + err = mBufferSource->set_buffers_geometry(mBufferSource, + width, height, + pixFormat); + + if (err != 0) { + CAMHAL_LOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err); + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + return NULL; + } + + if ( mBuffers == NULL ) { + CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers"); + LOG_FUNCTION_NAME_EXIT; + return NULL; + } + + mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued); + + for (i = 0; i < mBufferCount; i++ ) { + buffer_handle_t *handle; + int stride; // dummy variable to get stride + // TODO(XXX): Do we need to keep stride information in camera hal? + + err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride); + + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + goto fail; + } + + CAMHAL_LOGDB("got handle %p", handle); + mBuffers[i].opaque = (void *)handle; + mBuffers[i].type = CAMERA_BUFFER_ANW; + mBuffers[i].format = mPixelFormat; + mFramesWithCameraAdapterMap.add(handle, i); + + bytes = CameraHal::calculateBufferSize(format, width, height); + } + + for( i = 0; i < mBufferCount-undequeued; i++ ) { + void *y_uv[2]; + android::Rect bounds(width, height); + + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque; + mBufferSource->lock_buffer(mBufferSource, handle); + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mBuffers[i].mapped = y_uv[0]; + } + + // return the rest of the buffers back to ANativeWindow + for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++) { + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque; + void *y_uv[2]; + android::Rect bounds(width, height); + + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mBuffers[i].mapped = y_uv[0]; + mapper.unlock(*handle); + + err = mBufferSource->cancel_buffer(mBufferSource, handle); + if (err != 0) { + CAMHAL_LOGEB("cancel_buffer failed: %s (%d)", strerror(-err), -err); + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + goto fail; + } + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[i].opaque); + } + + mFrameWidth = width; + mFrameHeight = height; + mBufferSourceDirection = BUFFER_SOURCE_TAP_OUT; + + return mBuffers; + + fail: + // need to cancel buffers if any were dequeued + for (int start = 0; start < i && i > 0; start++) { + int err = mBufferSource->cancel_buffer(mBufferSource, + (buffer_handle_t *) mBuffers[start].opaque); + if (err != 0) { + CAMHAL_LOGEB("cancelBuffer failed w/ error 0x%08x", err); + break; + } + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[start].opaque); + } + + freeBufferList(mBuffers); + + CAMHAL_LOGEA("Error occurred, performing cleanup"); + + if (NULL != mErrorNotifier.get()) { + mErrorNotifier->errorNotify(-ENOMEM); + } + + LOG_FUNCTION_NAME_EXIT; + return NULL; + +} + +CameraBuffer *BufferSourceAdapter::getBuffers(bool reset) { + int undequeued = 0; + status_t err; + android::Mutex::Autolock lock(mLock); + + if (!mBufferSource || !mBuffers) { + CAMHAL_LOGE("Adapter is not set up properly: " + "mBufferSource:%p mBuffers:%p", + mBufferSource, mBuffers); + goto fail; + } + + // CameraHal is indicating to us that the state of the mBuffer + // might have changed. We might need to check the state of the + // buffer list and pass a new one depending on the state of our + // surface + if (reset) { + const int lnumBufs = mBufferCount; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + android::Rect bounds(mFrameWidth, mFrameHeight); + void *y_uv[2]; + CameraBuffer * newBuffers = NULL; + unsigned int index = 0; + android::KeyedVector missingIndices; + + newBuffers = new CameraBuffer [lnumBufs]; + memset (newBuffers, 0, sizeof(CameraBuffer) * lnumBufs); + + // Use this vector to figure out missing indices + for (int i = 0; i < mBufferCount; i++) { + missingIndices.add(mBuffers[i].opaque, i); + } + + // assign buffers that we have already dequeued + for (index = 0; index < mFramesWithCameraAdapterMap.size(); index++) { + int value = mFramesWithCameraAdapterMap.valueAt(index); + newBuffers[index].opaque = mBuffers[value].opaque; + newBuffers[index].type = mBuffers[value].type; + newBuffers[index].format = mBuffers[value].format; + newBuffers[index].mapped = mBuffers[value].mapped; + mFramesWithCameraAdapterMap.replaceValueAt(index, index); + missingIndices.removeItem(newBuffers[index].opaque); + } + + mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued); + + // dequeue the rest of the buffers + for (index; index < (unsigned int)(mBufferCount-undequeued); index++) { + buffer_handle_t *handle; + int stride; // dummy variable to get stride + + err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride); + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + goto fail; + } + newBuffers[index].opaque = (void *)handle; + newBuffers[index].type = CAMERA_BUFFER_ANW; + newBuffers[index].format = mPixelFormat; + mFramesWithCameraAdapterMap.add(handle, index); + + mBufferSource->lock_buffer(mBufferSource, handle); + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + newBuffers[index].mapped = y_uv[0]; + CAMHAL_LOGDB("got handle %p", handle); + + missingIndices.removeItem(newBuffers[index].opaque); + } + + // now we need to figure out which buffers aren't dequeued + // which are in mBuffers but not newBuffers yet + if ((mBufferCount - index) != missingIndices.size()) { + CAMHAL_LOGD("Hrmm somethings gone awry. We are missing a different number" + " of buffers than we can fill"); + } + for (unsigned int i = 0; i < missingIndices.size(); i++) { + int j = missingIndices.valueAt(i); + + CAMHAL_LOGD("Filling at %d", j); + newBuffers[index].opaque = mBuffers[j].opaque; + newBuffers[index].type = mBuffers[j].type; + newBuffers[index].format = mBuffers[j].format; + newBuffers[index].mapped = mBuffers[j].mapped; + } + + delete [] mBuffers; + mBuffers = newBuffers; + } + + return mBuffers; + + fail: + return NULL; +} + +unsigned int BufferSourceAdapter::getSize() { + android::Mutex::Autolock lock(mLock); + return CameraHal::calculateBufferSize(mPixelFormat, mFrameWidth, mFrameHeight); +} + +int BufferSourceAdapter::getBufferCount() { + int count = -1; + + android::Mutex::Autolock lock(mLock); + if (mBufferSource) extendedOps()->get_buffer_count(mBufferSource, &count); + return count; +} + +CameraBuffer* BufferSourceAdapter::getBufferList(int *num) { + LOG_FUNCTION_NAME; + status_t err; + const int lnumBufs = 1; + int formatSource; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + buffer_handle_t *handle; + + // TODO(XXX): Only supporting one input buffer at a time right now + *num = 1; + mBufferCount = *num; + mBuffers = new CameraBuffer [lnumBufs]; + memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs); + + if ( NULL == mBufferSource ) { + return NULL; + } + + err = extendedOps()->update_and_get_buffer(mBufferSource, + &handle, + &mBuffers[0].stride, + &mBuffers[0].privateData); + if (err != 0) { + CAMHAL_LOGEB("update and get buffer failed: %s (%d)", strerror(-err), -err); + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + goto fail; + } + + CAMHAL_LOGD("got handle %p", handle); + mBuffers[0].opaque = (void *)handle; + mBuffers[0].type = CAMERA_BUFFER_ANW; + mFramesWithCameraAdapterMap.add(handle, 0); + + err = extendedOps()->get_buffer_dimension(mBufferSource, &mBuffers[0].width, &mBuffers[0].height); + err = extendedOps()->get_buffer_format(mBufferSource, &formatSource); + + int t, l, r, b, w, h; + err = extendedOps()->get_crop(mBufferSource, &l, &t, &r, &b); + err = extendedOps()->get_current_size(mBufferSource, &w, &h); + + // lock buffer + { + void *y_uv[2]; + android::Rect bounds(mBuffers[0].width, mBuffers[0].height); + mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + mBuffers[0].mapped = y_uv[0]; + } + + mFrameWidth = mBuffers[0].width; + mFrameHeight = mBuffers[0].height; + mPixelFormat = getFormatFromANW(formatSource); + + mBuffers[0].format = mPixelFormat; + mBuffers[0].actual_size = CameraHal::calculateBufferSize(mPixelFormat, w, h); + mBuffers[0].offset = t * w + l * CameraHal::getBPP(mPixelFormat); + mBufferSourceDirection = BUFFER_SOURCE_TAP_IN; + + return mBuffers; + + fail: + // need to cancel buffers if any were dequeued + freeBufferList(mBuffers); + + if (NULL != mErrorNotifier.get()) { + mErrorNotifier->errorNotify(-ENOMEM); + } + + LOG_FUNCTION_NAME_EXIT; + return NULL; +} + +uint32_t * BufferSourceAdapter::getOffsets() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +int BufferSourceAdapter::minUndequeueableBuffers(int& undequeueable) { + LOG_FUNCTION_NAME; + int ret = NO_ERROR; + + if(!mBufferSource) + { + ret = INVALID_OPERATION; + goto end; + } + + ret = mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeueable); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("get_min_undequeued_buffer_count failed: %s (%d)", strerror(-ret), -ret); + if ( ENODEV == ret ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + return -ret; + } + + end: + return ret; + LOG_FUNCTION_NAME_EXIT; + +} + +int BufferSourceAdapter::maxQueueableBuffers(unsigned int& queueable) +{ + LOG_FUNCTION_NAME; + int ret = NO_ERROR; + int undequeued = 0; + + if(mBufferCount == 0) { + ret = INVALID_OPERATION; + goto end; + } + + ret = minUndequeueableBuffers(undequeued); + if (ret != NO_ERROR) { + goto end; + } + + queueable = mBufferCount - undequeued; + + end: + return ret; + LOG_FUNCTION_NAME_EXIT; +} + +int BufferSourceAdapter::getFd() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return -1; + +} + +status_t BufferSourceAdapter::returnBuffersToWindow() +{ + status_t ret = NO_ERROR; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + + //Give the buffers back to display here - sort of free it + if (mBufferSource) { + for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) { + int value = mFramesWithCameraAdapterMap.valueAt(i); + buffer_handle_t *handle = (buffer_handle_t *) mBuffers[value].opaque; + + // if buffer index is out of bounds skip + if ((value < 0) || (value >= mBufferCount)) { + CAMHAL_LOGEA("Potential out bounds access to handle...skipping"); + continue; + } + + // unlock buffer before giving it up + mapper.unlock(*handle); + + ret = mBufferSource->cancel_buffer(mBufferSource, handle); + if ( ENODEV == ret ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + return -ret; + } else if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("cancel_buffer() failed: %s (%d)", + strerror(-ret), + -ret); + return -ret; + } + } + } else { + CAMHAL_LOGE("mBufferSource is NULL"); + } + + ///Clear the frames with camera adapter map + mFramesWithCameraAdapterMap.clear(); + + return ret; + +} + +int BufferSourceAdapter::freeBufferList(CameraBuffer * buflist) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + + if ( mBuffers != buflist ) { + return BAD_VALUE; + } + + android::AutoMutex lock(mLock); + + if (mBufferSourceDirection == BUFFER_SOURCE_TAP_OUT) returnBuffersToWindow(); + + if( mBuffers != NULL) + { + delete [] mBuffers; + mBuffers = NULL; + } + + return NO_ERROR; +} + + +bool BufferSourceAdapter::supportsExternalBuffering() +{ + return false; +} + +void BufferSourceAdapter::addFrame(CameraFrame* frame) +{ + if (mQueueFrame.get()) { + mQueueFrame->addFrame(frame); + } +} + +void BufferSourceAdapter::handleFrameCallback(CameraFrame* frame) +{ + status_t ret = NO_ERROR; + buffer_handle_t *handle = NULL; + int i; + uint32_t x, y; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + + android::AutoMutex lock(mLock); + + if (!mBuffers || !frame->mBuffer) { + CAMHAL_LOGEA("Adapter sent BufferSourceAdapter a NULL frame?"); + return; + } + + for ( i = 0; i < mBufferCount; i++ ) { + if (frame->mBuffer == &mBuffers[i]) { + break; + } + } + + if (i >= mBufferCount) { + CAMHAL_LOGD("Can't find frame in buffer list"); + if (frame->mFrameType != CameraFrame::REPROCESS_INPUT_FRAME) { + mFrameProvider->returnFrame(frame->mBuffer, + static_cast(frame->mFrameType)); + } + return; + } + + handle = (buffer_handle_t *) mBuffers[i].opaque; + + // Handle input buffers + // TODO(XXX): Move handling of input buffers out of here if + // it becomes more complex + if (frame->mFrameType == CameraFrame::REPROCESS_INPUT_FRAME) { + CAMHAL_LOGD("Unlock %p (buffer #%d)", handle, i); + mapper.unlock(*handle); + extendedOps()->release_buffer(mBufferSource, mBuffers[i].privateData); + return; + } + + CameraHal::getXYFromOffset(&x, &y, frame->mOffset, frame->mAlignment, mPixelFormat); + CAMHAL_LOGVB("offset = %u left = %d top = %d right = %d bottom = %d", + frame->mOffset, x, y, x + frame->mWidth, y + frame->mHeight); + ret = mBufferSource->set_crop(mBufferSource, x, y, x + frame->mWidth, y + frame->mHeight); + if (NO_ERROR != ret) { + CAMHAL_LOGE("mBufferSource->set_crop returned error %d", ret); + goto fail; + } + + if ( NULL != frame->mMetaData.get() ) { + camera_memory_t *extMeta = frame->mMetaData->getExtendedMetadata(); + if ( NULL != extMeta ) { + camera_metadata_t *metaData = static_cast (extMeta->data); + metaData->timestamp = frame->mTimestamp; + ret = extendedOps()->set_metadata(mBufferSource, extMeta); + if (ret != 0) { + CAMHAL_LOGE("Surface::set_metadata returned error %d", ret); + goto fail; + } + } + } + + // unlock buffer before enqueueing + mapper.unlock(*handle); + + ret = mBufferSource->enqueue_buffer(mBufferSource, handle); + if (ret != 0) { + CAMHAL_LOGE("Surface::queueBuffer returned error %d", ret); + goto fail; + } + + mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) frame->mBuffer->opaque); + + return; + +fail: + mFramesWithCameraAdapterMap.clear(); + mBufferSource = NULL; + mReturnFrame->requestExit(); + mQueueFrame->requestExit(); +} + + +bool BufferSourceAdapter::handleFrameReturn() +{ + status_t err; + buffer_handle_t *buf; + int i = 0; + int stride; // dummy variable to get stride + CameraFrame::FrameType type; + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + void *y_uv[2]; + android::Rect bounds(mFrameWidth, mFrameHeight); + + android::AutoMutex lock(mLock); + + if ( (NULL == mBufferSource) || (NULL == mBuffers) ) { + return false; + } + + err = mBufferSource->dequeue_buffer(mBufferSource, &buf, &stride); + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + + return false; + } + + err = mBufferSource->lock_buffer(mBufferSource, buf); + if (err != 0) { + CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err); + + if ( ENODEV == err ) { + CAMHAL_LOGEA("Preview surface abandoned!"); + mBufferSource = NULL; + } + + return false; + } + + mapper.lock(*buf, CAMHAL_GRALLOC_USAGE, bounds, y_uv); + + for(i = 0; i < mBufferCount; i++) { + if (mBuffers[i].opaque == buf) + break; + } + + if (i >= mBufferCount) { + CAMHAL_LOGEB("Failed to find handle %p", buf); + } + + mFramesWithCameraAdapterMap.add((buffer_handle_t *) mBuffers[i].opaque, i); + + CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount - 1); + + mFrameProvider->returnFrame(&mBuffers[i], formatToOutputFrameType(mPixelFormat)); + return true; +} + +void BufferSourceAdapter::frameCallback(CameraFrame* caFrame) +{ + if ((NULL != caFrame) && (NULL != caFrame->mCookie)) { + BufferSourceAdapter *da = (BufferSourceAdapter*) caFrame->mCookie; + da->addFrame(caFrame); + } else { + CAMHAL_LOGEB("Invalid Cookie in Camera Frame = %p, Cookie = %p", + caFrame, caFrame ? caFrame->mCookie : NULL); + } +} + +/*--------------------BufferSourceAdapter Class ENDS here-----------------------------*/ + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/CameraHal.cpp b/camera/CameraHal.cpp new file mode 100644 index 0000000..7e7cf9d --- /dev/null +++ b/camera/CameraHal.cpp @@ -0,0 +1,5012 @@ +/* + * 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. + */ + +/** +* @file CameraHal.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + +#include "CameraHal.h" +#include "ANativeWindowDisplayAdapter.h" +#include "BufferSourceAdapter.h" +#include "TICameraParameters.h" +#include "CameraProperties.h" +#include + +#include +#include + +namespace Ti { +namespace Camera { + +extern "C" CameraAdapter* OMXCameraAdapter_Factory(size_t); +extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t, CameraHal*); + +/*****************************************************************************/ + +////Constant definitions and declarations +////@todo Have a CameraProperties class to store these parameters as constants for every camera +//// Currently, they are hard-coded + +const int CameraHal::NO_BUFFERS_PREVIEW = MAX_CAMERA_BUFFERS; +const int CameraHal::NO_BUFFERS_IMAGE_CAPTURE = 5; +const int CameraHal::SW_SCALING_FPS_LIMIT = 15; + +const uint32_t MessageNotifier::EVENT_BIT_FIELD_POSITION = 16; + +const uint32_t MessageNotifier::FRAME_BIT_FIELD_POSITION = 0; + +// TODO(XXX): Temporarily increase number of buffers we can allocate from ANW +// until faux-NPA mode is implemented +const int CameraHal::NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP = 15; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING +// HACK: Default path to directory where RAW images coming from video port will be saved to. +// If directory not exists the saving is skipped and video port frame is ignored. +// The directory name is choosed in so weird way to enable RAW images saving only when +// directory has been created explicitly by user. +extern const char * const kRawImagesOutputDirPath = "/data/misc/camera/RaW_PiCtUrEs"; +extern const char * const kYuvImagesOutputDirPath = "/data/misc/camera/YuV_PiCtUrEs"; +#endif + +/******************************************************************************/ + + +#ifdef OMAP_ENHANCEMENT_CPCAM +static int dummy_update_and_get_buffer(preview_stream_ops_t*, buffer_handle_t**, int*,int*) { + return INVALID_OPERATION; +} + +static int dummy_release_buffer(preview_stream_ops_t*, int slot) { + return INVALID_OPERATION; +} + +static int dummy_get_buffer_dimension(preview_stream_ops_t*, int*, int*) { + return INVALID_OPERATION; +} + +static int dummy_get_buffer_format(preview_stream_ops_t*, int*) { + return INVALID_OPERATION; +} + +static int dummy_set_metadata(preview_stream_ops_t*, const camera_memory_t*) { + return INVALID_OPERATION; +} + +static int dummy_get_id(preview_stream_ops_t*, char *data, unsigned int dataSize) { + return INVALID_OPERATION; +} + +static int dummy_get_buffer_count(preview_stream_ops_t*, int *count) { + return INVALID_OPERATION; +} + +static int dummy_get_crop(preview_stream_ops_t*, + int *, int *, int *, int *) { + return INVALID_OPERATION; +} + +static int dummy_get_current_size(preview_stream_ops_t*, + int *, int *) { + return INVALID_OPERATION; +} +#endif + + +CameraHal::SocFamily CameraHal::getSocFamily() { + static const struct { + const char *name; + const CameraHal::SocFamily value; + } socFamilyArray[] = { + {"OMAP4430", SocFamily_Omap4430}, + {"OMAP4460", SocFamily_Omap4460}, + {"OMAP4470", SocFamily_Omap4470} + }; + // lets get the soc family string from sysfs + static const char *sysfsNode = "/sys/board_properties/soc/family"; + FILE *sysfsFd = fopen(sysfsNode, "r"); + static const int bufSize = 128; + char buf[bufSize]; + if (sysfsFd == NULL) { + CAMHAL_LOGEA("'%s' Not Available", sysfsNode); + return SocFamily_Undefined; + } + const char *res = fgets(buf, bufSize, sysfsFd); + fclose(sysfsFd); + if (res == NULL) { + CAMHAL_LOGEA("Error reading '%s'", sysfsNode); + return SocFamily_Undefined; + } + // translate it to CameraHal::SocFamily enum + for (int i = 0; i < SocFamily_ElementCount; ++i) { + if (strncmp(socFamilyArray[i].name, buf, strlen(socFamilyArray[i].name)) == 0) { + return socFamilyArray[i].value; + } + } + return SocFamily_Undefined; +} + + +#ifdef OMAP_ENHANCEMENT_CPCAM +static preview_stream_extended_ops_t dummyPreviewStreamExtendedOps = { +#ifdef OMAP_ENHANCEMENT_CPCAM + dummy_update_and_get_buffer, + dummy_release_buffer, + dummy_get_buffer_dimension, + dummy_get_buffer_format, + dummy_set_metadata, + dummy_get_id, + dummy_get_buffer_count, + dummy_get_crop, + dummy_get_current_size, +#endif +}; +#endif + + +DisplayAdapter::DisplayAdapter() +{ +#ifdef OMAP_ENHANCEMENT_CPCAM + mExtendedOps = &dummyPreviewStreamExtendedOps; +#endif +} + +#ifdef OMAP_ENHANCEMENT_CPCAM +void DisplayAdapter::setExtendedOps(preview_stream_extended_ops_t * extendedOps) { + mExtendedOps = extendedOps ? extendedOps : &dummyPreviewStreamExtendedOps; +} +#endif + + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +struct timeval CameraHal::mStartPreview; +struct timeval CameraHal::mStartFocus; +struct timeval CameraHal::mStartCapture; + +#endif + +static void orientation_cb(uint32_t orientation, uint32_t tilt, void* cookie) { + CameraHal *camera = NULL; + + if (cookie) { + camera = (CameraHal*) cookie; + camera->onOrientationEvent(orientation, tilt); + } + +} + +/*-------------Camera Hal Interface Method definitions STARTS here--------------------*/ + +/** + Callback function to receive orientation events from SensorListener + */ +void CameraHal::onOrientationEvent(uint32_t orientation, uint32_t tilt) { + LOG_FUNCTION_NAME; + + if ( NULL != mCameraAdapter ) { + mCameraAdapter->onOrientationEvent(orientation, tilt); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Set the notification and data callbacks + + @param[in] notify_cb Notify callback for notifying the app about events and errors + @param[in] data_cb Buffer callback for sending the preview/raw frames to the app + @param[in] data_cb_timestamp Buffer callback for sending the video frames w/ timestamp + @param[in] user Callback cookie + @return none + + */ +void CameraHal::setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + LOG_FUNCTION_NAME; + + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setCallbacks(this, + notify_cb, + data_cb, + data_cb_timestamp, + get_memory, + user); + } + + if ( NULL != mCameraAdapter ) { + mCameraAdapter->setSharedAllocator(get_memory); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Enable a message, or set of messages. + + @param[in] msgtype Bitmask of the messages to enable (defined in include/ui/Camera.h) + @return none + + */ +void CameraHal::enableMsgType(int32_t msgType) +{ + LOG_FUNCTION_NAME; + + if ( ( msgType & CAMERA_MSG_SHUTTER ) && ( !mShutterEnabled ) ) + { + msgType &= ~CAMERA_MSG_SHUTTER; + } + + // ignoring enable focus message from camera service + // we will enable internally in autoFocus call + msgType &= ~CAMERA_MSG_FOCUS; +#ifdef ANDROID_API_JB_OR_LATER + msgType &= ~CAMERA_MSG_FOCUS_MOVE; +#endif + + { + android::AutoMutex lock(mLock); + mMsgEnabled |= msgType; + } + + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + { + if(mDisplayPaused) + { + CAMHAL_LOGDA("Preview currently paused...will enable preview callback when restarted"); + msgType &= ~CAMERA_MSG_PREVIEW_FRAME; + }else + { + CAMHAL_LOGDA("Enabling Preview Callback"); + } + } + else + { + CAMHAL_LOGDB("Preview callback not enabled %x", msgType); + } + + + ///Configure app callback notifier with the message callback required + mAppCallbackNotifier->enableMsgType (msgType); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Disable a message, or set of messages. + + @param[in] msgtype Bitmask of the messages to disable (defined in include/ui/Camera.h) + @return none + + */ +void CameraHal::disableMsgType(int32_t msgType) +{ + LOG_FUNCTION_NAME; + + { + android::AutoMutex lock(mLock); + mMsgEnabled &= ~msgType; + } + + if( msgType & CAMERA_MSG_PREVIEW_FRAME) + { + CAMHAL_LOGDA("Disabling Preview Callback"); + } + + ///Configure app callback notifier + mAppCallbackNotifier->disableMsgType (msgType); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Query whether a message, or a set of messages, is enabled. + + Note that this is operates as an AND, if any of the messages queried are off, this will + return false. + + @param[in] msgtype Bitmask of the messages to query (defined in include/ui/Camera.h) + @return true If all message types are enabled + false If any message type + + */ +int CameraHal::msgTypeEnabled(int32_t msgType) +{ + int32_t msgEnabled = 0; + + LOG_FUNCTION_NAME; + android::AutoMutex lock(mLock); + + msgEnabled = mMsgEnabled; + if (!previewEnabled() && !mPreviewInitializationDone) { + msgEnabled &= ~(CAMERA_MSG_PREVIEW_FRAME | CAMERA_MSG_PREVIEW_METADATA); + } + + LOG_FUNCTION_NAME_EXIT; + return (msgEnabled & msgType); +} + +/** + @brief Set the camera parameters. + + @param[in] params Camera parameters to configure the camera + @return NO_ERROR + @todo Define error codes + + */ +int CameraHal::setParameters(const char* parameters) +{ + + LOG_FUNCTION_NAME; + + android::CameraParameters params; + + android::String8 str_params(parameters); + params.unflatten(str_params); + + LOG_FUNCTION_NAME_EXIT; + + return setParameters(params); +} + +/** + @brief Set the camera parameters. + + @param[in] params Camera parameters to configure the camera + @return NO_ERROR + @todo Define error codes + + */ +int CameraHal::setParameters(const android::CameraParameters& params) +{ + + LOG_FUNCTION_NAME; + + int w, h; + int framerate; + const char *valstr = NULL; + int varint = 0; + status_t ret = NO_ERROR; + // Needed for KEY_RECORDING_HINT + bool restartPreviewRequired = false; + bool updateRequired = false; + android::CameraParameters oldParams = mParameters; +#ifdef MOTOROLA_CAMERA + char value[PROPERTY_VALUE_MAX]; +#endif + +#ifdef V4L_CAMERA_ADAPTER + if (strcmp (V4L_CAMERA_NAME_USB, mCameraProperties->get(CameraProperties::CAMERA_NAME)) == 0 ) { + updateRequired = true; + } +#endif + + { + android::AutoMutex lock(mLock); + + ///Ensure that preview is not enabled when the below parameters are changed. + if(!previewEnabled()) + { + if ((valstr = params.getPreviewFormat()) != NULL) { + if ( isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS))) { + mParameters.setPreviewFormat(valstr); + CAMHAL_LOGDB("PreviewFormat set %s", valstr); + } else { + CAMHAL_LOGEB("Invalid preview format: %s. Supported: %s", valstr, + mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS)); + return BAD_VALUE; + } + } + + if ((valstr = params.get(TICameraParameters::KEY_VNF)) != NULL) { + if (strcmp(mCameraProperties->get(CameraProperties::VNF_SUPPORTED), + android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGDB("VNF %s", valstr); + mParameters.set(TICameraParameters::KEY_VNF, valstr); + } else if (strcmp(valstr, android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGEB("ERROR: Invalid VNF: %s", valstr); + return BAD_VALUE; + } else { + mParameters.set(TICameraParameters::KEY_VNF, + android::CameraParameters::FALSE); + } + } + + if ((valstr = params.get(android::CameraParameters::KEY_VIDEO_STABILIZATION)) != NULL) { + // make sure we support vstab...if we don't and application is trying to set + // vstab then return an error + if (strcmp(mCameraProperties->get(CameraProperties::VSTAB_SUPPORTED), + android::CameraParameters::TRUE) != 0 && + strcmp(valstr, android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGEB("ERROR: Invalid VSTAB: %s", valstr); + return BAD_VALUE; + } + } + + if( (valstr = params.get(TICameraParameters::KEY_CAP_MODE)) != NULL) { + + if (strcmp(TICameraParameters::VIDEO_MODE, valstr)) { + mCapModeBackup = valstr; + } + + CAMHAL_LOGDB("Capture mode set %s", valstr); + + const char *currentMode = mParameters.get(TICameraParameters::KEY_CAP_MODE); + if ( NULL != currentMode ) { + if ( strcmp(currentMode, valstr) != 0 ) { + updateRequired = true; + } + } else { + updateRequired = true; + } + + mParameters.set(TICameraParameters::KEY_CAP_MODE, valstr); + } else if (!mCapModeBackup.isEmpty()) { + // Restore previous capture mode after stopPreview() + mParameters.set(TICameraParameters::KEY_CAP_MODE, + mCapModeBackup.string()); + updateRequired = true; + } + +#ifdef OMAP_ENHANCEMENT_VTC + if ((valstr = params.get(TICameraParameters::KEY_VTC_HINT)) != NULL ) { + mParameters.set(TICameraParameters::KEY_VTC_HINT, valstr); + if (strcmp(valstr, android::CameraParameters::TRUE) == 0) { + mVTCUseCase = true; + } else { + mVTCUseCase = false; + } + CAMHAL_LOGDB("VTC Hint = %d", mVTCUseCase); + } + + if (mVTCUseCase) { + if ((valstr = params.get(TICameraParameters::KEY_VIDEO_ENCODER_HANDLE)) != NULL ) { + mParameters.set(TICameraParameters::KEY_VIDEO_ENCODER_HANDLE, valstr); + } + + if ((valstr = params.get(TICameraParameters::KEY_VIDEO_ENCODER_SLICE_HEIGHT)) != NULL ) { + mParameters.set(TICameraParameters::KEY_VIDEO_ENCODER_SLICE_HEIGHT, valstr); + } + } +#endif + } + + if ((valstr = params.get(TICameraParameters::KEY_IPP)) != NULL) { + if (isParameterValid(valstr,mCameraProperties->get(CameraProperties::SUPPORTED_IPP_MODES))) { + if ((mParameters.get(TICameraParameters::KEY_IPP) == NULL) || + (strcmp(valstr, mParameters.get(TICameraParameters::KEY_IPP)))) { + CAMHAL_LOGDB("IPP mode set %s", params.get(TICameraParameters::KEY_IPP)); + mParameters.set(TICameraParameters::KEY_IPP, valstr); + restartPreviewRequired = true; + } + } else { + CAMHAL_LOGEB("ERROR: Invalid IPP mode: %s", valstr); + return BAD_VALUE; + } + } + + if ( (valstr = params.get(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT)) != NULL ) + { + if (strcmp(valstr, mParameters.get(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT))) + { + CAMHAL_LOGDB("Stereo 3D preview image layout is %s", valstr); + mParameters.set(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT, valstr); + restartPreviewRequired = true; + } + } + +#ifdef OMAP_ENHANCEMENT + int orientation =0; + if((valstr = params.get(TICameraParameters::KEY_SENSOR_ORIENTATION)) != NULL) + { + doesSetParameterNeedUpdate(valstr, + mParameters.get(TICameraParameters::KEY_SENSOR_ORIENTATION), + updateRequired); + + orientation = params.getInt(TICameraParameters::KEY_SENSOR_ORIENTATION); + if ( orientation < 0 || orientation >= 360 || (orientation%90) != 0 ) { + CAMHAL_LOGE("Invalid sensor orientation: %s. Value must be one of: [0, 90, 180, 270]", valstr); + return BAD_VALUE; + } + + CAMHAL_LOGD("Sensor Orientation is set to %d", orientation); + mParameters.set(TICameraParameters::KEY_SENSOR_ORIENTATION, valstr); + } +#endif + + params.getPreviewSize(&w, &h); + if (w == -1 && h == -1) { + CAMHAL_LOGEA("Unable to get preview size"); + return BAD_VALUE; + } + + mVideoWidth = w; + mVideoHeight = h; + + // Handle RECORDING_HINT to Set/Reset Video Mode Parameters + valstr = params.get(android::CameraParameters::KEY_RECORDING_HINT); + if(valstr != NULL) + { + CAMHAL_LOGDB("Recording Hint is set to %s", valstr); + if(strcmp(valstr, android::CameraParameters::TRUE) == 0) + { + CAMHAL_LOGVB("Video Resolution: %d x %d", mVideoWidth, mVideoHeight); + mParameters.set(android::CameraParameters::KEY_RECORDING_HINT, valstr); + restartPreviewRequired |= setVideoModeParameters(params); + } + else if(strcmp(valstr, android::CameraParameters::FALSE) == 0) + { + mParameters.set(android::CameraParameters::KEY_RECORDING_HINT, valstr); + restartPreviewRequired |= resetVideoModeParameters(); + } + else + { + CAMHAL_LOGEA("Invalid RECORDING_HINT"); + return BAD_VALUE; + } + } + else + { + // This check is required in following case. + // If VideoRecording activity sets KEY_RECORDING_HINT to TRUE and + // ImageCapture activity doesnot set KEY_RECORDING_HINT to FALSE (i.e. simply NULL), + // then Video Mode parameters may remain present in ImageCapture activity as well. + CAMHAL_LOGDA("Recording Hint is set to NULL"); + mParameters.set(android::CameraParameters::KEY_RECORDING_HINT, ""); + restartPreviewRequired |= resetVideoModeParameters(); + } + + if ( (!isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIZES))) + && (!isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES))) + && (!isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES))) + && (!isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES))) ) { + CAMHAL_LOGEB("Invalid preview resolution %d x %d", w, h); + return BAD_VALUE; + } + + int oldWidth, oldHeight; + mParameters.getPreviewSize(&oldWidth, &oldHeight); + if ( ( oldWidth != w ) || ( oldHeight != h ) ) + { + mParameters.setPreviewSize(w, h); + restartPreviewRequired = true; + } + + CAMHAL_LOGDB("Preview Resolution: %d x %d", w, h); + + if ((valstr = params.get(android::CameraParameters::KEY_FOCUS_MODE)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_FOCUS_MODES))) { + CAMHAL_LOGDB("Focus mode set %s", valstr); + + // we need to take a decision on the capture mode based on whether CAF picture or + // video is chosen so the behavior of each is consistent to the application + if(strcmp(valstr, android::CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) == 0){ + restartPreviewRequired |= resetVideoModeParameters(); + } else if (strcmp(valstr, android::CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO) == 0){ + restartPreviewRequired |= setVideoModeParameters(params); + } + + mParameters.set(android::CameraParameters::KEY_FOCUS_MODE, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid FOCUS mode = %s", valstr); + return BAD_VALUE; + } + } + + mRawCapture = false; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + valstr = params.get(TICameraParameters::KEY_CAP_MODE); + if ( (!valstr || strcmp(valstr, TICameraParameters::HIGH_QUALITY_MODE) == 0) && + access(kRawImagesOutputDirPath, F_OK) != -1 ) { + mRawCapture = true; + } +#endif + + if ( (valstr = params.get(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT)) != NULL ) + { + CAMHAL_LOGDB("Stereo 3D capture image layout is %s", valstr); + mParameters.set(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT, valstr); + } + + params.getPictureSize(&w, &h); + if ( (isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIZES))) + || (isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES))) + || (isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES))) + || (isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES))) ) { + mParameters.setPictureSize(w, h); + } else { + CAMHAL_LOGEB("ERROR: Invalid picture resolution %d x %d", w, h); + return BAD_VALUE; + } + + CAMHAL_LOGDB("Picture Size by App %d x %d", w, h); + + if ( (valstr = params.getPictureFormat()) != NULL ) { + if (isParameterValid(valstr,mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_FORMATS))) { + if ((strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) && + mCameraProperties->get(CameraProperties::MAX_PICTURE_WIDTH) && + mCameraProperties->get(CameraProperties::MAX_PICTURE_HEIGHT)) { + unsigned int width = 0, height = 0; + // Set picture size to full frame for raw bayer capture + width = atoi(mCameraProperties->get(CameraProperties::MAX_PICTURE_WIDTH)); + height = atoi(mCameraProperties->get(CameraProperties::MAX_PICTURE_HEIGHT)); + mParameters.setPictureSize(width,height); + } + mParameters.setPictureFormat(valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid picture format: %s",valstr); + ret = BAD_VALUE; + } + } + +#ifdef OMAP_ENHANCEMENT_BURST_CAPTURE + if ((valstr = params.get(TICameraParameters::KEY_BURST)) != NULL) { + if (params.getInt(TICameraParameters::KEY_BURST) >=0) { + CAMHAL_LOGDB("Burst set %s", valstr); + mParameters.set(TICameraParameters::KEY_BURST, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Burst value: %s",valstr); + return BAD_VALUE; + } + } +#endif + + // Variable framerate ranges have higher priority over + // deprecated constant FPS. + // There is possible 3 situations : + // 1) User change FPS range and HAL use it for fps port value (don't care about + // changed or not const FPS). + // 2) User change single FPS and not change FPS range - will be applyed single FPS value + // to port. + // 3) Both FPS range and const FPS are unchanged - FPS range will be applied to port. + + int curFramerate = 0; + bool frameRangeUpdated = false, fpsUpdated = false; + int curMaxFPS = 0, curMinFPS = 0, maxFPS = 0, minFPS = 0; + + mParameters.getPreviewFpsRange(&curMinFPS, &curMaxFPS); + params.getPreviewFpsRange(&minFPS, &maxFPS); + + curFramerate = mParameters.getPreviewFrameRate(); + framerate = params.getPreviewFrameRate(); + + valstr = params.get(android::CameraParameters::KEY_PREVIEW_FPS_RANGE); + if (valstr != NULL && strlen(valstr) && + ((curMaxFPS != maxFPS) || (curMinFPS != minFPS))) { + CAMHAL_LOGDB("## current minFPS = %d; maxFPS=%d", curMinFPS, curMaxFPS); + CAMHAL_LOGDB("## requested minFPS = %d; maxFPS=%d", minFPS, maxFPS); + if (!isFpsRangeValid(minFPS, maxFPS, params.get(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE)) && + !isFpsRangeValid(minFPS, maxFPS, params.get(TICameraParameters::KEY_FRAMERATE_RANGES_EXT_SUPPORTED))) { + CAMHAL_LOGEA("Trying to set invalid FPS Range (%d,%d)", minFPS, maxFPS); + return BAD_VALUE; + } + mParameters.set(android::CameraParameters::KEY_PREVIEW_FPS_RANGE, valstr); + CAMHAL_LOGDB("FPS Range = %s", valstr); + if ( curMaxFPS == (FRAME_RATE_HIGH_HD * CameraHal::VFR_SCALE) && + maxFPS < (FRAME_RATE_HIGH_HD * CameraHal::VFR_SCALE) ) { + restartPreviewRequired = true; + } + frameRangeUpdated = true; + } + + valstr = params.get(android::CameraParameters::KEY_PREVIEW_FRAME_RATE); + if (valstr != NULL && strlen(valstr) && (framerate != curFramerate)) { + CAMHAL_LOGD("current framerate = %d reqested framerate = %d", curFramerate, framerate); + if (!isParameterValid(framerate, params.get(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)) && + !isParameterValid(framerate, params.get(TICameraParameters::KEY_FRAMERATES_EXT_SUPPORTED))) { + CAMHAL_LOGEA("Trying to set invalid frame rate %d", framerate); + return BAD_VALUE; + } + mParameters.setPreviewFrameRate(framerate); + CAMHAL_LOGDB("Set frame rate %d", framerate); + fpsUpdated = true; + } + + if (frameRangeUpdated) { + mParameters.set(TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE, + mParameters.get(android::CameraParameters::KEY_PREVIEW_FPS_RANGE)); + } else if (fpsUpdated) { + char tmpBuffer[MAX_PROP_VALUE_LENGTH]; + sprintf(tmpBuffer, "%d,%d", framerate * CameraHal::VFR_SCALE, framerate * CameraHal::VFR_SCALE); + mParameters.set(TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE, tmpBuffer); + } + + if ((valstr = params.get(TICameraParameters::KEY_GBCE)) != NULL) { + if (strcmp(mCameraProperties->get(CameraProperties::SUPPORTED_GBCE), + android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGDB("GBCE %s", valstr); + mParameters.set(TICameraParameters::KEY_GBCE, valstr); + } else if (strcmp(valstr, android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGEB("ERROR: Invalid GBCE: %s", valstr); + return BAD_VALUE; + } else { + mParameters.set(TICameraParameters::KEY_GBCE, android::CameraParameters::FALSE); + } + } else { + mParameters.set(TICameraParameters::KEY_GBCE, android::CameraParameters::FALSE); + } + + if ((valstr = params.get(TICameraParameters::KEY_GLBCE)) != NULL) { + if (strcmp(mCameraProperties->get(CameraProperties::SUPPORTED_GLBCE), + android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGDB("GLBCE %s", valstr); + mParameters.set(TICameraParameters::KEY_GLBCE, valstr); + } else if (strcmp(valstr, android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGEB("ERROR: Invalid GLBCE: %s", valstr); + return BAD_VALUE; + } else { + mParameters.set(TICameraParameters::KEY_GLBCE, android::CameraParameters::FALSE); + } + } else { + mParameters.set(TICameraParameters::KEY_GLBCE, android::CameraParameters::FALSE); + } + +#ifdef OMAP_ENHANCEMENT_S3D + ///Update the current parameter set + if ( (valstr = params.get(TICameraParameters::KEY_AUTOCONVERGENCE_MODE)) != NULL ) { + CAMHAL_LOGDB("AutoConvergence mode set = %s", valstr); + mParameters.set(TICameraParameters::KEY_AUTOCONVERGENCE_MODE, valstr); + } + + if ( (valstr = params.get(TICameraParameters::KEY_MANUAL_CONVERGENCE)) != NULL ) { + int manualConvergence = (int)strtol(valstr, 0, 0); + + if ( ( manualConvergence < strtol(mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MIN), 0, 0) ) || + ( manualConvergence > strtol(mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MAX), 0, 0) ) ) { + CAMHAL_LOGEB("ERROR: Invalid Manual Convergence = %d", manualConvergence); + return BAD_VALUE; + } else { + CAMHAL_LOGDB("ManualConvergence Value = %d", manualConvergence); + mParameters.set(TICameraParameters::KEY_MANUAL_CONVERGENCE, valstr); + } + } + + if((valstr = params.get(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION)) != NULL) { + if ( strcmp(mCameraProperties->get(CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED), + android::CameraParameters::TRUE) == 0 ) { + CAMHAL_LOGDB("Mechanical Mialignment Correction is %s", valstr); + mParameters.set(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION, valstr); + } else { + mParameters.remove(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION); + } + } + + if ((valstr = params.get(TICameraParameters::KEY_EXPOSURE_MODE)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_EXPOSURE_MODES))) { + CAMHAL_LOGDB("Exposure mode set = %s", valstr); + mParameters.set(TICameraParameters::KEY_EXPOSURE_MODE, valstr); + if (!strcmp(valstr, TICameraParameters::EXPOSURE_MODE_MANUAL)) { + int manualVal; + if ((valstr = params.get(TICameraParameters::KEY_MANUAL_EXPOSURE)) != NULL) { + manualVal = params.getInt(TICameraParameters::KEY_MANUAL_EXPOSURE); + if (manualVal < mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN) || + manualVal > mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MAX)) { + CAMHAL_LOGEB("ERROR: Manual Exposure = %s is out of range - " + "setting minimum supported value", valstr); + valstr = mParameters.get(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN); + } + CAMHAL_LOGDB("Manual Exposure = %s", valstr); + mParameters.set(TICameraParameters::KEY_MANUAL_EXPOSURE, valstr); + } + if ((valstr = params.get(TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT)) != NULL) { + manualVal = params.getInt(TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT); + if (manualVal < mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN) || + manualVal > mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MAX)) { + CAMHAL_LOGEB("ERROR: Manual Exposure right = %s is out of range - " + "setting minimum supported value", valstr); + valstr = mParameters.get(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN); + } + CAMHAL_LOGDB("Manual Exposure right = %s", valstr); + mParameters.set(TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT, valstr); + } + if ((valstr = params.get(TICameraParameters::KEY_MANUAL_GAIN_ISO)) != NULL) { + manualVal = params.getInt(TICameraParameters::KEY_MANUAL_GAIN_ISO); + if (manualVal < mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN) || + manualVal > mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MAX)) { + CAMHAL_LOGEB("ERROR: Manual Gain = %s is out of range - " + "setting minimum supported value", valstr); + valstr = mParameters.get(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN); + } + CAMHAL_LOGDB("Manual Gain = %s", valstr); + mParameters.set(TICameraParameters::KEY_MANUAL_GAIN_ISO, valstr); + } + if ((valstr = params.get(TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT)) != NULL) { + manualVal = params.getInt(TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT); + if (manualVal < mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN) || + manualVal > mParameters.getInt(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MAX)) { + CAMHAL_LOGEB("ERROR: Manual Gain right = %s is out of range - " + "setting minimum supported value", valstr); + valstr = mParameters.get(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN); + } + CAMHAL_LOGDB("Manual Gain right = %s", valstr); + mParameters.set(TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT, valstr); + } + } + } else { + CAMHAL_LOGEB("ERROR: Invalid Exposure mode = %s", valstr); + return BAD_VALUE; + } + } +#endif + + if ((valstr = params.get(android::CameraParameters::KEY_WHITE_BALANCE)) != NULL) { + if ( isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_WHITE_BALANCE))) { + CAMHAL_LOGDB("White balance set %s", valstr); + mParameters.set(android::CameraParameters::KEY_WHITE_BALANCE, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid white balance = %s", valstr); + return BAD_VALUE; + } + } + +#ifdef OMAP_ENHANCEMENT + if ((valstr = params.get(TICameraParameters::KEY_CONTRAST)) != NULL) { + if (params.getInt(TICameraParameters::KEY_CONTRAST) >= 0 ) { + CAMHAL_LOGDB("Contrast set %s", valstr); + mParameters.set(TICameraParameters::KEY_CONTRAST, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Contrast = %s", valstr); + return BAD_VALUE; + } + } + + if ((valstr =params.get(TICameraParameters::KEY_SHARPNESS)) != NULL) { + if (params.getInt(TICameraParameters::KEY_SHARPNESS) >= 0 ) { + CAMHAL_LOGDB("Sharpness set %s", valstr); + mParameters.set(TICameraParameters::KEY_SHARPNESS, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Sharpness = %s", valstr); + return BAD_VALUE; + } + } + + if ((valstr = params.get(TICameraParameters::KEY_SATURATION)) != NULL) { + if (params.getInt(TICameraParameters::KEY_SATURATION) >= 0 ) { + CAMHAL_LOGDB("Saturation set %s", valstr); + mParameters.set(TICameraParameters::KEY_SATURATION, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Saturation = %s", valstr); + return BAD_VALUE; + } + } + + if ((valstr = params.get(TICameraParameters::KEY_BRIGHTNESS)) != NULL) { + if (params.getInt(TICameraParameters::KEY_BRIGHTNESS) >= 0 ) { + CAMHAL_LOGDB("Brightness set %s", valstr); + mParameters.set(TICameraParameters::KEY_BRIGHTNESS, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Brightness = %s", valstr); + return BAD_VALUE; + } + } +#endif + + if ((valstr = params.get(android::CameraParameters::KEY_ANTIBANDING)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_ANTIBANDING))) { + CAMHAL_LOGDB("Antibanding set %s", valstr); + mParameters.set(android::CameraParameters::KEY_ANTIBANDING, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Antibanding = %s", valstr); + return BAD_VALUE; + } + } + +#ifdef OMAP_ENHANCEMENT + if ((valstr = params.get(TICameraParameters::KEY_ISO)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_ISO_VALUES))) { + CAMHAL_LOGDB("ISO set %s", valstr); + mParameters.set(TICameraParameters::KEY_ISO, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid ISO = %s", valstr); + return BAD_VALUE; + } + } +#endif + + if( (valstr = params.get(android::CameraParameters::KEY_FOCUS_AREAS)) != NULL ) + { + CAMHAL_LOGDB("Focus areas position set %s", params.get(android::CameraParameters::KEY_FOCUS_AREAS)); + mParameters.set(android::CameraParameters::KEY_FOCUS_AREAS, valstr); + } + +#ifdef OMAP_ENHANCEMENT + if( (valstr = params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)) != NULL ) + { + CAMHAL_LOGDB("Measurements set to %s", valstr); + mParameters.set(TICameraParameters::KEY_MEASUREMENT_ENABLE, valstr); + + if (strcmp(valstr, android::CameraParameters::TRUE) == 0) + { + mMeasurementEnabled = true; + } + else if (strcmp(valstr, android::CameraParameters::FALSE) == 0) + { + mMeasurementEnabled = false; + } + else + { + mMeasurementEnabled = false; + } + + } +#endif + + if( (valstr = params.get(android::CameraParameters::KEY_EXPOSURE_COMPENSATION)) != NULL) + { + CAMHAL_LOGDB("Exposure compensation set %s", params.get(android::CameraParameters::KEY_EXPOSURE_COMPENSATION)); + mParameters.set(android::CameraParameters::KEY_EXPOSURE_COMPENSATION, valstr); + } + + if ((valstr = params.get(android::CameraParameters::KEY_SCENE_MODE)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_SCENE_MODES))) { + CAMHAL_LOGDB("Scene mode set %s", valstr); + doesSetParameterNeedUpdate(valstr, + mParameters.get(android::CameraParameters::KEY_SCENE_MODE), + updateRequired); + mParameters.set(android::CameraParameters::KEY_SCENE_MODE, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Scene mode = %s", valstr); + return BAD_VALUE; + } + } + + if ((valstr = params.get(android::CameraParameters::KEY_FLASH_MODE)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_FLASH_MODES))) { + CAMHAL_LOGDB("Flash mode set %s", valstr); + mParameters.set(android::CameraParameters::KEY_FLASH_MODE, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Flash mode = %s", valstr); + return BAD_VALUE; + } + } + + if ((valstr = params.get(android::CameraParameters::KEY_EFFECT)) != NULL) { + if (isParameterValid(valstr, mCameraProperties->get(CameraProperties::SUPPORTED_EFFECTS))) { + CAMHAL_LOGDB("Effect set %s", valstr); + mParameters.set(android::CameraParameters::KEY_EFFECT, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Effect = %s", valstr); + return BAD_VALUE; + } + } + + varint = params.getInt(android::CameraParameters::KEY_ROTATION); + if ( varint >= 0 ) { + CAMHAL_LOGDB("Rotation set %d", varint); + mParameters.set(android::CameraParameters::KEY_ROTATION, varint); + } + + varint = params.getInt(android::CameraParameters::KEY_JPEG_QUALITY); + if ( varint >= 0 ) { + CAMHAL_LOGDB("Jpeg quality set %d", varint); + mParameters.set(android::CameraParameters::KEY_JPEG_QUALITY, varint); + } + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + if ( varint >= 0 ) { + CAMHAL_LOGDB("Thumbnail width set %d", varint); + mParameters.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, varint); + } + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + if ( varint >= 0 ) { + CAMHAL_LOGDB("Thumbnail width set %d", varint); + mParameters.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, varint); + } + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + if ( varint >= 0 ) { + CAMHAL_LOGDB("Thumbnail quality set %d", varint); + mParameters.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, varint); + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_LATITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS latitude set %s", params.get(android::CameraParameters::KEY_GPS_LATITUDE)); + mParameters.set(android::CameraParameters::KEY_GPS_LATITUDE, valstr); + }else{ + mParameters.remove(android::CameraParameters::KEY_GPS_LATITUDE); + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_LONGITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS longitude set %s", params.get(android::CameraParameters::KEY_GPS_LONGITUDE)); + mParameters.set(android::CameraParameters::KEY_GPS_LONGITUDE, valstr); + }else{ + mParameters.remove(android::CameraParameters::KEY_GPS_LONGITUDE); + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_ALTITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS altitude set %s", params.get(android::CameraParameters::KEY_GPS_ALTITUDE)); + mParameters.set(android::CameraParameters::KEY_GPS_ALTITUDE, valstr); + }else{ + mParameters.remove(android::CameraParameters::KEY_GPS_ALTITUDE); + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_TIMESTAMP)) != NULL ) + { + CAMHAL_LOGDB("GPS timestamp set %s", params.get(android::CameraParameters::KEY_GPS_TIMESTAMP)); + mParameters.set(android::CameraParameters::KEY_GPS_TIMESTAMP, valstr); + }else{ + mParameters.remove(android::CameraParameters::KEY_GPS_TIMESTAMP); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_DATESTAMP)) != NULL ) + { + CAMHAL_LOGDB("GPS datestamp set %s", valstr); + mParameters.set(TICameraParameters::KEY_GPS_DATESTAMP, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_DATESTAMP); + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_PROCESSING_METHOD)) != NULL ) + { + CAMHAL_LOGDB("GPS processing method set %s", params.get(android::CameraParameters::KEY_GPS_PROCESSING_METHOD)); + mParameters.set(android::CameraParameters::KEY_GPS_PROCESSING_METHOD, valstr); + }else{ + mParameters.remove(android::CameraParameters::KEY_GPS_PROCESSING_METHOD); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_MAPDATUM )) != NULL ) + { + CAMHAL_LOGDB("GPS MAPDATUM set %s", valstr); + mParameters.set(TICameraParameters::KEY_GPS_MAPDATUM, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_MAPDATUM); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_VERSION)) != NULL ) + { + CAMHAL_LOGDB("GPS MAPDATUM set %s", valstr); + mParameters.set(TICameraParameters::KEY_GPS_VERSION, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_VERSION); + } + +#ifndef MOTOROLA_CAMERA + if( (valstr = params.get(TICameraParameters::KEY_EXIF_MODEL)) != NULL ) + { + CAMHAL_LOGDB("EXIF Model set %s", valstr); + mParameters.set(TICameraParameters::KEY_EXIF_MODEL, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_EXIF_MAKE)) != NULL ) + { + CAMHAL_LOGDB("EXIF Make set %s", valstr); + mParameters.set(TICameraParameters::KEY_EXIF_MAKE, valstr); + } +#else + if( (property_get("ro.product.model",value,0) > 0)) + { + CAMHAL_LOGDB("EXIF Model set %s",value); + mParameters.set(TICameraParameters::KEY_EXIF_MODEL, value); + } + + if( (property_get("ro.product.manufacturer",value,0) > 0) ) + { + CAMHAL_LOGDB("EXIF Make set %s",value); + mParameters.set(TICameraParameters::KEY_EXIF_MAKE, value); + } + + // enabled/disabled similar parameters: + // KEY_MOT_LEDFLASH // int: 0..100 percent + if((params.get(TICameraParameters::KEY_MOT_LEDFLASH) != NULL) + && (params.getInt(TICameraParameters::KEY_MOT_LEDFLASH) >=0) + && (params.getInt(TICameraParameters::KEY_MOT_LEDFLASH) <=100)) + { + CAMHAL_LOGDB("Led Flash : %s",params.get(TICameraParameters::KEY_MOT_LEDFLASH)); + mParameters.set(TICameraParameters::KEY_MOT_LEDFLASH, + params.get(TICameraParameters::KEY_MOT_LEDFLASH)); + } + + // KEY_MOT_LEDTORCH // int: 0..100 percent + if((params.get(TICameraParameters::KEY_MOT_LEDTORCH) != NULL) + && (params.getInt(TICameraParameters::KEY_MOT_LEDTORCH) >=0) + && (params.getInt(TICameraParameters::KEY_MOT_LEDTORCH) <=100)) + { + CAMHAL_LOGDB("Led Torch : %s",params.get(TICameraParameters::KEY_MOT_LEDTORCH)); + mParameters.set(TICameraParameters::KEY_MOT_LEDTORCH, + params.get(TICameraParameters::KEY_MOT_LEDTORCH)); + } +#endif + +#ifdef OMAP_ENHANCEMENT + if( (valstr = params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE)) != NULL ) + { + CAMHAL_LOGDB("Exposure Bracketing set %s", params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE)); + mParameters.set(TICameraParameters::KEY_EXP_BRACKETING_RANGE, valstr); + mParameters.remove(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE); + } + else if ((valstr = params.get(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE)) != NULL) { + CAMHAL_LOGDB("ABS Exposure+Gain Bracketing set %s", params.get(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE)); + mParameters.set(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE, valstr); + mParameters.remove(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + } else + { + mParameters.remove(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + } + + if( (valstr = params.get(TICameraParameters::KEY_ZOOM_BRACKETING_RANGE)) != NULL ) { + CAMHAL_LOGDB("Zoom Bracketing range %s", valstr); + mParameters.set(TICameraParameters::KEY_ZOOM_BRACKETING_RANGE, valstr); + } else { + mParameters.remove(TICameraParameters::KEY_ZOOM_BRACKETING_RANGE); + } +#endif + + if ((valstr = params.get(android::CameraParameters::KEY_ZOOM)) != NULL ) { + varint = atoi(valstr); + if ( varint >= 0 && varint <= mMaxZoomSupported ) { + CAMHAL_LOGDB("Zoom set %d", varint); + doesSetParameterNeedUpdate(valstr, + mParameters.get(android::CameraParameters::KEY_ZOOM), + updateRequired); + mParameters.set(android::CameraParameters::KEY_ZOOM, valstr); + } else { + CAMHAL_LOGEB("ERROR: Invalid Zoom: %s", valstr); + return BAD_VALUE; + } + } + + if( (valstr = params.get(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK)) != NULL ) + { + CAMHAL_LOGDB("Auto Exposure Lock set %s", valstr); + doesSetParameterNeedUpdate(valstr, + mParameters.get(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK), + updateRequired); + mParameters.set(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK, valstr); + } + + if( (valstr = params.get(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK)) != NULL ) + { + CAMHAL_LOGDB("Auto WhiteBalance Lock set %s", valstr); + doesSetParameterNeedUpdate(valstr, + mParameters.get(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK), + updateRequired); + mParameters.set(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, valstr); + } + if( (valstr = params.get(android::CameraParameters::KEY_METERING_AREAS)) != NULL ) + { + CAMHAL_LOGDB("Metering areas position set %s", params.get(android::CameraParameters::KEY_METERING_AREAS)); + mParameters.set(android::CameraParameters::KEY_METERING_AREAS, valstr); + } + + if( (valstr = params.get(TICameraParameters::RAW_WIDTH)) != NULL ) { + CAMHAL_LOGDB("Raw image width set %s", params.get(TICameraParameters::RAW_WIDTH)); + mParameters.set(TICameraParameters::RAW_WIDTH, valstr); + } + + if( (valstr = params.get(TICameraParameters::RAW_HEIGHT)) != NULL ) { + CAMHAL_LOGDB("Raw image height set %s", params.get(TICameraParameters::RAW_HEIGHT)); + mParameters.set(TICameraParameters::RAW_HEIGHT, valstr); + } + + //TI extensions for enable/disable algos + if( (valstr = params.get(TICameraParameters::KEY_ALGO_EXTERNAL_GAMMA)) != NULL ) + { + CAMHAL_LOGDB("External Gamma set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_EXTERNAL_GAMMA, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_ALGO_NSF1)) != NULL ) + { + CAMHAL_LOGDB("NSF1 set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_NSF1, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_ALGO_NSF2)) != NULL ) + { + CAMHAL_LOGDB("NSF2 set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_NSF2, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_ALGO_SHARPENING)) != NULL ) + { + CAMHAL_LOGDB("Sharpening set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_SHARPENING, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_ALGO_THREELINCOLORMAP)) != NULL ) + { + CAMHAL_LOGDB("Color Conversion set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_THREELINCOLORMAP, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_ALGO_GIC)) != NULL ) + { + CAMHAL_LOGDB("Green Inballance Correction set %s", valstr); + mParameters.set(TICameraParameters::KEY_ALGO_GIC, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_GAMMA_TABLE)) != NULL ) + { + CAMHAL_LOGDB("Manual gamma table set %s", valstr); + mParameters.set(TICameraParameters::KEY_GAMMA_TABLE, valstr); + } + + android::CameraParameters adapterParams = mParameters; + +#ifdef OMAP_ENHANCEMENT + if( NULL != params.get(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS) ) + { + int posBracketRange = params.getInt(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS); + if ( 0 < posBracketRange ) + { + mBracketRangePositive = posBracketRange; + } + } + CAMHAL_LOGDB("Positive bracketing range %d", mBracketRangePositive); + + + if( NULL != params.get(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG) ) + { + int negBracketRange = params.getInt(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG); + if ( 0 < negBracketRange ) + { + mBracketRangeNegative = negBracketRange; + } + } + CAMHAL_LOGDB("Negative bracketing range %d", mBracketRangeNegative); + + if( ( (valstr = params.get(TICameraParameters::KEY_TEMP_BRACKETING)) != NULL) && + ( strcmp(valstr, android::CameraParameters::TRUE) == 0 )) { + if ( !mBracketingEnabled ) { + CAMHAL_LOGDA("Enabling bracketing"); + mBracketingEnabled = true; + } else { + CAMHAL_LOGDA("Bracketing already enabled"); + } + adapterParams.set(TICameraParameters::KEY_TEMP_BRACKETING, valstr); + mParameters.set(TICameraParameters::KEY_TEMP_BRACKETING, valstr); + } else if ( ( (valstr = params.get(TICameraParameters::KEY_TEMP_BRACKETING)) != NULL ) && + ( strcmp(valstr, android::CameraParameters::FALSE) == 0 )) { + CAMHAL_LOGDA("Disabling bracketing"); + + adapterParams.set(TICameraParameters::KEY_TEMP_BRACKETING, valstr); + mParameters.set(TICameraParameters::KEY_TEMP_BRACKETING, valstr); + mBracketingEnabled = false; + if ( mBracketingRunning ) { + stopImageBracketing(); + } + + } else { + adapterParams.remove(TICameraParameters::KEY_TEMP_BRACKETING); + mParameters.remove(TICameraParameters::KEY_TEMP_BRACKETING); + } +#endif + +#ifdef OMAP_ENHANCEMENT_VTC + if (mVTCUseCase && !mTunnelSetup && (mCameraAdapter != NULL) && + ((mParameters.get(TICameraParameters::KEY_VIDEO_ENCODER_HANDLE)) != NULL )&& + ((mParameters.get(TICameraParameters::KEY_VIDEO_ENCODER_SLICE_HEIGHT)) != NULL )) { + + uint32_t sliceHeight = mParameters.getInt(TICameraParameters::KEY_VIDEO_ENCODER_SLICE_HEIGHT); + uint32_t encoderHandle = mParameters.getInt(TICameraParameters::KEY_VIDEO_ENCODER_HANDLE); + int w, h; + mParameters.getPreviewSize(&w, &h); + status_t done = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_SETUP_TUNNEL, sliceHeight, encoderHandle, w, h); + if (done == NO_ERROR) mTunnelSetup = true; + ret |= done; + } +#endif + + // Only send parameters to adapter if preview is already + // enabled or doesSetParameterNeedUpdate says so. Initial setParameters to camera adapter, + // will be called in startPreview() + // TODO(XXX): Need to identify other parameters that need update from camera adapter + if ( (NULL != mCameraAdapter) && + (mPreviewEnabled || updateRequired) && + (!(mPreviewEnabled && restartPreviewRequired)) ) { + ret |= mCameraAdapter->setParameters(adapterParams); + } + +#ifdef OMAP_ENHANCEMENT + if( ( (valstr = params.get(TICameraParameters::KEY_SHUTTER_ENABLE)) != NULL ) && + ( strcmp(valstr, android::CameraParameters::TRUE) == 0 )) + { + CAMHAL_LOGDA("Enabling shutter sound"); + + mShutterEnabled = true; + mMsgEnabled |= CAMERA_MSG_SHUTTER; + mParameters.set(TICameraParameters::KEY_SHUTTER_ENABLE, valstr); + } + else if ( ( (valstr = params.get(TICameraParameters::KEY_SHUTTER_ENABLE)) != NULL ) && + ( strcmp(valstr, android::CameraParameters::FALSE) == 0 )) + { + CAMHAL_LOGDA("Disabling shutter sound"); + + mShutterEnabled = false; + mMsgEnabled &= ~CAMERA_MSG_SHUTTER; + mParameters.set(TICameraParameters::KEY_SHUTTER_ENABLE, valstr); + } +#endif + } + + //On fail restore old parameters + if ( NO_ERROR != ret ) { + mParameters = oldParams; + } + + // Restart Preview if needed by KEY_RECODING_HINT only if preview is already running. + // If preview is not started yet, Video Mode parameters will take effect on next startPreview() + if (restartPreviewRequired && previewEnabled() && !mRecordingEnabled) { + CAMHAL_LOGDA("Restarting Preview"); + ret = restartPreview(); + } else if (restartPreviewRequired && !previewEnabled() && + mDisplayPaused && !mRecordingEnabled) { + CAMHAL_LOGDA("Restarting preview in paused mode"); + ret = restartPreview(); + + // TODO(XXX): If there is some delay between the restartPreview call and the code + // below, then the user could see some preview frames and callbacks. Let's find + // a better place to put this later... + if (ret == NO_ERROR) { + mDisplayPaused = true; + mPreviewEnabled = false; + ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); + } + } + + if ( !mBracketingRunning && mBracketingEnabled ) { + startImageBracketing(); + } + + if (ret != NO_ERROR) + { + CAMHAL_LOGEA("Failed to restart Preview"); + return ret; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::allocPreviewBufs(int width, int height, const char* previewFormat, + unsigned int buffercount, unsigned int &max_queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if(mDisplayAdapter.get() == NULL) + { + // Memory allocation of preview buffers is now placed in gralloc + // CameraHal should not allocate preview buffers without DisplayAdapter + return NO_MEMORY; + } + + if(!mPreviewBuffers) + { + mPreviewLength = 0; + mPreviewBuffers = mDisplayAdapter->allocateBufferList(width, height, + previewFormat, + mPreviewLength, + buffercount); + if (NULL == mPreviewBuffers ) { + CAMHAL_LOGEA("Couldn't allocate preview buffers"); + return NO_MEMORY; + } + + mPreviewOffsets = (uint32_t *) mDisplayAdapter->getOffsets(); + if ( NULL == mPreviewOffsets ) { + CAMHAL_LOGEA("Buffer mapping failed"); + return BAD_VALUE; + } + + mBufProvider = (BufferProvider*) mDisplayAdapter.get(); + + ret = mDisplayAdapter->maxQueueableBuffers(max_queueable); + if (ret != NO_ERROR) { + return ret; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freePreviewBufs() +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + CAMHAL_LOGDB("mPreviewBuffers = %p", mPreviewBuffers); + if(mPreviewBuffers) + { + ret = mBufProvider->freeBufferList(mPreviewBuffers); + mPreviewBuffers = NULL; + LOG_FUNCTION_NAME_EXIT; + return ret; + } + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +status_t CameraHal::allocPreviewDataBufs(size_t size, size_t bufferCount) +{ + status_t ret = NO_ERROR; + int bytes; + + LOG_FUNCTION_NAME; + + bytes = size; + + if ( NO_ERROR == ret ) + { + if( NULL != mPreviewDataBuffers ) + { + ret = freePreviewDataBufs(); + } + } + + if ( NO_ERROR == ret ) + { + bytes = ((bytes+4095)/4096)*4096; + mPreviewDataBuffers = mMemoryManager->allocateBufferList(0, 0, NULL, bytes, bufferCount); + + CAMHAL_LOGDB("Size of Preview data buffer = %d", bytes); + if( NULL == mPreviewDataBuffers ) + { + CAMHAL_LOGEA("Couldn't allocate image buffers using memory manager"); + ret = -NO_MEMORY; + } + else + { + bytes = size; + } + } + + if ( NO_ERROR == ret ) + { + mPreviewDataFd = mMemoryManager->getFd(); + mPreviewDataLength = bytes; + mPreviewDataOffsets = mMemoryManager->getOffsets(); + } + else + { + mPreviewDataFd = -1; + mPreviewDataLength = 0; + mPreviewDataOffsets = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freePreviewDataBufs() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + + if( NULL != mPreviewDataBuffers ) + { + + ret = mMemoryManager->freeBufferList(mPreviewDataBuffers); + mPreviewDataBuffers = NULL; + + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::allocImageBufs(unsigned int width, unsigned int height, size_t size, + const char* previewFormat, unsigned int bufferCount) +{ + status_t ret = NO_ERROR; + int bytes = size; + + LOG_FUNCTION_NAME; + + // allocate image buffers only if not already allocated + if(NULL != mImageBuffers) { + return NO_ERROR; + } + + if ( NO_ERROR == ret ) { + bytes = ((bytes+4095)/4096)*4096; + mImageBuffers = mMemoryManager->allocateBufferList(0, 0, previewFormat, bytes, bufferCount); + CAMHAL_LOGDB("Size of Image cap buffer = %d", bytes); + if( NULL == mImageBuffers ) { + CAMHAL_LOGEA("Couldn't allocate image buffers using memory manager"); + ret = -NO_MEMORY; + } else { + bytes = size; + } + } + + if ( NO_ERROR == ret ) { + mImageFd = mMemoryManager->getFd(); + mImageLength = bytes; + mImageOffsets = mMemoryManager->getOffsets(); + mImageCount = bufferCount; + } else { + mImageFd = -1; + mImageLength = 0; + mImageOffsets = NULL; + mImageCount = 0; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::allocVideoBufs(uint32_t width, uint32_t height, uint32_t bufferCount) +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + if( NULL != mVideoBuffers ){ + ret = freeVideoBufs(mVideoBuffers); + mVideoBuffers = NULL; + } + + if ( NO_ERROR == ret ){ + int32_t stride; + CameraBuffer *buffers = new CameraBuffer [bufferCount]; + + memset (buffers, 0, sizeof(CameraBuffer) * bufferCount); + + if (buffers != NULL){ + for (unsigned int i = 0; i< bufferCount; i++){ + android::GraphicBufferAllocator &GrallocAlloc = android::GraphicBufferAllocator::get(); + buffer_handle_t handle; + ret = GrallocAlloc.alloc(width, height, HAL_PIXEL_FORMAT_NV12, CAMHAL_GRALLOC_USAGE, &handle, &stride); + if (ret != NO_ERROR){ + CAMHAL_LOGEA("Couldn't allocate video buffers using Gralloc"); + ret = -NO_MEMORY; + for (unsigned int j=0; j< i; j++){ + CAMHAL_LOGEB("Freeing Gralloc Buffer %p", buffers[i].opaque); + GrallocAlloc.free((buffer_handle_t)buffers[i].opaque); + } + delete [] buffers; + goto exit; + } + buffers[i].type = CAMERA_BUFFER_GRALLOC; + buffers[i].opaque = (void *)handle; + CAMHAL_LOGVB("*** Gralloc Handle =0x%x ***", handle); + } + + mVideoBuffers = buffers; + } + else{ + CAMHAL_LOGEA("Couldn't allocate video buffers "); + ret = -NO_MEMORY; + } + } + + exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::allocRawBufs(int width, int height, const char* previewFormat, int bufferCount) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME + + + ///@todo Enhance this method allocImageBufs() to take in a flag for burst capture + ///Always allocate the buffers for image capture using MemoryManager + if (NO_ERROR == ret) { + if(( NULL != mVideoBuffers )) { + // Re-use the buffer for raw capture. + return ret; + } + } + + if ( NO_ERROR == ret ) { + mVideoLength = 0; + mVideoLength = (((width * height * 2) + 4095)/4096)*4096; + mVideoBuffers = mMemoryManager->allocateBufferList(width, height, previewFormat, + mVideoLength, bufferCount); + + CAMHAL_LOGDB("Size of Video cap buffer (used for RAW capture) %d", mVideoLength); + if( NULL == mVideoBuffers ) { + CAMHAL_LOGEA("Couldn't allocate Video buffers using memory manager"); + ret = -NO_MEMORY; + } + } + + if ( NO_ERROR == ret ) { + mVideoFd = mMemoryManager->getFd(); + mVideoOffsets = mMemoryManager->getOffsets(); + } else { + mVideoFd = -1; + mVideoOffsets = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void endImageCapture( void *userData) +{ + LOG_FUNCTION_NAME; + + if ( NULL != userData ) + { + CameraHal *c = reinterpret_cast(userData); + c->signalEndImageCapture(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void releaseImageBuffers(void *userData) +{ + LOG_FUNCTION_NAME; + + if (NULL != userData) { + CameraHal *c = reinterpret_cast(userData); + c->freeImageBufs(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t CameraHal::signalEndImageCapture() +{ + status_t ret = NO_ERROR; + int w,h; + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME; + + if (mBufferSourceAdapter_Out.get()) { + mBufferSourceAdapter_Out->disableDisplay(); + } + + if (mBufferSourceAdapter_In.get()) { + mBufferSourceAdapter_In->disableDisplay(); + } + + if ( mBracketingRunning ) { + stopImageBracketing(); + } else { + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freeImageBufs() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if (NULL == mImageBuffers) { + return -EINVAL; + } + + if (mBufferSourceAdapter_Out.get()) { + mBufferSourceAdapter_Out = 0; + } else { + ret = mMemoryManager->freeBufferList(mImageBuffers); + } + + mImageBuffers = NULL; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freeVideoBufs(CameraBuffer *bufs) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + int count = atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS)); + if(bufs == NULL) + { + CAMHAL_LOGEA("NULL pointer passed to freeVideoBuffer"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + android::GraphicBufferAllocator &GrallocAlloc = android::GraphicBufferAllocator::get(); + + for(int i = 0; i < count; i++){ + CAMHAL_LOGVB("Free Video Gralloc Handle 0x%x", bufs[i].opaque); + GrallocAlloc.free((buffer_handle_t)bufs[i].opaque); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freeRawBufs() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME + + if ( NO_ERROR == ret ) { + if( NULL != mVideoBuffers ) { + ///@todo Pluralise the name of this method to freeBuffers + ret = mMemoryManager->freeBufferList(mVideoBuffers); + mVideoBuffers = NULL; + } else { + ret = -EINVAL; + } + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +/** + @brief Start preview mode. + + @param none + @return NO_ERROR Camera switched to VF mode + @todo Update function header with the different errors that are possible + + */ +status_t CameraHal::startPreview() { + LOG_FUNCTION_NAME; + + // When tunneling is enabled during VTC, startPreview happens in 2 steps: + // When the application sends the command CAMERA_CMD_PREVIEW_INITIALIZATION, + // cameraPreviewInitialization() is called, which in turn causes the CameraAdapter + // to move from loaded to idle state. And when the application calls startPreview, + // the CameraAdapter moves from idle to executing state. + // + // If the application calls startPreview() without sending the command + // CAMERA_CMD_PREVIEW_INITIALIZATION, then the function cameraPreviewInitialization() + // AND startPreview() are executed. In other words, if the application calls + // startPreview() without sending the command CAMERA_CMD_PREVIEW_INITIALIZATION, + // then the CameraAdapter moves from loaded to idle to executing state in one shot. + status_t ret = cameraPreviewInitialization(); + + // The flag mPreviewInitializationDone is set to true at the end of the function + // cameraPreviewInitialization(). Therefore, if everything goes alright, then the + // flag will be set. Sometimes, the function cameraPreviewInitialization() may + // return prematurely if all the resources are not available for starting preview. + // For example, if the preview window is not set, then it would return NO_ERROR. + // Under such circumstances, one should return from startPreview as well and should + // not continue execution. That is why, we check the flag and not the return value. + if (!mPreviewInitializationDone) return ret; + + // Once startPreview is called, there is no need to continue to remember whether + // the function cameraPreviewInitialization() was called earlier or not. And so + // the flag mPreviewInitializationDone is reset here. Plus, this preserves the + // current behavior of startPreview under the circumstances where the application + // calls startPreview twice or more. + mPreviewInitializationDone = false; + + ///Enable the display adapter if present, actual overlay enable happens when we post the buffer + if(mDisplayAdapter.get() != NULL) { + CAMHAL_LOGDA("Enabling display"); + int width, height; + mParameters.getPreviewSize(&width, &height); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview); +#else + ret = mDisplayAdapter->enableDisplay(width, height, NULL); +#endif + + if ( ret != NO_ERROR ) { + CAMHAL_LOGEA("Couldn't enable display"); + + // FIXME: At this stage mStateSwitchLock is locked and unlock is supposed to be called + // only from mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW) + // below. But this will never happen because of goto error. Thus at next + // startPreview() call CameraHAL will be deadlocked. + // Need to revisit mStateSwitch lock, for now just abort the process. + CAMHAL_ASSERT_X(false, + "At this stage mCameraAdapter->mStateSwitchLock is still locked, " + "deadlock is guaranteed"); + + goto error; + } + + } + + ///Send START_PREVIEW command to adapter + CAMHAL_LOGDA("Starting CameraAdapter preview mode"); + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW); + + if(ret!=NO_ERROR) { + CAMHAL_LOGEA("Couldn't start preview w/ CameraAdapter"); + goto error; + } + CAMHAL_LOGDA("Started preview"); + + mPreviewEnabled = true; + mPreviewStartInProgress = false; + return ret; + + error: + + CAMHAL_LOGEA("Performing cleanup after error"); + + //Do all the cleanup + freePreviewBufs(); + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW); + if(mDisplayAdapter.get() != NULL) { + mDisplayAdapter->disableDisplay(false); + } + mAppCallbackNotifier->stop(); + mPreviewStartInProgress = false; + mPreviewEnabled = false; + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//////////// +/** + @brief Set preview mode related initialization + -> Camera Adapter set params + -> Allocate buffers + -> Set use buffers for preview + @param none + @return NO_ERROR + @todo Update function header with the different errors that are possible + + */ +status_t CameraHal::cameraPreviewInitialization() +{ + + status_t ret = NO_ERROR; + CameraAdapter::BuffersDescriptor desc; + CameraFrame frame; + unsigned int required_buffer_count; + unsigned int max_queueble_buffers; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + gettimeofday(&mStartPreview, NULL); +#endif + + LOG_FUNCTION_NAME; + + if (mPreviewInitializationDone) { + return NO_ERROR; + } + + if ( mPreviewEnabled ){ + CAMHAL_LOGDA("Preview already running"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + if ( NULL != mCameraAdapter ) { + ret = mCameraAdapter->setParameters(mParameters); + } + + if ((mPreviewStartInProgress == false) && (mDisplayPaused == false)){ + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW,( int ) &frame); + if ( NO_ERROR != ret ){ + CAMHAL_LOGEB("Error: CAMERA_QUERY_RESOLUTION_PREVIEW %d", ret); + return ret; + } + + ///Update the current preview width and height + mPreviewWidth = frame.mWidth; + mPreviewHeight = frame.mHeight; + } + + ///If we don't have the preview callback enabled and display adapter, + if(!mSetPreviewWindowCalled || (mDisplayAdapter.get() == NULL)){ + CAMHAL_LOGD("Preview not started. Preview in progress flag set"); + mPreviewStartInProgress = true; + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_SWITCH_TO_EXECUTING); + if ( NO_ERROR != ret ){ + CAMHAL_LOGEB("Error: CAMERA_SWITCH_TO_EXECUTING %d", ret); + return ret; + } + return NO_ERROR; + } + + if( (mDisplayAdapter.get() != NULL) && ( !mPreviewEnabled ) && ( mDisplayPaused ) ) + { + CAMHAL_LOGDA("Preview is in paused state"); + + mDisplayPaused = false; + mPreviewEnabled = true; + if ( NO_ERROR == ret ) + { + ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Display adapter resume failed %x", ret); + } + } + //restart preview callbacks + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + { + mAppCallbackNotifier->enableMsgType (CAMERA_MSG_PREVIEW_FRAME); + } + + signalEndImageCapture(); + return ret; + } + + required_buffer_count = atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS)); + + ///Allocate the preview buffers + ret = allocPreviewBufs(mPreviewWidth, mPreviewHeight, mParameters.getPreviewFormat(), required_buffer_count, max_queueble_buffers); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Couldn't allocate buffers for Preview"); + goto error; + } + + if ( mMeasurementEnabled ) + { + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA, + ( int ) &frame, + required_buffer_count); + if ( NO_ERROR != ret ) + { + return ret; + } + + ///Allocate the preview data buffers + ret = allocPreviewDataBufs(frame.mLength, required_buffer_count); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEA("Couldn't allocate preview data buffers"); + goto error; + } + + if ( NO_ERROR == ret ) + { + desc.mBuffers = mPreviewDataBuffers; + desc.mOffsets = mPreviewDataOffsets; + desc.mFd = mPreviewDataFd; + desc.mLength = mPreviewDataLength; + desc.mCount = ( size_t ) required_buffer_count; + desc.mMaxQueueable = (size_t) required_buffer_count; + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA, + ( int ) &desc); + } + + } + + ///Pass the buffers to Camera Adapter + desc.mBuffers = mPreviewBuffers; + desc.mOffsets = mPreviewOffsets; + desc.mFd = mPreviewFd; + desc.mLength = mPreviewLength; + desc.mCount = ( size_t ) required_buffer_count; + desc.mMaxQueueable = (size_t) max_queueble_buffers; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW, + ( int ) &desc); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Failed to register preview buffers: 0x%x", ret); + freePreviewBufs(); + return ret; + } + + ///Start the callback notifier + ret = mAppCallbackNotifier->start(); + + if( ALREADY_EXISTS == ret ) + { + //Already running, do nothing + CAMHAL_LOGDA("AppCallbackNotifier already running"); + ret = NO_ERROR; + } + else if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("Started AppCallbackNotifier.."); + mAppCallbackNotifier->setMeasurements(mMeasurementEnabled); + } + else + { + CAMHAL_LOGDA("Couldn't start AppCallbackNotifier"); + goto error; + } + + if (ret == NO_ERROR) mPreviewInitializationDone = true; + + mAppCallbackNotifier->startPreviewCallbacks(mParameters, mPreviewBuffers, mPreviewOffsets, mPreviewFd, mPreviewLength, required_buffer_count); + + return ret; + + error: + + CAMHAL_LOGEA("Performing cleanup after error"); + + //Do all the cleanup + freePreviewBufs(); + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW); + if(mDisplayAdapter.get() != NULL) + { + mDisplayAdapter->disableDisplay(false); + } + mAppCallbackNotifier->stop(); + mPreviewStartInProgress = false; + mPreviewEnabled = false; + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Sets ANativeWindow object. + + Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it + to render buffers to display. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window) +{ + status_t ret = NO_ERROR; + CameraAdapter::BuffersDescriptor desc; + + LOG_FUNCTION_NAME; + mSetPreviewWindowCalled = true; + + ///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter + if(!window) + { + if(mDisplayAdapter.get() != NULL) + { + ///NULL window passed, destroy the display adapter if present + CAMHAL_LOGD("NULL window passed, destroying display adapter"); + mDisplayAdapter.clear(); + ///@remarks If there was a window previously existing, we usually expect another valid window to be passed by the client + ///@remarks so, we will wait until it passes a valid window to begin the preview again + mSetPreviewWindowCalled = false; + } + CAMHAL_LOGD("NULL ANativeWindow passed to setPreviewWindow"); + return NO_ERROR; + }else if(mDisplayAdapter.get() == NULL) + { + // Need to create the display adapter since it has not been created + // Create display adapter + ANativeWindowDisplayAdapter* displayAdapter = new ANativeWindowDisplayAdapter(); + displayAdapter->setExternalLocking(mExternalLocking); + if (NULL != mAppCallbackNotifier.get()) { + mAppCallbackNotifier->setExternalLocking(mExternalLocking); + } else { + CAMHAL_LOGE("Can't apply locking policy on AppCallbackNotifier"); + CAMHAL_ASSERT(0); + } + mDisplayAdapter = displayAdapter; +#ifdef OMAP_ENHANCEMENT_CPCAM + mDisplayAdapter->setExtendedOps(mExtendedPreviewStreamOps); +#endif + ret = NO_ERROR; + if(!mDisplayAdapter.get() || ((ret=mDisplayAdapter->initialize())!=NO_ERROR)) + { + if(ret!=NO_ERROR) + { + mDisplayAdapter.clear(); + CAMHAL_LOGEA("DisplayAdapter initialize failed"); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + else + { + CAMHAL_LOGEA("Couldn't create DisplayAdapter"); + LOG_FUNCTION_NAME_EXIT; + return NO_MEMORY; + } + } + + // DisplayAdapter needs to know where to get the CameraFrames from inorder to display + // Since CameraAdapter is the one that provides the frames, set it as the frame provider for DisplayAdapter + mDisplayAdapter->setFrameProvider(mCameraAdapter); + + // Any dynamic errors that happen during the camera use case has to be propagated back to the application + // via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application + // Set it as the error handler for the DisplayAdapter + mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get()); + + // Update the display adapter with the new window that is passed from CameraService + ret = mDisplayAdapter->setPreviewWindow(window); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); + } + + if(mPreviewStartInProgress) + { + CAMHAL_LOGDA("setPreviewWindow called when preview running"); + // Start the preview since the window is now available + ret = startPreview(); + } + } else { + // Update the display adapter with the new window that is passed from CameraService + ret = mDisplayAdapter->setPreviewWindow(window); + if ( (NO_ERROR == ret) && previewEnabled() ) { + restartPreview(); + } else if (ret == ALREADY_EXISTS) { + // ALREADY_EXISTS should be treated as a noop in this case + ret = NO_ERROR; + } + } + LOG_FUNCTION_NAME_EXIT; + + return ret; + +} + + +#ifdef OMAP_ENHANCEMENT_CPCAM +void CameraHal::setExtendedPreviewStreamOps(preview_stream_extended_ops_t *ops) +{ + mExtendedPreviewStreamOps = ops; +} + +/** + @brief Sets Tapout Surfaces. + + Buffers provided to CameraHal via this object for tap-out + functionality. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::setTapoutLocked(struct preview_stream_ops *tapout) +{ + status_t ret = NO_ERROR; + int index = -1; + + LOG_FUNCTION_NAME; + + if (!tapout) { + CAMHAL_LOGD("Missing argument"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + // Set tapout point + // 1. Check name of tap-out + // 2. If not already set, then create a new one + // 3. Allocate buffers. If user is re-setting the surface, free buffers first and re-allocate + // in case dimensions have changed + + for (unsigned int i = 0; i < mOutAdapters.size(); i++) { + android::sp out; + out = mOutAdapters.itemAt(i); + ret = out->setPreviewWindow(tapout); + if (ret == ALREADY_EXISTS) { + CAMHAL_LOGD("Tap Out already set at index = %d", i); + index = i; + ret = NO_ERROR; + } + } + + if (index < 0) { + android::sp out = new BufferSourceAdapter(); + + ret = out->initialize(); + if (ret != NO_ERROR) { + out.clear(); + CAMHAL_LOGEA("DisplayAdapter initialize failed"); + goto exit; + } + + // BufferSourceAdapter will be handler of the extended OPS + out->setExtendedOps(mExtendedPreviewStreamOps); + + // CameraAdapter will be the frame provider for BufferSourceAdapter + out->setFrameProvider(mCameraAdapter); + + // BufferSourceAdapter will use ErrorHandler to send errors back to + // the application + out->setErrorHandler(mAppCallbackNotifier.get()); + + // Update the display adapter with the new window that is passed from CameraService + ret = out->setPreviewWindow(tapout); + if(ret != NO_ERROR) { + CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); + goto exit; + } + + if (NULL != mCameraAdapter) { + unsigned int bufferCount, max_queueable; + CameraFrame frame; + + bufferCount = out->getBufferCount(); + if (bufferCount < 1) bufferCount = NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, + ( int ) &frame, + bufferCount); + if (NO_ERROR != ret) { + CAMHAL_LOGEB("CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x", ret); + } + if (NO_ERROR == ret) { + CameraBuffer *bufs = NULL; + unsigned int stride; + unsigned int height = frame.mHeight; + int size = frame.mLength; + + stride = frame.mAlignment / getBPP(mParameters.getPictureFormat()); + bufs = out->allocateBufferList(stride, + height, + mParameters.getPictureFormat(), + size, + bufferCount); + if (bufs == NULL){ + CAMHAL_LOGEB("error allocating buffer list"); + goto exit; + } + } + } + mOutAdapters.add(out); + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Releases Tapout Surfaces. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::releaseTapoutLocked(struct preview_stream_ops *tapout) +{ + status_t ret = NO_ERROR; + char id[OP_STR_SIZE]; + + LOG_FUNCTION_NAME; + + if (!tapout) { + CAMHAL_LOGD("Missing argument"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + // Get the name of tapout + ret = mExtendedPreviewStreamOps->get_id(tapout, id, sizeof(id)); + if (NO_ERROR != ret) { + CAMHAL_LOGEB("get_id OPS returned error %d", ret); + return ret; + } + + // 1. Check name of tap-out + // 2. If exist, then free buffers and then remove it + if (mBufferSourceAdapter_Out.get() && mBufferSourceAdapter_Out->match(id)) { + CAMHAL_LOGD("REMOVE tap out %p previously set as current", tapout); + mBufferSourceAdapter_Out.clear(); + } + for (unsigned int i = 0; i < mOutAdapters.size(); i++) { + android::sp out; + out = mOutAdapters.itemAt(i); + if (out->match(id)) { + CAMHAL_LOGD("REMOVE tap out %p \"%s\" at position %d", tapout, id, i); + mOutAdapters.removeAt(i); + break; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Sets Tapin Surfaces. + + Buffers provided to CameraHal via this object for tap-in + functionality. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::setTapinLocked(struct preview_stream_ops *tapin) +{ + status_t ret = NO_ERROR; + int index = -1; + + LOG_FUNCTION_NAME; + + if (!tapin) { + CAMHAL_LOGD("Missing argument"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + // 1. Set tapin point + // 1. Check name of tap-in + // 2. If not already set, then create a new one + // 3. Allocate buffers. If user is re-setting the surface, free buffers first and re-allocate + // in case dimensions have changed + for (unsigned int i = 0; i < mInAdapters.size(); i++) { + android::sp in; + in = mInAdapters.itemAt(i); + ret = in->setPreviewWindow(tapin); + if (ret == ALREADY_EXISTS) { + CAMHAL_LOGD("Tap In already set at index = %d", i); + index = i; + ret = NO_ERROR; + } + } + + if (index < 0) { + android::sp in = new BufferSourceAdapter(); + + ret = in->initialize(); + if (ret != NO_ERROR) { + in.clear(); + CAMHAL_LOGEA("DisplayAdapter initialize failed"); + goto exit; + } + + // BufferSourceAdapter will be handler of the extended OPS + in->setExtendedOps(mExtendedPreviewStreamOps); + + // CameraAdapter will be the frame provider for BufferSourceAdapter + in->setFrameProvider(mCameraAdapter); + + // BufferSourceAdapter will use ErrorHandler to send errors back to + // the application + in->setErrorHandler(mAppCallbackNotifier.get()); + + // Update the display adapter with the new window that is passed from CameraService + ret = in->setPreviewWindow(tapin); + if(ret != NO_ERROR) { + CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); + goto exit; + } + + mInAdapters.add(in); + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +/** + @brief Releases Tapin Surfaces. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::releaseTapinLocked(struct preview_stream_ops *tapin) +{ + status_t ret = NO_ERROR; + char id[OP_STR_SIZE]; + + LOG_FUNCTION_NAME; + + if (!tapin) { + CAMHAL_LOGD("Missing argument"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + // Get the name of tapin + ret = mExtendedPreviewStreamOps->get_id(tapin, id, sizeof(id)); + if (NO_ERROR != ret) { + CAMHAL_LOGEB("get_id OPS returned error %d", ret); + return ret; + } + + // 1. Check name of tap-in + // 2. If exist, then free buffers and then remove it + if (mBufferSourceAdapter_In.get() && mBufferSourceAdapter_In->match(id)) { + CAMHAL_LOGD("REMOVE tap in %p previously set as current", tapin); + mBufferSourceAdapter_In.clear(); + } + for (unsigned int i = 0; i < mInAdapters.size(); i++) { + android::sp in; + in = mInAdapters.itemAt(i); + if (in->match(id)) { + CAMHAL_LOGD("REMOVE tap in %p \"%s\" at position %d", tapin, id, i); + mInAdapters.removeAt(i); + break; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +/** + @brief Sets ANativeWindow object. + + Buffers provided to CameraHal via this object for tap-in/tap-out + functionality. + + TODO(XXX): this is just going to use preview_stream_ops for now, but we + most likely need to extend it when we want more functionality + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::setBufferSource(struct preview_stream_ops *tapin, struct preview_stream_ops *tapout) +{ + status_t ret = NO_ERROR; + int index = -1; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + CAMHAL_LOGD ("setBufferSource(%p, %p)", tapin, tapout); + + ret = setTapoutLocked(tapout); + if (ret != NO_ERROR) { + CAMHAL_LOGE("setTapoutLocked returned error 0x%x", ret); + goto exit; + } + + ret = setTapinLocked(tapin); + if (ret != NO_ERROR) { + CAMHAL_LOGE("setTapinLocked returned error 0x%x", ret); + goto exit; + } + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +/** + @brief Releases ANativeWindow object. + + Release Buffers previously released with setBufferSource() + + TODO(XXX): this is just going to use preview_stream_ops for now, but we + most likely need to extend it when we want more functionality + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::releaseBufferSource(struct preview_stream_ops *tapin, struct preview_stream_ops *tapout) +{ + status_t ret = NO_ERROR; + int index = -1; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + CAMHAL_LOGD ("releaseBufferSource(%p, %p)", tapin, tapout); + if (tapout) { + ret |= releaseTapoutLocked(tapout); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Error %d to release tap out", ret); + } + } + + if (tapin) { + ret |= releaseTapinLocked(tapin); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Error %d to release tap in", ret); + } + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} +#endif + + +/** + @brief Stop a previously started preview. + + @param none + @return none + + */ +void CameraHal::stopPreview() +{ + LOG_FUNCTION_NAME; + + if( (!previewEnabled() && !mDisplayPaused) || mRecordingEnabled) + { + LOG_FUNCTION_NAME_EXIT; + return; + } + + bool imageCaptureRunning = (mCameraAdapter->getState() & CameraAdapter::CAPTURE_STATE) && + (mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE); + if(mDisplayPaused && !imageCaptureRunning) + { + // Display is paused, which essentially means there is no preview active. + // Note: this is done so that when stopPreview is called by client after + // an image capture, we do not de-initialize the camera adapter and + // restart over again. + + return; + } + + forceStopPreview(); + + // Reset Capture-Mode to default, so that when we switch from VideoRecording + // to ImageCapture, CAPTURE_MODE is not left to VIDEO_MODE. + CAMHAL_LOGDA("Resetting Capture-Mode to default"); + mParameters.set(TICameraParameters::KEY_CAP_MODE, ""); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Returns true if preview is enabled + + @param none + @return true If preview is running currently + false If preview has been stopped + + */ +bool CameraHal::previewEnabled() +{ + LOG_FUNCTION_NAME; + + return (mPreviewEnabled || mPreviewStartInProgress); +} + +/** + @brief Start record mode. + + When a record image is available a CAMERA_MSG_VIDEO_FRAME message is sent with + the corresponding frame. Every record frame must be released by calling + releaseRecordingFrame(). + + @param none + @return NO_ERROR If recording could be started without any issues + @todo Update the header with possible error values in failure scenarios + + */ +status_t CameraHal::startRecording( ) +{ + int w, h; + const char *valstr = NULL; + bool restartPreviewRequired = false; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartPreview, NULL); + +#endif + + if(!previewEnabled()) + { + return NO_INIT; + } + + // set internal recording hint in case camera adapter needs to make some + // decisions....(will only be sent to camera adapter if camera restart is required) + mParameters.set(TICameraParameters::KEY_RECORDING_HINT, android::CameraParameters::TRUE); + + // if application starts recording in continuous focus picture mode... + // then we need to force default capture mode (as opposed to video mode) + if ( ((valstr = mParameters.get(android::CameraParameters::KEY_FOCUS_MODE)) != NULL) && + (strcmp(valstr, android::CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) == 0) ){ + restartPreviewRequired = resetVideoModeParameters(); + } + + // only need to check recording hint if preview restart is not already needed + valstr = mParameters.get(android::CameraParameters::KEY_RECORDING_HINT); + if ( !restartPreviewRequired && + (!valstr || (valstr && (strcmp(valstr, android::CameraParameters::TRUE) != 0))) ) { + restartPreviewRequired = setVideoModeParameters(mParameters); + } + + if (restartPreviewRequired) { + { + android::AutoMutex lock(mLock); + mCapModeBackup = mParameters.get(TICameraParameters::KEY_CAP_MODE); + } + ret = restartPreview(); + } + + if ( NO_ERROR == ret ) + { + int count = atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS)); + mParameters.getPreviewSize(&w, &h); + CAMHAL_LOGDB("%s Video Width=%d Height=%d", __FUNCTION__, mVideoWidth, mVideoHeight); + + if ((w != mVideoWidth) && (h != mVideoHeight)) + { + ret = allocVideoBufs(mVideoWidth, mVideoHeight, count); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("allocImageBufs returned error 0x%x", ret); + mParameters.remove(TICameraParameters::KEY_RECORDING_HINT); + return ret; + } + + mAppCallbackNotifier->useVideoBuffers(true); + mAppCallbackNotifier->setVideoRes(mVideoWidth, mVideoHeight); + ret = mAppCallbackNotifier->initSharedVideoBuffers(mPreviewBuffers, mPreviewOffsets, mPreviewFd, mPreviewLength, count, mVideoBuffers); + } + else + { + mAppCallbackNotifier->useVideoBuffers(false); + mAppCallbackNotifier->setVideoRes(mPreviewWidth, mPreviewHeight); + ret = mAppCallbackNotifier->initSharedVideoBuffers(mPreviewBuffers, mPreviewOffsets, mPreviewFd, mPreviewLength, count, NULL); + } + } + + if ( NO_ERROR == ret ) + { + ret = mAppCallbackNotifier->startRecording(); + } + + if ( NO_ERROR == ret ) + { + ///Buffers for video capture (if different from preview) are expected to be allocated within CameraAdapter + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_VIDEO); + } + + if ( NO_ERROR == ret ) + { + mRecordingEnabled = true; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Set the camera parameters specific to Video Recording. + + This function checks for the camera parameters which have to be set for recording. + Video Recording needs CAPTURE_MODE to be VIDEO_MODE. This function sets it. + This function also enables Video Recording specific functions like VSTAB & VNF. + + @param none + @return true if preview needs to be restarted for VIDEO_MODE parameters to take effect. + @todo Modify the policies for enabling VSTAB & VNF usecase based later. + + */ +bool CameraHal::setVideoModeParameters(const android::CameraParameters& params) +{ + const char *valstr = NULL; + const char *valstrRemote = NULL; + bool restartPreviewRequired = false; + + LOG_FUNCTION_NAME; + + // Set CAPTURE_MODE to VIDEO_MODE, if not set already and Restart Preview + valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); + if ( (valstr == NULL) || + ( (valstr != NULL) && ( (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) != 0) && + (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE_HQ ) != 0) ) ) ) { + CAMHAL_LOGDA("Set CAPTURE_MODE to VIDEO_MODE"); + mParameters.set(TICameraParameters::KEY_CAP_MODE, (const char *) TICameraParameters::VIDEO_MODE); + restartPreviewRequired = true; + } + + // set VSTAB, restart is required if VSTAB value has changed + int prevWidth, prevHeight; + params.getPreviewSize(&prevWidth, &prevHeight); + valstr = mParameters.get(android::CameraParameters::KEY_VIDEO_STABILIZATION); + if (prevWidth == 1920 && + (mSocFamily == SocFamily_Omap4430 || mSocFamily == SocFamily_Omap4460)) { + // forcibly set to false because of not enough memory for needed buffer size in this case + CAMHAL_LOGDA("Forcing VSTAB off"); + if (strcmp(valstr, android::CameraParameters::FALSE) != 0) { + restartPreviewRequired = true; + } + mParameters.set(android::CameraParameters::KEY_VIDEO_STABILIZATION, + android::CameraParameters::FALSE); + } else { + if ((valstrRemote = params.get(android::CameraParameters::KEY_VIDEO_STABILIZATION)) != NULL) { + // make sure we support vstab + if (strcmp(mCameraProperties->get(CameraProperties::VSTAB_SUPPORTED), + android::CameraParameters::TRUE) == 0) { + if (strcmp(valstr, valstrRemote) != 0) { + restartPreviewRequired = true; + } + mParameters.set(android::CameraParameters::KEY_VIDEO_STABILIZATION, + valstrRemote); + } + } else if (mParameters.get(android::CameraParameters::KEY_VIDEO_STABILIZATION)) { + // vstab was configured but now unset + restartPreviewRequired = true; + mParameters.remove(android::CameraParameters::KEY_VIDEO_STABILIZATION); + } + } + + // Set VNF + if ((valstrRemote = params.get(TICameraParameters::KEY_VNF)) == NULL) { + CAMHAL_LOGDA("Enable VNF"); + mParameters.set(TICameraParameters::KEY_VNF, android::CameraParameters::TRUE); + restartPreviewRequired = true; + } else { + valstr = mParameters.get(TICameraParameters::KEY_VNF); + if (valstr && strcmp(valstr, valstrRemote) != 0) { + restartPreviewRequired = true; + } + mParameters.set(TICameraParameters::KEY_VNF, valstrRemote); + } + +#if !defined(OMAP_ENHANCEMENT) && !defined(ENHANCED_DOMX) + // For VSTAB alone for 1080p resolution, padded width goes > 2048, which cannot be rendered by GPU. + // In such case, there is support in Ducati for combination of VSTAB & VNF requiring padded width < 2048. + // So we are forcefully enabling VNF, if VSTAB is enabled for 1080p resolution. + int w, h; + params.getPreviewSize(&w, &h); + valstr = mParameters.get(android::CameraParameters::KEY_VIDEO_STABILIZATION); + if (valstr && (strcmp(valstr, android::CameraParameters::TRUE) == 0) && (w == 1920)) { + CAMHAL_LOGDA("Force Enable VNF for 1080p"); + const char *valKeyVnf = mParameters.get(TICameraParameters::KEY_VNF); + if(!valKeyVnf || (strcmp(valKeyVnf, android::CameraParameters::TRUE) != 0)) { + mParameters.set(TICameraParameters::KEY_VNF, android::CameraParameters::TRUE); + restartPreviewRequired = true; + } + } +#endif + + LOG_FUNCTION_NAME_EXIT; + + return restartPreviewRequired; +} + +/** + @brief Reset the camera parameters specific to Video Recording. + + This function resets CAPTURE_MODE and disables Recording specific functions like VSTAB & VNF. + + @param none + @return true if preview needs to be restarted for VIDEO_MODE parameters to take effect. + + */ +bool CameraHal::resetVideoModeParameters() +{ + const char *valstr = NULL; + bool restartPreviewRequired = false; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + // ignore this if we are already recording + if (mRecordingEnabled) { + return false; + } + + // Set CAPTURE_MODE to VIDEO_MODE, if not set already and Restart Preview + valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); + if ((valstr != NULL) && (strcmp(valstr, TICameraParameters::VIDEO_MODE) == 0)) { + CAMHAL_LOGDA("Reset Capture-Mode to default"); + mParameters.set(TICameraParameters::KEY_CAP_MODE, ""); + restartPreviewRequired = true; + } + + LOG_FUNCTION_NAME_EXIT; + + return restartPreviewRequired; +} + +/** + @brief Restart the preview with setParameter. + + This function restarts preview, for some VIDEO_MODE parameters to take effect. + + @param none + @return NO_ERROR If recording parameters could be set without any issues + + */ +status_t CameraHal::restartPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + // Retain CAPTURE_MODE before calling stopPreview(), since it is reset in stopPreview(). + + forceStopPreview(); + + { + android::AutoMutex lock(mLock); + if (!mCapModeBackup.isEmpty()) { + mParameters.set(TICameraParameters::KEY_CAP_MODE, mCapModeBackup.string()); + } else { + mParameters.set(TICameraParameters::KEY_CAP_MODE, ""); + } + mCameraAdapter->setParameters(mParameters); + } + + ret = startPreview(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Stop a previously started recording. + + @param none + @return none + + */ +void CameraHal::stopRecording() +{ + CameraAdapter::AdapterState currentState; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if (!mRecordingEnabled ) + { + return; + } + + currentState = mCameraAdapter->getState(); + if (currentState == CameraAdapter::VIDEO_CAPTURE_STATE) { + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE); + } + + mAppCallbackNotifier->stopRecording(); + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_VIDEO); + + mRecordingEnabled = false; + + if ( mAppCallbackNotifier->getUesVideoBuffers() ){ + freeVideoBufs(mVideoBuffers); + if (mVideoBuffers){ + CAMHAL_LOGVB(" FREEING mVideoBuffers %p", mVideoBuffers); + delete [] mVideoBuffers; + } + mVideoBuffers = NULL; + } + + // reset internal recording hint in case camera adapter needs to make some + // decisions....(will only be sent to camera adapter if camera restart is required) + mParameters.remove(TICameraParameters::KEY_RECORDING_HINT); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Returns true if recording is enabled. + + @param none + @return true If recording is currently running + false If recording has been stopped + + */ +int CameraHal::recordingEnabled() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return mRecordingEnabled; +} + +/** + @brief Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + + @param[in] mem MemoryBase pointer to the frame being released. Must be one of the buffers + previously given by CameraHal + @return none + + */ +void CameraHal::releaseRecordingFrame(const void* mem) +{ + LOG_FUNCTION_NAME; + + //CAMHAL_LOGDB(" 0x%x", mem->pointer()); + + if ( ( mRecordingEnabled ) && mem != NULL) + { + mAppCallbackNotifier->releaseRecordingFrame(mem); + } + + LOG_FUNCTION_NAME_EXIT; + + return; +} + +/** + @brief Start auto focus + + This call asynchronous. + The notification callback routine is called with CAMERA_MSG_FOCUS once when + focusing is complete. autoFocus() will be called again if another auto focus is + needed. + + @param none + @return NO_ERROR + @todo Define the error codes if the focus is not locked + + */ +status_t CameraHal::autoFocus() +{ + status_t ret = NO_ERROR; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartFocus, NULL); + +#endif + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + mMsgEnabled |= CAMERA_MSG_FOCUS; + + if ( NULL == mCameraAdapter ) + { + ret = -1; + goto EXIT; + } + + CameraAdapter::AdapterState state; + ret = mCameraAdapter->getState(state); + if (ret != NO_ERROR) + { + goto EXIT; + } + + if ((state == CameraAdapter::AF_STATE) || (state == CameraAdapter::VIDEO_AF_STATE)) + { + CAMHAL_LOGI("Ignoring start-AF (already in progress)"); + goto EXIT; + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass the autoFocus timestamp along with the command to camera adapter + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_PERFORM_AUTOFOCUS, ( int ) &mStartFocus); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_PERFORM_AUTOFOCUS); + +#endif + +EXIT: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Cancels auto-focus function. + + If the auto-focus is still in progress, this function will cancel it. + Whether the auto-focus is in progress or not, this function will return the + focus position to the default. If the camera does not support auto-focus, this is a no-op. + + + @param none + @return NO_ERROR If the cancel succeeded + @todo Define error codes if cancel didnt succeed + + */ +status_t CameraHal::cancelAutoFocus() +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + android::CameraParameters adapterParams = mParameters; + mMsgEnabled &= ~CAMERA_MSG_FOCUS; + + if( NULL != mCameraAdapter ) + { + adapterParams.set(TICameraParameters::KEY_AUTO_FOCUS_LOCK, android::CameraParameters::FALSE); + mCameraAdapter->setParameters(adapterParams); + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_CANCEL_AUTOFOCUS); + mAppCallbackNotifier->flushEventQueue(); + } + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + +void CameraHal::setEventProvider(int32_t eventMask, MessageNotifier * eventNotifier) +{ + + LOG_FUNCTION_NAME; + + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + delete mEventProvider; + mEventProvider = NULL; + } + + mEventProvider = new EventProvider(eventNotifier, this, eventCallbackRelay); + if ( NULL == mEventProvider ) + { + CAMHAL_LOGEA("Error in creating EventProvider"); + } + else + { + mEventProvider->enableEventNotification(eventMask); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void CameraHal::eventCallbackRelay(CameraHalEvent* event) +{ + LOG_FUNCTION_NAME; + + CameraHal *appcbn = ( CameraHal * ) (event->mCookie); + appcbn->eventCallback(event ); + + LOG_FUNCTION_NAME_EXIT; +} + +void CameraHal::eventCallback(CameraHalEvent* event) +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + +status_t CameraHal::startImageBracketing() +{ + status_t ret = NO_ERROR; + CameraFrame frame; + CameraAdapter::BuffersDescriptor desc; + unsigned int max_queueable = 0; + + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartCapture, NULL); + +#endif + + LOG_FUNCTION_NAME; + + if(!previewEnabled() && !mDisplayPaused) + { + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if ( !mBracketingEnabled ) + { + return ret; + } + + if ( NO_ERROR == ret ) + { + mBracketingRunning = true; + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, + ( int ) &frame, + ( mBracketRangeNegative + 1 )); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setBurst(true); + } + } + + if ( NO_ERROR == ret ) + { + mParameters.getPictureSize(( int * ) &frame.mWidth, + ( int * ) &frame.mHeight); + + ret = allocImageBufs(frame.mWidth, + frame.mHeight, + frame.mLength, + mParameters.getPictureFormat(), + ( mBracketRangeNegative + 1 )); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("allocImageBufs returned error 0x%x", ret); + } + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + + desc.mBuffers = mImageBuffers; + desc.mOffsets = mImageOffsets; + desc.mFd = mImageFd; + desc.mLength = mImageLength; + desc.mCount = ( size_t ) ( mBracketRangeNegative + 1 ); + desc.mMaxQueueable = ( size_t ) ( mBracketRangeNegative + 1 ); + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE, + ( int ) &desc); + + if ( NO_ERROR == ret ) + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass capture timestamp along with the camera adapter command + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_BRACKET_CAPTURE, ( mBracketRangePositive + 1 ), (int) &mStartCapture); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_BRACKET_CAPTURE, ( mBracketRangePositive + 1 )); + +#endif + + } + } + + return ret; +} + +status_t CameraHal::stopImageBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if( !previewEnabled() ) + { + return NO_INIT; + } + + mBracketingRunning = false; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Take a picture. + + @param none + @return NO_ERROR If able to switch to image capture + @todo Define error codes if unable to switch to image capture + + */ +status_t CameraHal::takePicture(const char *params) +{ + // cancel AF state if needed (before any operation and mutex lock) + if ((mCameraAdapter->getState() == CameraAdapter::AF_STATE) || + (mCameraAdapter->getState() == CameraAdapter::VIDEO_AF_STATE)) { + cancelAutoFocus(); + } + + android::AutoMutex lock(mLock); + return __takePicture(params); +} + +/** + @brief Internal function for getting a captured image. + shared by takePicture and reprocess. + @param none + @return NO_ERROR If able to switch to image capture + @todo Define error codes if unable to switch to image capture + + */ +status_t CameraHal::__takePicture(const char *params, struct timeval *captureStart) +{ + status_t ret = NO_ERROR; + CameraFrame frame; + CameraAdapter::BuffersDescriptor desc; + int burst = -1; + const char *valstr = NULL; + unsigned int bufferCount = 1; + unsigned int max_queueable = 0; + unsigned int rawBufferCount = 1; + bool isCPCamMode = false; + android::sp outAdapter = 0; + bool reuseTapout = false; +#ifdef MOTOROLA_CAMERA + unsigned int intensity = DEFAULT_INTENSITY; +#endif + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( NULL == captureStart ) { + gettimeofday(&mStartCapture, NULL); + } else { + memcpy(&mStartCapture, captureStart, sizeof(struct timeval)); + } + +#endif + + LOG_FUNCTION_NAME; + + if(!previewEnabled() && !mDisplayPaused) + { + LOG_FUNCTION_NAME_EXIT; + CAMHAL_LOGEA("Preview not started..."); + return NO_INIT; + } + + valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); + + isCPCamMode = valstr && !strcmp(valstr, TICameraParameters::CP_CAM_MODE); + + // return error if we are already capturing + // however, we can queue a capture when in cpcam mode + if ( ((mCameraAdapter->getState() == CameraAdapter::CAPTURE_STATE && + mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE) || + (mCameraAdapter->getState() == CameraAdapter::VIDEO_CAPTURE_STATE && + mCameraAdapter->getNextState() != CameraAdapter::VIDEO_STATE)) && + !isCPCamMode) { + CAMHAL_LOGEA("Already capturing an image..."); + return NO_INIT; + } + + // we only support video snapshot if we are in video mode (recording hint is set) + if ( (mCameraAdapter->getState() == CameraAdapter::VIDEO_STATE) && + (valstr && ( strcmp(valstr, TICameraParameters::VIDEO_MODE) && + strcmp(valstr, TICameraParameters::VIDEO_MODE_HQ ) ) ) ) { + CAMHAL_LOGEA("Trying to capture while recording without recording hint set..."); + return INVALID_OPERATION; + } + +#ifdef OMAP_ENHANCEMENT_CPCAM + // check if camera application is using shots parameters + // api. parameters set here override anything set using setParameters + // TODO(XXX): Just going to use legacy TI parameters for now. Need + // add new APIs in CameraHal to utilize android::ShotParameters later, so + // we don't have to parse through the whole set of parameters + // in camera adapter + if (strlen(params) > 0) { + android::ShotParameters shotParams; + const char *valStr; + const char *valExpComp, *valExpGain; + int valNum; + + android::String8 shotParams8(params); + + shotParams.unflatten(shotParams8); + mParameters.remove(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE); + mParameters.remove(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + + valExpGain = shotParams.get(android::ShotParameters::KEY_EXP_GAIN_PAIRS); + valExpComp = shotParams.get(android::ShotParameters::KEY_EXP_COMPENSATION); + if (NULL != valExpComp) { + mParameters.set(TICameraParameters::KEY_EXP_BRACKETING_RANGE, valExpComp); + } else if (NULL != valExpGain) { + mParameters.set(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE, valExpGain); + } + + valNum = shotParams.getInt(android::ShotParameters::KEY_BURST); + if (valNum >= 0) { + mParameters.set(TICameraParameters::KEY_BURST, valNum); + burst = valNum; + } + + valStr = shotParams.get(android::ShotParameters::KEY_FLUSH_CONFIG); + if (valStr!= NULL) { + if ( 0 == strcmp(valStr, android::ShotParameters::TRUE) ) { + mParameters.set(TICameraParameters::KEY_FLUSH_SHOT_CONFIG_QUEUE, + android::CameraParameters::TRUE); + } else if ( 0 == strcmp(valStr, android::ShotParameters::FALSE) ) { + mParameters.set(TICameraParameters::KEY_FLUSH_SHOT_CONFIG_QUEUE, + android::CameraParameters::FALSE); + } + } + + valStr = shotParams.get(android::ShotParameters::KEY_CURRENT_TAP_OUT); + if (valStr != NULL) { + int index = -1; + for (unsigned int i = 0; i < mOutAdapters.size(); i++) { + if(mOutAdapters.itemAt(i)->match(valStr)) { + index = i; + break; + } + } + if (index < 0) { + CAMHAL_LOGE("Invalid tap out surface passed to camerahal"); + return BAD_VALUE; + } + CAMHAL_LOGD("Found matching out adapter at %d", index); + outAdapter = mOutAdapters.itemAt(index); + if ( outAdapter == mBufferSourceAdapter_Out ) { + reuseTapout = true; + } + } + + mCameraAdapter->setParameters(mParameters); + } else +#endif + { + // TODO(XXX): Should probably reset burst and bracketing params + // when we remove legacy TI parameters implementation + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture parameters set: ", &mStartCapture); + +#endif + + // if we are already in the middle of a capture and using the same + // tapout ST...then we just need setParameters and start image + // capture to queue more shots + if (((mCameraAdapter->getState() & CameraAdapter::CAPTURE_STATE) == + CameraAdapter::CAPTURE_STATE) && + (mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE) && + (reuseTapout) ) { +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + //pass capture timestamp along with the camera adapter command + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE, + (int) &mStartCapture); +#else + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE); +#endif + return ret; + } + + if ( !mBracketingRunning ) + { + // if application didn't set burst through android::ShotParameters + // then query from TICameraParameters + if ((burst == -1) && (NO_ERROR == ret)) { + burst = mParameters.getInt(TICameraParameters::KEY_BURST); + } + + //Allocate all buffers only in burst capture case + if ( burst > 0 ) { + // For CPCam mode...allocate for worst case burst + bufferCount = isCPCamMode || (burst > CameraHal::NO_BUFFERS_IMAGE_CAPTURE) ? + CameraHal::NO_BUFFERS_IMAGE_CAPTURE : burst; + + if (outAdapter.get()) { + if ( reuseTapout ) { + bufferCount = mImageCount; + } else { + bufferCount = outAdapter->getBufferCount(); + if (bufferCount < 1) { + bufferCount = NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP; + } + } + } + + if ( NULL != mAppCallbackNotifier.get() ) { + mAppCallbackNotifier->setBurst(true); + } + } else if ( mBracketingEnabled ) { + bufferCount = mBracketRangeNegative + 1; + if ( NULL != mAppCallbackNotifier.get() ) { + mAppCallbackNotifier->setBurst(false); + } + } else { + if ( NULL != mAppCallbackNotifier.get() ) { + mAppCallbackNotifier->setBurst(false); + } + } + + // pause preview during normal image capture + // do not pause preview if recording (video state) + if ( (NO_ERROR == ret) && (NULL != mDisplayAdapter.get()) ) { + if ((mCameraAdapter->getState() != CameraAdapter::VIDEO_STATE) && + (mCameraAdapter->getState() != CameraAdapter::VIDEO_AF_STATE)) { + mDisplayPaused = true; + mPreviewEnabled = false; + ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); + // since preview is paused we should stop sending preview frames too + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) { + mAppCallbackNotifier->disableMsgType (CAMERA_MSG_PREVIEW_FRAME); + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + mDisplayAdapter->setSnapshotTimeRef(&mStartCapture); +#endif + } + + // if we taking video snapshot... + if ((NO_ERROR == ret) && ((mCameraAdapter->getState() == CameraAdapter::VIDEO_STATE) || + (mCameraAdapter->getState() == CameraAdapter::VIDEO_AF_STATE))) { + // enable post view frames if not already enabled so we can internally + // save snapshot frames for generating thumbnail + if((mMsgEnabled & CAMERA_MSG_POSTVIEW_FRAME) == 0) { + mAppCallbackNotifier->enableMsgType(CAMERA_MSG_POSTVIEW_FRAME); + } + } + + if ( (NO_ERROR == ret) && (NULL != mCameraAdapter) ) + { +#ifdef MOTOROLA_CAMERA + intensity = getFlashIntensity(); + + if (intensity == 0) + { + //notification callback can be triggered with this to inform user + mParameters.set(android::CameraParameters::KEY_FLASH_MODE, android::CameraParameters::FLASH_MODE_OFF); + } + else if (intensity <= DEFAULT_INTENSITY) + { + mParameters.set(TICameraParameters::KEY_MOT_LEDFLASH, (int) intensity); + mParameters.set(TICameraParameters::KEY_MOT_LEDTORCH, (int) intensity); + } +#endif + + if ( NO_ERROR == ret ) + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, + ( int ) &frame, + bufferCount); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x", ret); + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture buffer size queried: ", &mStartCapture); + +#endif + + if (outAdapter.get()) { + // Avoid locking the tapout again when reusing it + if (!reuseTapout) { + // Need to reset buffers if we are switching adapters since we don't know + // the state of the new buffer list + ret = outAdapter->maxQueueableBuffers(max_queueable); + if (NO_ERROR != ret) { + CAMHAL_LOGE("Couldn't get max queuable"); + return ret; + } + mImageBuffers = outAdapter->getBuffers(true); + mImageOffsets = outAdapter->getOffsets(); + mImageFd = outAdapter->getFd(); + mImageLength = outAdapter->getSize(); + mImageCount = bufferCount; + mBufferSourceAdapter_Out = outAdapter; + } + } else { + mBufferSourceAdapter_Out.clear(); + // allocImageBufs will only allocate new buffers if mImageBuffers is NULL + if ( NO_ERROR == ret ) { + max_queueable = bufferCount; + ret = allocImageBufs(frame.mAlignment / getBPP(mParameters.getPictureFormat()), + frame.mHeight, + frame.mLength, + mParameters.getPictureFormat(), + bufferCount); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("allocImageBufs returned error 0x%x", ret); + } + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture buffers allocated: ", &mStartCapture); + memcpy(&mImageBuffers->ppmStamp, &mStartCapture, sizeof(struct timeval)); + +#endif + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + desc.mBuffers = mImageBuffers; + desc.mOffsets = mImageOffsets; + desc.mFd = mImageFd; + desc.mLength = mImageLength; + desc.mCount = ( size_t ) bufferCount; + desc.mMaxQueueable = ( size_t ) max_queueable; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE, + ( int ) &desc); + } + if (mRawCapture) { + if ( NO_ERROR == ret ) { + CAMHAL_LOGDB("Raw capture buffers setup - %s", mParameters.getPictureFormat()); + ret = allocRawBufs(mParameters.getInt(TICameraParameters::RAW_WIDTH), + mParameters.getInt(TICameraParameters::RAW_HEIGHT), + android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB, + rawBufferCount); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("allocRawBufs (for RAW capture) returned error 0x%x", ret); + } + } + + if ((NO_ERROR == ret) && ( NULL != mCameraAdapter )) { + desc.mBuffers = mVideoBuffers; + desc.mOffsets = mVideoOffsets; + desc.mFd = mVideoFd; + desc.mLength = mVideoLength; + desc.mCount = ( size_t ) rawBufferCount; + desc.mMaxQueueable = ( size_t ) rawBufferCount; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_VIDEO_CAPTURE, + ( int ) &desc); + } + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture buffers registered: ", &mStartCapture); + +#endif + + if ((ret == NO_ERROR) && mBufferSourceAdapter_Out.get()) { + mBufferSourceAdapter_Out->enableDisplay(0, 0, NULL); + } + + if ((NO_ERROR == ret) && (NULL != mCameraAdapter)) { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass capture timestamp along with the camera adapter command + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE, (int) &mStartCapture); + + CameraHal::PPM("Takepicture capture started: ", &mStartCapture); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE); + +#endif + + } + + return ret; +} + +/** + @brief Cancel a picture that was started with takePicture. + + Calling this method when no picture is being taken is a no-op. + + @param none + @return NO_ERROR If cancel succeeded. Cancel can succeed if image callback is not sent + @todo Define error codes + + */ +status_t CameraHal::cancelPicture( ) +{ + LOG_FUNCTION_NAME; + status_t ret = NO_ERROR; + + ret = signalEndImageCapture(); + return NO_ERROR; +} + +/** + @brief Return the camera parameters. + + @param none + @return Currently configured camera parameters + + */ +char* CameraHal::getParameters() +{ + android::String8 params_str8; + char* params_string; + const char * valstr = NULL; + + LOG_FUNCTION_NAME; + + if( NULL != mCameraAdapter ) + { + mCameraAdapter->getParameters(mParameters); + } + + if ( (valstr = mParameters.get(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT)) != NULL ) { + if (!strcmp(TICameraParameters::S3D_TB_FULL, valstr)) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PICTURE_TOPBOTTOM_SIZES)); + } else if (!strcmp(TICameraParameters::S3D_SS_FULL, valstr)) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PICTURE_SIDEBYSIDE_SIZES)); + } else if ((!strcmp(TICameraParameters::S3D_TB_SUBSAMPLED, valstr)) + || (!strcmp(TICameraParameters::S3D_SS_SUBSAMPLED, valstr))) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PICTURE_SUBSAMPLED_SIZES)); + } + } + + if ( (valstr = mParameters.get(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT)) != NULL ) { + if (!strcmp(TICameraParameters::S3D_TB_FULL, valstr)) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PREVIEW_TOPBOTTOM_SIZES)); + } else if (!strcmp(TICameraParameters::S3D_SS_FULL, valstr)) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES)); + } else if ((!strcmp(TICameraParameters::S3D_TB_SUBSAMPLED, valstr)) + || (!strcmp(TICameraParameters::S3D_SS_SUBSAMPLED, valstr))) { + mParameters.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, mParameters.get(TICameraParameters::KEY_SUPPORTED_PREVIEW_SUBSAMPLED_SIZES)); + } + } + + android::CameraParameters mParams = mParameters; + + // Handle RECORDING_HINT to Set/Reset Video Mode Parameters + valstr = mParameters.get(android::CameraParameters::KEY_RECORDING_HINT); + if(valstr != NULL) + { + if(strcmp(valstr, android::CameraParameters::TRUE) == 0) + { + //HACK FOR MMS MODE + resetPreviewRes(&mParams); + } + } + + // do not send internal parameters to upper layers + mParams.remove(TICameraParameters::KEY_RECORDING_HINT); + mParams.remove(TICameraParameters::KEY_AUTO_FOCUS_LOCK); + + params_str8 = mParams.flatten(); + + // camera service frees this string... + params_string = (char*) malloc(sizeof(char) * (params_str8.length()+1)); + strcpy(params_string, params_str8.string()); + + LOG_FUNCTION_NAME_EXIT; + + ///Return the current set of parameters + + return params_string; +} + + +#ifdef OMAP_ENHANCEMENT_CPCAM +/** + @brief Starts reprocessing operation. + */ +status_t CameraHal::reprocess(const char *params) +{ + status_t ret = NO_ERROR; + int bufferCount = 0; + CameraAdapter::BuffersDescriptor desc; + CameraBuffer *reprocBuffers = NULL; + android::ShotParameters shotParams; + const char *valStr = NULL; + struct timeval startReprocess; + + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&startReprocess, NULL); + +#endif + + // 0. Get tap in surface + if (strlen(params) > 0) { + android::String8 shotParams8(params); + shotParams.unflatten(shotParams8); + } + + valStr = shotParams.get(android::ShotParameters::KEY_CURRENT_TAP_IN); + if (valStr != NULL) { + int index = -1; + for (unsigned int i = 0; i < mInAdapters.size(); i++) { + if(mInAdapters.itemAt(i)->match(valStr)) { + index = i; + break; + } + } + if (index < 0) { + CAMHAL_LOGE("Invalid tap in surface passed to camerahal"); + return BAD_VALUE; + } + CAMHAL_LOGD("Found matching in adapter at %d", index); + mBufferSourceAdapter_In = mInAdapters.itemAt(index); + } else { + CAMHAL_LOGE("No tap in surface sent with shot config!"); + return BAD_VALUE; + } + + // 1. Get buffers + if (mBufferSourceAdapter_In.get()) { + reprocBuffers = mBufferSourceAdapter_In->getBufferList(&bufferCount); + } + + if (!reprocBuffers) { + CAMHAL_LOGE("Error: couldn't get input buffers for reprocess()"); + goto exit; + } + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Got reprocess buffers: ", &startReprocess); + +#endif + + // 2. Get buffer information and parse parameters + { + shotParams.setBurst(bufferCount); + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + memcpy(&reprocBuffers->ppmStamp, &startReprocess, sizeof(struct timeval)); + +#endif + + // 3. Give buffer to camera adapter + desc.mBuffers = reprocBuffers; + desc.mOffsets = 0; + desc.mFd = 0; + desc.mLength = 0; + desc.mCount = (size_t) bufferCount; + desc.mMaxQueueable = (size_t) bufferCount; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_REPROCESS, (int) &desc); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Error calling camera use buffers"); + goto exit; + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Reprocess buffers registered: ", &startReprocess); + +#endif + + // 4. Start reprocessing + ret = mBufferSourceAdapter_In->enableDisplay(0, 0, NULL); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Error enabling tap in point"); + goto exit; + } + + // 4.5. cancel AF state if needed (before any operation and mutex lock) + if ((mCameraAdapter->getState() == CameraAdapter::AF_STATE) || + (mCameraAdapter->getState() == CameraAdapter::VIDEO_AF_STATE)) { + cancelAutoFocus(); + } + + // 5. Start capturing + ret = __takePicture(shotParams.flatten().string(), &startReprocess); + +exit: + return ret; +} + +/** + @brief Cancels current reprocessing operation + + */ +status_t CameraHal::cancel_reprocess( ) +{ + LOG_FUNCTION_NAME; + status_t ret = NO_ERROR; + + ret = signalEndImageCapture(); + return NO_ERROR; +} +#endif + + +void CameraHal::putParameters(char *parms) +{ + free(parms); +} + +/** + @brief Send command to camera driver. + + @param none + @return NO_ERROR If the command succeeds + @todo Define the error codes that this function can return + + */ +status_t CameraHal::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( ( NO_ERROR == ret ) && ( NULL == mCameraAdapter ) ) + { + CAMHAL_LOGEA("No CameraAdapter instance"); + return -EINVAL; + } + + /////////////////////////////////////////////////////// + // Following commands NEED preview to be started + /////////////////////////////////////////////////////// + + if ((!previewEnabled()) && ((cmd == CAMERA_CMD_START_SMOOTH_ZOOM) + || (cmd == CAMERA_CMD_STOP_SMOOTH_ZOOM) + || (cmd == CAMERA_CMD_START_FACE_DETECTION) +#ifdef OMAP_ENHANCEMENT_VTC + || (cmd == CAMERA_CMD_PREVIEW_DEINITIALIZATION) +#endif + )) + { + CAMHAL_LOGEA("sendCommand with cmd = 0x%x need preview to be started", cmd); + return BAD_VALUE; + } + + if ( NO_ERROR == ret ) + { + switch(cmd) + { + case CAMERA_CMD_START_SMOOTH_ZOOM: + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_SMOOTH_ZOOM, arg1); + + break; + + case CAMERA_CMD_STOP_SMOOTH_ZOOM: + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM); + + break; + + case CAMERA_CMD_START_FACE_DETECTION: + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_FD); + + break; + + case CAMERA_CMD_STOP_FACE_DETECTION: + if (previewEnabled()) { + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_FD); + } + + break; + +#ifdef OMAP_ENHANCEMENT_VTC + case CAMERA_CMD_PREVIEW_DEINITIALIZATION: + if(mDisplayAdapter.get() != NULL) { + ///Stop the buffer display first + mDisplayAdapter->disableDisplay(); + } + + if(mAppCallbackNotifier.get() != NULL) { + //Stop the callback sending + mAppCallbackNotifier->stop(); + mAppCallbackNotifier->flushAndReturnFrames(); + mAppCallbackNotifier->stopPreviewCallbacks(); + } + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_DESTROY_TUNNEL); + mTunnelSetup = false; + + break; + + case CAMERA_CMD_PREVIEW_INITIALIZATION: + ret = cameraPreviewInitialization(); + + break; +#endif + +#ifdef ANDROID_API_JB_OR_LATER + case CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG: + { + const bool enable = static_cast(arg1); + android::AutoMutex lock(mLock); + if ( enable ) { + mMsgEnabled |= CAMERA_MSG_FOCUS_MOVE; + } else { + mMsgEnabled &= ~CAMERA_MSG_FOCUS_MOVE; + } + break; + } +#endif + + default: + break; + }; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Release the hardware resources owned by this object. + + Note that this is *not* done in the destructor. + + @param none + @return none + + */ +void CameraHal::release() +{ + LOG_FUNCTION_NAME; + ///@todo Investigate on how release is used by CameraService. Vaguely remember that this is called + ///just before CameraHal object destruction + deinitialize(); + LOG_FUNCTION_NAME_EXIT; +} + + +/** + @brief Dump state of the camera hardware + + @param[in] fd File descriptor + @param[in] args Arguments + @return NO_ERROR Dump succeeded + @todo Error codes for dump fail + + */ +status_t CameraHal::dump(int fd) const +{ + LOG_FUNCTION_NAME; + ///Implement this method when the h/w dump function is supported on Ducati side + return NO_ERROR; +} + +/*-------------Camera Hal Interface Method definitions ENDS here--------------------*/ + + + + +/*-------------Camera Hal Internal Method definitions STARTS here--------------------*/ + +/** + @brief Constructor of CameraHal + + Member variables are initialized here. No allocations should be done here as we + don't use c++ exceptions in the code. + + */ +CameraHal::CameraHal(int cameraId) + : mSocFamily(getSocFamily()) +{ + LOG_FUNCTION_NAME; + + ///Initialize all the member variables to their defaults + mPreviewEnabled = false; + mPreviewBuffers = NULL; + mImageBuffers = NULL; + mBufProvider = NULL; + mPreviewStartInProgress = false; + mVideoBuffers = NULL; + mVideoBufProvider = NULL; + mRecordingEnabled = false; + mDisplayPaused = false; + mSetPreviewWindowCalled = false; + mMsgEnabled = 0; + mAppCallbackNotifier = NULL; + mMemoryManager = NULL; + mCameraAdapter = NULL; + mBracketingEnabled = false; + mBracketingRunning = false; + mEventProvider = NULL; + mBracketRangePositive = 1; + mBracketRangeNegative = 1; + mMaxZoomSupported = 0; + mShutterEnabled = true; + mMeasurementEnabled = false; + mPreviewDataBuffers = NULL; + mCameraProperties = NULL; + mCurrentTime = 0; + mFalsePreview = 0; + mImageOffsets = NULL; + mImageLength = 0; + mImageFd = 0; + mImageCount = 0; + mVideoOffsets = NULL; + mVideoFd = 0; + mVideoLength = 0; + mPreviewDataOffsets = NULL; + mPreviewDataFd = 0; + mPreviewDataLength = 0; + mPreviewFd = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + mPreviewLength = 0; + mPreviewOffsets = NULL; + mPreviewRunning = 0; + mPreviewStateOld = 0; + mRecordingEnabled = 0; + mRecordEnabled = 0; + mSensorListener = NULL; + mVideoWidth = 0; + mVideoHeight = 0; +#ifdef OMAP_ENHANCEMENT_VTC + mVTCUseCase = false; + mTunnelSetup = false; +#endif + mPreviewInitializationDone = false; + +#ifdef OMAP_ENHANCEMENT_CPCAM + mExtendedPreviewStreamOps = 0; +#endif + + //These values depends on the sensor characteristics + + mRawCapture = false; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Initialize the CameraHAL constructor timestamp, which is used in the + // PPM() method as time reference if the user does not supply one. + gettimeofday(&ppm_start, NULL); + +#endif + + mCameraIndex = cameraId; + + mExternalLocking = false; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Destructor of CameraHal + + This function simply calls deinitialize() to free up memory allocate during construct + phase + */ +CameraHal::~CameraHal() +{ + LOG_FUNCTION_NAME; + + ///Call de-initialize here once more - it is the last chance for us to relinquish all the h/w and s/w resources + deinitialize(); + + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + delete mEventProvider; + mEventProvider = NULL; + } + + /// Free the callback notifier + mAppCallbackNotifier.clear(); + + /// Free the display adapter + mDisplayAdapter.clear(); + + if ( NULL != mCameraAdapter ) { + int strongCount = mCameraAdapter->getStrongCount(); + + mCameraAdapter->decStrong(mCameraAdapter); + + mCameraAdapter = NULL; + } + + freeImageBufs(); + freeRawBufs(); + + /// Free the memory manager + mMemoryManager.clear(); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Initialize the Camera HAL + + Creates CameraAdapter, AppCallbackNotifier, DisplayAdapter and MemoryManager + + @param None + @return NO_ERROR - On success + NO_MEMORY - On failure to allocate memory for any of the objects + @remarks Camera Hal internal function + + */ + +status_t CameraHal::initialize(CameraProperties::Properties* properties) +{ + LOG_FUNCTION_NAME; + + int sensor_index = 0; + const char* sensor_name = NULL; + + ///Initialize the event mask used for registering an event provider for AppCallbackNotifier + ///Currently, registering all events as to be coming from CameraAdapter + int32_t eventMask = CameraHalEvent::ALL_EVENTS; + + // Get my camera properties + mCameraProperties = properties; + + if(!mCameraProperties) + { + goto fail_loop; + } + + // Dump the properties of this Camera + // will only print if DEBUG macro is defined + mCameraProperties->dump(); + + if (strcmp(CameraProperties::DEFAULT_VALUE, mCameraProperties->get(CameraProperties::CAMERA_SENSOR_INDEX)) != 0 ) + { + sensor_index = atoi(mCameraProperties->get(CameraProperties::CAMERA_SENSOR_INDEX)); + } + + if (strcmp(CameraProperties::DEFAULT_VALUE, mCameraProperties->get(CameraProperties::CAMERA_NAME)) != 0 ) { + sensor_name = mCameraProperties->get(CameraProperties::CAMERA_NAME); + } + CAMHAL_LOGDB("Sensor index= %d; Sensor name= %s", sensor_index, sensor_name); + + if (strcmp(sensor_name, V4L_CAMERA_NAME_USB) == 0) { +#ifdef V4L_CAMERA_ADAPTER + mCameraAdapter = V4LCameraAdapter_Factory(sensor_index, this); +#endif + } + else { +#ifdef OMX_CAMERA_ADAPTER + mCameraAdapter = OMXCameraAdapter_Factory(sensor_index); +#endif + } + + if ( ( NULL == mCameraAdapter ) || (mCameraAdapter->initialize(properties)!=NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize CameraAdapter"); + mCameraAdapter = NULL; + goto fail_loop; + } + + mCameraAdapter->incStrong(mCameraAdapter); + mCameraAdapter->registerImageReleaseCallback(releaseImageBuffers, (void *) this); + mCameraAdapter->registerEndCaptureCallback(endImageCapture, (void *)this); + + if(!mAppCallbackNotifier.get()) + { + /// Create the callback notifier + mAppCallbackNotifier = new AppCallbackNotifier(); + if( ( NULL == mAppCallbackNotifier.get() ) || ( mAppCallbackNotifier->initialize() != NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize AppCallbackNotifier"); + goto fail_loop; + } + } + + if(!mMemoryManager.get()) + { + /// Create Memory Manager + mMemoryManager = new MemoryManager(); + if( ( NULL == mMemoryManager.get() ) || ( mMemoryManager->initialize() != NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize MemoryManager"); + goto fail_loop; + } + } + + ///Setup the class dependencies... + + ///AppCallbackNotifier has to know where to get the Camera frames and the events like auto focus lock etc from. + ///CameraAdapter is the one which provides those events + ///Set it as the frame and event providers for AppCallbackNotifier + ///@remarks setEventProvider API takes in a bit mask of events for registering a provider for the different events + /// That way, if events can come from DisplayAdapter in future, we will be able to add it as provider + /// for any event + mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter); + mAppCallbackNotifier->setFrameProvider(mCameraAdapter); + + ///Any dynamic errors that happen during the camera use case has to be propagated back to the application + ///via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application + ///Set it as the error handler for CameraAdapter + mCameraAdapter->setErrorHandler(mAppCallbackNotifier.get()); + + ///Start the callback notifier + if(mAppCallbackNotifier->start() != NO_ERROR) + { + CAMHAL_LOGEA("Couldn't start AppCallbackNotifier"); + goto fail_loop; + } + + CAMHAL_LOGDA("Started AppCallbackNotifier.."); + mAppCallbackNotifier->setMeasurements(mMeasurementEnabled); + + ///Initialize default parameters + initDefaultParameters(); + + + if ( setParameters(mParameters) != NO_ERROR ) + { + CAMHAL_LOGEA("Failed to set default parameters?!"); + } + + // register for sensor events + mSensorListener = new SensorListener(); + if (mSensorListener.get()) { + if (mSensorListener->initialize() == NO_ERROR) { + mSensorListener->setCallbacks(orientation_cb, this); + mSensorListener->enableSensor(SensorListener::SENSOR_ORIENTATION); + } else { + CAMHAL_LOGEA("Error initializing SensorListener. not fatal, continuing"); + mSensorListener.clear(); + mSensorListener = NULL; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + + fail_loop: + + ///Free up the resources because we failed somewhere up + deinitialize(); + LOG_FUNCTION_NAME_EXIT; + + return NO_MEMORY; + +} + +bool CameraHal::isResolutionValid(unsigned int width, unsigned int height, const char *supportedResolutions) +{ + bool ret = false; + status_t status = NO_ERROR; + char tmpBuffer[MAX_PROP_VALUE_LENGTH]; + char *pos = NULL; + + LOG_FUNCTION_NAME; + + if (NULL == supportedResolutions) { + CAMHAL_LOGEA("Invalid supported resolutions string"); + goto exit; + } + + status = snprintf(tmpBuffer, MAX_PROP_VALUE_LENGTH - 1, "%dx%d", width, height); + if (0 > status) { + CAMHAL_LOGEA("Error encountered while generating validation string"); + goto exit; + } + + ret = isParameterValid(tmpBuffer, supportedResolutions); + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool CameraHal::isFpsRangeValid(int fpsMin, int fpsMax, const char *supportedFpsRanges) +{ + bool ret = false; + char supported[MAX_PROP_VALUE_LENGTH]; + char *pos; + int suppFpsRangeArray[2]; + int i = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == supportedFpsRanges ) { + CAMHAL_LOGEA("Invalid supported FPS ranges string"); + return false; + } + + if (fpsMin <= 0 || fpsMax <= 0 || fpsMin > fpsMax) { + return false; + } + + strncpy(supported, supportedFpsRanges, MAX_PROP_VALUE_LENGTH); + pos = strtok(supported, " (,)"); + while (pos != NULL) { + suppFpsRangeArray[i] = atoi(pos); + if (i++) { + if (fpsMin >= suppFpsRangeArray[0] && fpsMax <= suppFpsRangeArray[1]) { + ret = true; + break; + } + i = 0; + } + pos = strtok(NULL, " (,)"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool CameraHal::isParameterValid(const char *param, const char *supportedParams) +{ + bool ret = false; + char *pos; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + if (NULL == supportedParams) { + CAMHAL_LOGEA("Invalid supported parameters string"); + goto exit; + } + + if (NULL == param) { + CAMHAL_LOGEA("Invalid parameter string"); + goto exit; + } + + strncpy(supported, supportedParams, MAX_PROP_VALUE_LENGTH - 1); + + pos = strtok(supported, ","); + while (pos != NULL) { + if (!strcmp(pos, param)) { + ret = true; + break; + } + pos = strtok(NULL, ","); + } + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool CameraHal::isParameterValid(int param, const char *supportedParams) +{ + bool ret = false; + status_t status; + char tmpBuffer[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + if (NULL == supportedParams) { + CAMHAL_LOGEA("Invalid supported parameters string"); + goto exit; + } + + status = snprintf(tmpBuffer, MAX_PROP_VALUE_LENGTH - 1, "%d", param); + if (0 > status) { + CAMHAL_LOGEA("Error encountered while generating validation string"); + goto exit; + } + + ret = isParameterValid(tmpBuffer, supportedParams); + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::doesSetParameterNeedUpdate(const char* new_param, const char* old_param, bool& update) { + if (!new_param || !old_param) { + return -EINVAL; + } + + // if params mismatch we should update parameters for camera adapter + if ((strcmp(new_param, old_param) != 0)) { + update = true; + } + + return NO_ERROR; +} + +status_t CameraHal::parseResolution(const char *resStr, int &width, int &height) +{ + status_t ret = NO_ERROR; + char *ctx, *pWidth, *pHeight; + const char *sep = "x"; + + LOG_FUNCTION_NAME; + + if ( NULL == resStr ) + { + return -EINVAL; + } + + //This fixes "Invalid input resolution" + char *resStr_copy = (char *)malloc(strlen(resStr) + 1); + if ( NULL != resStr_copy ) + { + strcpy(resStr_copy, resStr); + pWidth = strtok_r(resStr_copy, sep, &ctx); + + if ( NULL != pWidth ) + { + width = atoi(pWidth); + } + else + { + CAMHAL_LOGEB("Invalid input resolution %s", resStr); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) + { + pHeight = strtok_r(NULL, sep, &ctx); + + if ( NULL != pHeight ) + { + height = atoi(pHeight); + } + else + { + CAMHAL_LOGEB("Invalid input resolution %s", resStr); + ret = -EINVAL; + } + } + + free(resStr_copy); + resStr_copy = NULL; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void CameraHal::insertSupportedParams() +{ + LOG_FUNCTION_NAME; + + android::CameraParameters &p = mParameters; + + ///Set the name of the camera + p.set(TICameraParameters::KEY_CAMERA_NAME, mCameraProperties->get(CameraProperties::CAMERA_NAME)); + + mMaxZoomSupported = atoi(mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_STAGES)); + + p.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIZES)); + p.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_FORMATS)); + p.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIZES)); + p.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS)); + p.set(TICameraParameters::KEY_SUPPORTED_PICTURE_SUBSAMPLED_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES)); + p.set(TICameraParameters::KEY_SUPPORTED_PICTURE_SIDEBYSIDE_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES)); + p.set(TICameraParameters::KEY_SUPPORTED_PICTURE_TOPBOTTOM_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES)); + p.set(TICameraParameters::KEY_SUPPORTED_PREVIEW_SUBSAMPLED_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES)); + p.set(TICameraParameters::KEY_SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES)); + p.set(TICameraParameters::KEY_SUPPORTED_PREVIEW_TOPBOTTOM_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES)); + p.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES)); + p.set(TICameraParameters::KEY_FRAMERATES_EXT_SUPPORTED, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES_EXT)); + p.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, mCameraProperties->get(CameraProperties::FRAMERATE_RANGE_SUPPORTED)); + p.set(TICameraParameters::KEY_FRAMERATE_RANGES_EXT_SUPPORTED, mCameraProperties->get(CameraProperties::FRAMERATE_RANGE_EXT_SUPPORTED)); + p.set(android::CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_THUMBNAIL_SIZES)); + p.set(android::CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, mCameraProperties->get(CameraProperties::SUPPORTED_WHITE_BALANCE)); + p.set(android::CameraParameters::KEY_SUPPORTED_EFFECTS, mCameraProperties->get(CameraProperties::SUPPORTED_EFFECTS)); + p.set(android::CameraParameters::KEY_SUPPORTED_SCENE_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_SCENE_MODES)); + p.set(android::CameraParameters::KEY_SUPPORTED_FLASH_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_FLASH_MODES)); + p.set(android::CameraParameters::KEY_SUPPORTED_FOCUS_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_FOCUS_MODES)); + p.set(android::CameraParameters::KEY_SUPPORTED_ANTIBANDING, mCameraProperties->get(CameraProperties::SUPPORTED_ANTIBANDING)); + p.set(android::CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::SUPPORTED_EV_MAX)); + p.set(android::CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::SUPPORTED_EV_MIN)); + p.set(android::CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, mCameraProperties->get(CameraProperties::SUPPORTED_EV_STEP)); + p.set(TICameraParameters::KEY_SUPPORTED_EXPOSURE, mCameraProperties->get(CameraProperties::SUPPORTED_EXPOSURE_MODES)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MAX, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MAX)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_STEP, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_STEP)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MAX, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MAX)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_STEP, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_STEP)); + p.set(TICameraParameters::KEY_SUPPORTED_ISO_VALUES, mCameraProperties->get(CameraProperties::SUPPORTED_ISO_VALUES)); + p.set(android::CameraParameters::KEY_ZOOM_RATIOS, mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_RATIOS)); + p.set(android::CameraParameters::KEY_MAX_ZOOM, mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_STAGES)); + p.set(android::CameraParameters::KEY_ZOOM_SUPPORTED, mCameraProperties->get(CameraProperties::ZOOM_SUPPORTED)); + p.set(android::CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, mCameraProperties->get(CameraProperties::SMOOTH_ZOOM_SUPPORTED)); + p.set(TICameraParameters::KEY_SUPPORTED_IPP, mCameraProperties->get(CameraProperties::SUPPORTED_IPP_MODES)); + p.set(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT_VALUES, mCameraProperties->get(CameraProperties::S3D_PRV_FRAME_LAYOUT_VALUES)); + p.set(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT_VALUES, mCameraProperties->get(CameraProperties::S3D_CAP_FRAME_LAYOUT_VALUES)); + p.set(TICameraParameters::KEY_AUTOCONVERGENCE_MODE_VALUES, mCameraProperties->get(CameraProperties::AUTOCONVERGENCE_MODE_VALUES)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_MIN, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MIN)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_MAX, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MAX)); + p.set(TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_STEP, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_STEP)); + p.set(android::CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED, mCameraProperties->get(CameraProperties::VSTAB_SUPPORTED)); + p.set(TICameraParameters::KEY_VNF_SUPPORTED, mCameraProperties->get(CameraProperties::VNF_SUPPORTED)); + p.set(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, mCameraProperties->get(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED)); + p.set(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, mCameraProperties->get(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED)); + p.set(android::CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, mCameraProperties->get(CameraProperties::VIDEO_SNAPSHOT_SUPPORTED)); + p.set(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED, mCameraProperties->get(CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED)); + p.set(TICameraParameters::KEY_CAP_MODE_VALUES, mCameraProperties->get(CameraProperties::CAP_MODE_VALUES)); + + LOG_FUNCTION_NAME_EXIT; + +} + +void CameraHal::initDefaultParameters() +{ + //Purpose of this function is to initialize the default current and supported parameters for the currently + //selected camera. + + android::CameraParameters &p = mParameters; + int currentRevision, adapterRevision; + status_t ret = NO_ERROR; + int width, height; + const char *valstr; + + LOG_FUNCTION_NAME; + + insertSupportedParams(); + + ret = parseResolution(mCameraProperties->get(CameraProperties::PREVIEW_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.setPreviewSize(width, height); + } + else + { + p.setPreviewSize(MIN_WIDTH, MIN_HEIGHT); + } + + ret = parseResolution(mCameraProperties->get(CameraProperties::PICTURE_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.setPictureSize(width, height); + } + else + { + p.setPictureSize(PICTURE_WIDTH, PICTURE_HEIGHT); + } + + ret = parseResolution(mCameraProperties->get(CameraProperties::JPEG_THUMBNAIL_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, width); + p.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, height); + } + else + { + p.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, MIN_WIDTH); + p.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, MIN_HEIGHT); + } + + //Insert default values + p.setPreviewFrameRate(atoi(mCameraProperties->get(CameraProperties::PREVIEW_FRAME_RATE))); + p.set(android::CameraParameters::KEY_PREVIEW_FPS_RANGE, mCameraProperties->get(CameraProperties::FRAMERATE_RANGE)); + p.set(TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE, mCameraProperties->get(CameraProperties::FRAMERATE_RANGE)); + p.setPreviewFormat(mCameraProperties->get(CameraProperties::PREVIEW_FORMAT)); + p.setPictureFormat(mCameraProperties->get(CameraProperties::PICTURE_FORMAT)); + p.set(android::CameraParameters::KEY_JPEG_QUALITY, mCameraProperties->get(CameraProperties::JPEG_QUALITY)); + p.set(android::CameraParameters::KEY_WHITE_BALANCE, mCameraProperties->get(CameraProperties::WHITEBALANCE)); + p.set(android::CameraParameters::KEY_EFFECT, mCameraProperties->get(CameraProperties::EFFECT)); + p.set(android::CameraParameters::KEY_ANTIBANDING, mCameraProperties->get(CameraProperties::ANTIBANDING)); + p.set(android::CameraParameters::KEY_FLASH_MODE, mCameraProperties->get(CameraProperties::FLASH_MODE)); + p.set(android::CameraParameters::KEY_FOCUS_MODE, mCameraProperties->get(CameraProperties::FOCUS_MODE)); + p.set(android::CameraParameters::KEY_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::EV_COMPENSATION)); + p.set(android::CameraParameters::KEY_SCENE_MODE, mCameraProperties->get(CameraProperties::SCENE_MODE)); + p.set(android::CameraParameters::KEY_ZOOM, mCameraProperties->get(CameraProperties::ZOOM)); + p.set(TICameraParameters::KEY_CONTRAST, mCameraProperties->get(CameraProperties::CONTRAST)); + p.set(TICameraParameters::KEY_SATURATION, mCameraProperties->get(CameraProperties::SATURATION)); + p.set(TICameraParameters::KEY_BRIGHTNESS, mCameraProperties->get(CameraProperties::BRIGHTNESS)); + p.set(TICameraParameters::KEY_SHARPNESS, mCameraProperties->get(CameraProperties::SHARPNESS)); + p.set(TICameraParameters::KEY_EXPOSURE_MODE, mCameraProperties->get(CameraProperties::EXPOSURE_MODE)); + p.set(TICameraParameters::KEY_MANUAL_EXPOSURE, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN)); + p.set(TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN)); + p.set(TICameraParameters::KEY_MANUAL_GAIN_ISO, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN)); + p.set(TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT, mCameraProperties->get(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN)); + p.set(TICameraParameters::KEY_ISO, mCameraProperties->get(CameraProperties::ISO_MODE)); + p.set(TICameraParameters::KEY_IPP, mCameraProperties->get(CameraProperties::IPP)); + p.set(TICameraParameters::KEY_GBCE, mCameraProperties->get(CameraProperties::GBCE)); + p.set(TICameraParameters::KEY_GBCE_SUPPORTED, mCameraProperties->get(CameraProperties::SUPPORTED_GBCE)); + p.set(TICameraParameters::KEY_GLBCE, mCameraProperties->get(CameraProperties::GLBCE)); + p.set(TICameraParameters::KEY_GLBCE_SUPPORTED, mCameraProperties->get(CameraProperties::SUPPORTED_GLBCE)); + p.set(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT, mCameraProperties->get(CameraProperties::S3D_PRV_FRAME_LAYOUT)); + p.set(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT, mCameraProperties->get(CameraProperties::S3D_CAP_FRAME_LAYOUT)); + p.set(TICameraParameters::KEY_AUTOCONVERGENCE_MODE, mCameraProperties->get(CameraProperties::AUTOCONVERGENCE_MODE)); + p.set(TICameraParameters::KEY_MANUAL_CONVERGENCE, mCameraProperties->get(CameraProperties::MANUAL_CONVERGENCE)); + p.set(android::CameraParameters::KEY_VIDEO_STABILIZATION, mCameraProperties->get(CameraProperties::VSTAB)); + p.set(TICameraParameters::KEY_VNF, mCameraProperties->get(CameraProperties::VNF)); + p.set(android::CameraParameters::KEY_FOCAL_LENGTH, mCameraProperties->get(CameraProperties::FOCAL_LENGTH)); + p.set(android::CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, mCameraProperties->get(CameraProperties::HOR_ANGLE)); + p.set(android::CameraParameters::KEY_VERTICAL_VIEW_ANGLE, mCameraProperties->get(CameraProperties::VER_ANGLE)); + p.set(TICameraParameters::KEY_SENSOR_ORIENTATION, mCameraProperties->get(CameraProperties::SENSOR_ORIENTATION)); + p.set(TICameraParameters::KEY_EXIF_MAKE, mCameraProperties->get(CameraProperties::EXIF_MAKE)); + p.set(TICameraParameters::KEY_EXIF_MODEL, mCameraProperties->get(CameraProperties::EXIF_MODEL)); + p.set(android::CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, mCameraProperties->get(CameraProperties::JPEG_THUMBNAIL_QUALITY)); + p.set(android::CameraParameters::KEY_VIDEO_FRAME_FORMAT, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar"); + p.set(android::CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, mCameraProperties->get(CameraProperties::MAX_FD_HW_FACES)); + p.set(android::CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, mCameraProperties->get(CameraProperties::MAX_FD_SW_FACES)); + p.set(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION, mCameraProperties->get(CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION)); + // Only one area a.k.a Touch AF for now. + // TODO: Add support for multiple focus areas. + p.set(android::CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, mCameraProperties->get(CameraProperties::MAX_FOCUS_AREAS)); + p.set(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK, mCameraProperties->get(CameraProperties::AUTO_EXPOSURE_LOCK)); + p.set(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, mCameraProperties->get(CameraProperties::AUTO_WHITEBALANCE_LOCK)); + p.set(android::CameraParameters::KEY_MAX_NUM_METERING_AREAS, mCameraProperties->get(CameraProperties::MAX_NUM_METERING_AREAS)); + p.set(TICameraParameters::RAW_WIDTH, mCameraProperties->get(CameraProperties::RAW_WIDTH)); + p.set(TICameraParameters::RAW_HEIGHT,mCameraProperties->get(CameraProperties::RAW_HEIGHT)); + + // TI extensions for enable/disable algos + // Hadcoded for now + p.set(TICameraParameters::KEY_ALGO_EXTERNAL_GAMMA, android::CameraParameters::FALSE); + p.set(TICameraParameters::KEY_ALGO_NSF1, android::CameraParameters::TRUE); + p.set(TICameraParameters::KEY_ALGO_NSF2, android::CameraParameters::TRUE); + p.set(TICameraParameters::KEY_ALGO_SHARPENING, android::CameraParameters::TRUE); + p.set(TICameraParameters::KEY_ALGO_THREELINCOLORMAP, android::CameraParameters::TRUE); + p.set(TICameraParameters::KEY_ALGO_GIC, android::CameraParameters::TRUE); + +#ifdef MOTOROLA_CAMERA + p.set(TICameraParameters::KEY_MOT_LEDFLASH, DEFAULT_INTENSITY); + p.set(TICameraParameters::KEY_MOT_LEDTORCH, DEFAULT_INTENSITY); +#endif + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Stop a previously started preview. + @param none + @return none + + */ +void CameraHal::forceStopPreview() +{ + LOG_FUNCTION_NAME; + + // stop bracketing if it is running + if ( mBracketingRunning ) { + stopImageBracketing(); + } + + if(mDisplayAdapter.get() != NULL) { + ///Stop the buffer display first + mDisplayAdapter->disableDisplay(); + } + + if(mAppCallbackNotifier.get() != NULL) { + //Stop the callback sending + mAppCallbackNotifier->stop(); + mAppCallbackNotifier->flushAndReturnFrames(); + mAppCallbackNotifier->stopPreviewCallbacks(); + } + + if ( NULL != mCameraAdapter ) { + // only need to send these control commands to state machine if we are + // passed the LOADED_PREVIEW_STATE + if (mCameraAdapter->getState() > CameraAdapter::LOADED_PREVIEW_STATE) { + // according to javadoc...FD should be stopped in stopPreview + // and application needs to call startFaceDection again + // to restart FD + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_FD); + } + + mCameraAdapter->rollbackToInitializedState(); + + } + + freePreviewBufs(); + freePreviewDataBufs(); + + mPreviewEnabled = false; + mDisplayPaused = false; + mPreviewStartInProgress = false; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Deallocates memory for all the resources held by Camera HAL. + + Frees the following objects- CameraAdapter, AppCallbackNotifier, DisplayAdapter, + and Memory Manager + + @param none + @return none + + */ +void CameraHal::deinitialize() +{ + LOG_FUNCTION_NAME; + + if ( mPreviewEnabled || mDisplayPaused ) { + forceStopPreview(); + } + + mSetPreviewWindowCalled = false; + + if (mSensorListener.get()) { + mSensorListener->disableSensor(SensorListener::SENSOR_ORIENTATION); + mSensorListener.clear(); + mSensorListener = NULL; + } + + mBufferSourceAdapter_Out.clear(); + mBufferSourceAdapter_In.clear(); + mOutAdapters.clear(); + mInAdapters.clear(); + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t CameraHal::storeMetaDataInBuffers(bool enable) +{ + LOG_FUNCTION_NAME; + + return mAppCallbackNotifier->useMetaDataBufferMode(enable); + + LOG_FUNCTION_NAME_EXIT; +} + +void CameraHal::setExternalLocking(bool extBuffLocking) +{ + mExternalLocking = extBuffLocking; +} + +void CameraHal::resetPreviewRes(android::CameraParameters *params) +{ + LOG_FUNCTION_NAME; + + if ( (mVideoWidth <= 320) && (mVideoHeight <= 240)){ + params->setPreviewSize(mVideoWidth, mVideoHeight); + } + + LOG_FUNCTION_NAME_EXIT; +} + +#ifdef MOTOROLA_CAMERA +#include +#include +#include + +#define EXT_MODULE_VENDOR_STRING "SHARP,OV8820" +#define INT_MODULE_VENDOR_STRING "SEMCO,OV7739" + +#define DCM_CAM_CONFIG_FILE "/data/system/dcm_camera.config" +#define CAMERA_ENABLED 0x73 +#define CAMERA_DISABLED 0x45 + +#define MOT_BURST_COUNT "mot-burst-picture-count" +#define MOT_BURST_COUNT_VALUES "mot-burst-picture-count-values" +#define MOT_MAX_BURST_SIZE "mot-max-burst-size" +//Wide screen aspect ratio (16:9) +#define WIDE_AR 1.7 + +// TI supports arbitrary burst limits, so we +// go with what we've used on other platforms +#define SUPPORTED_BURSTS "0,1,3,6,9" + +#define TORCH_DRIVER_DEVICE "/dev/i2c-3" +#define TORCH_DEVICE_SLAVE_ADDR 0x53 +#define TORCH_DEVICE_CONTROL_REG 0x10 +#define TORCH_BRIGHTNESS_CONTROL_REG 0xA0 +#define TORCH_DEFAULT_BRIGHTNESS 0x02 +#define TORCH_ENABLE 0x0A +#define TORCH_DISABLE 0x0 +#define MAX_EXPOSURE_COMPENSATION 30 + +bool CameraHal::i2cRW(int read_size, int write_size, unsigned char *read_data, unsigned char *write_data) +{ + + int i2cfd = -1; + int i,j; + int ioctl_ret; + struct i2c_msg msgs[2]; + struct i2c_rdwr_ioctl_data i2c_trans; + bool retL = 0; + + enum { I2C_WRITE, I2C_READ }; + enum { ARG_BUS = 1, ARG_ADDR, ARG_READCNT, ARG_DATA }; + + msgs[0].addr = TORCH_DEVICE_SLAVE_ADDR; + msgs[0].flags = 0; + msgs[0].len = write_size; + msgs[0].buf = write_data; + + msgs[1].addr = TORCH_DEVICE_SLAVE_ADDR; + msgs[1].flags = I2C_M_RD; + msgs[1].len = read_size; + msgs[1].buf = read_data; + + i2c_trans.msgs = NULL; + i2c_trans.nmsgs = 0; + + if ((i2cfd = open(TORCH_DRIVER_DEVICE, O_RDWR)) < 0) { + CAMHAL_LOGD("failed to open %s", TORCH_DRIVER_DEVICE); + return 1; + } + + if ( write_size && read_size ) { + i2c_trans.msgs = &msgs[0]; + i2c_trans.nmsgs = 2; + } + else if (write_size) { + i2c_trans.msgs = &msgs[0]; + i2c_trans.nmsgs = 1; + } + else if (read_size) { + i2c_trans.msgs = &msgs[1]; + i2c_trans.nmsgs = 1; + } + else { + goto done; + } + + if ( write_size > 0 ) { + CAMHAL_LOGD("I2C_WRITE"); + for( i = 0; i < write_size; i++ ) + { + CAMHAL_LOGD( "%02X ", write_data[i] ); + } + } + + if( (ioctl_ret = ioctl( i2cfd, I2C_RDWR, &(i2c_trans))) < 0 ) + { + CAMHAL_LOGD("* failed driver call: ioctl returned %d", ioctl_ret); + retL = 1; + goto done; + } + + + if ( read_size > 0 ) { + CAMHAL_LOGD("I2C_READ"); + for( i = 0; i < read_size; i++ ) + { + CAMHAL_LOGD( "%02X ", read_data[i] ); + } + } + +done: + /* close the hardware */ + close(i2cfd); + + return retL; + +} + +unsigned int CameraHal::getFlashIntensity() +{ + unsigned int flashIntensity = DEFAULT_INTENSITY; + char value[PROPERTY_VALUE_MAX]; + unsigned long minFlashThreshold; + + if (property_get("ro.media.capture.flashIntensity", value, 0) > 0) + { + flashIntensity = atoi(value); + } + if (property_get("ro.media.capture.flashMinV", value, 0) > 0) + { + minFlashThreshold = atoi(value); + } + else + { + minFlashThreshold = FLASH_VOLTAGE_THRESHOLD2; + } + if ( minFlashThreshold != 0) + { + int fd = open("/sys/class/power_supply/battery/voltage_now", O_RDONLY); + if (fd < 0) + { + CAMHAL_LOGE("Battery status is unavailable, defaulting Flash intensity to MAX"); + } + else + { + char buf[8]; + if ( read(fd, buf, 8) < 0 ) + { + CAMHAL_LOGE("Unable to read battery status, defaulting flash intensity to MAX\n"); + } + else + { + unsigned long batteryLevel; + buf[7] = '\0'; + batteryLevel = atol(buf); + CAMHAL_LOGE("Current battery Level, %d uv", batteryLevel); + if (batteryLevel < minFlashThreshold) + { + CAMHAL_LOGE("Disabling flash due to low Battery"); + flashIntensity = 0; + } + else if (batteryLevel < FLASH_VOLTAGE_THRESHOLD1) + { + flashIntensity = flashIntensity >> 1 ; + } + } + close(fd); + } + } + CAMHAL_LOGE("flashIntensity = %d", flashIntensity); + return flashIntensity; +} + +bool CameraHal::SetFlashLedTorch( unsigned intensity ) +{ + android::CameraParameters params; + mCameraAdapter->getParameters(params); + CAMHAL_LOGE("CameraHalTI::SetFlashLedTorch %d", intensity); + unsigned char write_data[2]; + + if (intensity == 0) + { + write_data[0] = TORCH_DEVICE_CONTROL_REG; + write_data[1] = TORCH_DISABLE; + i2cRW(0, 2, NULL, write_data); + } + else + { + write_data[0] = TORCH_BRIGHTNESS_CONTROL_REG; + write_data[1] = TORCH_DEFAULT_BRIGHTNESS; + i2cRW(0, 2, NULL, write_data); + + write_data[0] = TORCH_DEVICE_CONTROL_REG; + write_data[1] = TORCH_ENABLE; + i2cRW(0, 2, NULL, write_data); + } + + return true; +} + +#endif + +void * +camera_buffer_get_omx_ptr (CameraBuffer *buffer) +{ + CAMHAL_LOGV("buffer_type %d opaque %p", buffer->type, buffer->opaque); + + if (buffer->type == CAMERA_BUFFER_ANW) { + buffer_handle_t *handle = (buffer_handle_t *)buffer->opaque; + CAMHAL_LOGV("anw %08x", *handle); + return (void *)*handle; + } else if (buffer->type == CAMERA_BUFFER_ION) { + return (void *)buffer->fd; + } else { + CAMHAL_LOGV("other %08x", buffer->opaque); + return (void *)buffer->opaque; + } +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/CameraHalCommon.cpp b/camera/CameraHalCommon.cpp new file mode 100644 index 0000000..ce01528 --- /dev/null +++ b/camera/CameraHalCommon.cpp @@ -0,0 +1,233 @@ +/* + * 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 "CameraHal.h" + +namespace Ti { +namespace Camera { + +const char CameraHal::PARAMS_DELIMITER []= ","; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +struct timeval CameraHal::ppm_start; + +#endif + +#if PPM_INSTRUMENTATION + +/** + @brief PPM instrumentation + + Dumps the current time offset. The time reference point + lies within the CameraHAL constructor. + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str){ + struct timeval ppm; + + gettimeofday(&ppm, NULL); + ppm.tv_sec = ppm.tv_sec - ppm_start.tv_sec; + ppm.tv_sec = ppm.tv_sec * 1000000; + ppm.tv_sec = ppm.tv_sec + ppm.tv_usec - ppm_start.tv_usec; + + CAMHAL_LOGI("PPM: %s :%ld.%ld ms", str, ( ppm.tv_sec /1000 ), ( ppm.tv_sec % 1000 )); +} + +#elif PPM_INSTRUMENTATION_ABS + +/** + @brief PPM instrumentation + + Dumps the current time offset. The time reference point + lies within the CameraHAL constructor. This implemetation + will also dump the abosolute timestamp, which is useful when + post calculation is done with data coming from the upper + layers (Camera application etc.) + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str){ + struct timeval ppm; + + unsigned long long elapsed, absolute; + gettimeofday(&ppm, NULL); + elapsed = ppm.tv_sec - ppm_start.tv_sec; + elapsed *= 1000000; + elapsed += ppm.tv_usec - ppm_start.tv_usec; + absolute = ppm.tv_sec; + absolute *= 1000; + absolute += ppm.tv_usec /1000; + + CAMHAL_LOGI("PPM: %s :%llu.%llu ms : %llu ms", str, ( elapsed /1000 ), ( elapsed % 1000 ), absolute); +} + +#endif + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +/** + @brief PPM instrumentation + + Calculates and dumps the elapsed time using 'ppm_first' as + reference. + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str, struct timeval* ppm_first, ...){ + char temp_str[256]; + struct timeval ppm; + unsigned long long absolute; + va_list args; + + va_start(args, ppm_first); + vsprintf(temp_str, str, args); + gettimeofday(&ppm, NULL); + absolute = ppm.tv_sec; + absolute *= 1000; + absolute += ppm.tv_usec /1000; + ppm.tv_sec = ppm.tv_sec - ppm_first->tv_sec; + ppm.tv_sec = ppm.tv_sec * 1000000; + ppm.tv_sec = ppm.tv_sec + ppm.tv_usec - ppm_first->tv_usec; + + CAMHAL_LOGI("PPM: %s :%ld.%ld ms : %llu ms", temp_str, ( ppm.tv_sec /1000 ), ( ppm.tv_sec % 1000 ), absolute); + + va_end(args); +} + +#endif + + +/** Common utility function definitions used all over the HAL */ + +unsigned int CameraHal::getBPP(const char* format) { + unsigned int bytesPerPixel; + + // Calculate bytes per pixel based on the pixel format + if (strcmp(format, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + bytesPerPixel = 2; + } else if (strcmp(format, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0 || + strcmp(format, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) { + bytesPerPixel = 2; + } else if (strcmp(format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + bytesPerPixel = 1; + } else { + bytesPerPixel = 1; + } + + return bytesPerPixel; +} + +void CameraHal::getXYFromOffset(unsigned int *x, unsigned int *y, + unsigned int offset, unsigned int stride, + const char* format) +{ + CAMHAL_ASSERT( x && y && format && (0U < stride) ); + + *x = (offset % stride) / getBPP(format); + *y = (offset / stride); +} + +const char* CameraHal::getPixelFormatConstant(const char* parametersFormat) +{ + const char *pixelFormat = NULL; + + if ( NULL != parametersFormat ) { + if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_YUV422I) ) { + CAMHAL_LOGVA("CbYCrY format selected"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_YUV422I; + } else if ( (0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_YUV420SP)) || + (0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_YUV420P)) ) { + // TODO(XXX): We are treating YV12 the same as YUV420SP + CAMHAL_LOGVA("YUV420SP format selected"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_YUV420SP; + } else if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_RGB565) ) { + CAMHAL_LOGVA("RGB565 format selected"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_RGB565; + } else if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ) { + CAMHAL_LOGVA("BAYER format selected"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB; + } else if ( 0 == strcmp(parametersFormat, android::CameraParameters::PIXEL_FORMAT_JPEG) ) { + CAMHAL_LOGVA("JPEG format selected"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_JPEG; + } else { + CAMHAL_LOGEA("Invalid format, NV12 format selected as default"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_YUV420SP; + } + } else { + CAMHAL_LOGEA("Preview format is NULL, defaulting to NV12"); + pixelFormat = (const char *) android::CameraParameters::PIXEL_FORMAT_YUV420SP; + } + + return pixelFormat; +} + +size_t CameraHal::calculateBufferSize(const char* parametersFormat, int width, int height) +{ + int bufferSize = -1; + + if ( NULL != parametersFormat ) { + if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_YUV422I) ) { + bufferSize = width * height * 2; + } else if ( (0 == strcmp(parametersFormat, android::CameraParameters::PIXEL_FORMAT_YUV420SP)) || + (0 == strcmp(parametersFormat, android::CameraParameters::PIXEL_FORMAT_YUV420P)) ) { + bufferSize = width * height * 3 / 2; + } else if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_RGB565) ) { + bufferSize = width * height * 2; + } else if ( 0 == strcmp(parametersFormat, (const char *) android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ) { + bufferSize = width * height * 2; + } else { + CAMHAL_LOGEA("Invalid format"); + bufferSize = 0; + } + } else { + CAMHAL_LOGEA("Preview format is NULL"); + bufferSize = 0; + } + + return bufferSize; +} + + +bool CameraHal::parsePair(const char *str, int *first, int *second, char delim) +{ + // Find the first integer. + char *end; + int w = (int)strtol(str, &end, 10); + // If a delimeter does not immediately follow, give up. + if (*end != delim) { + CAMHAL_LOGE("Cannot find delimeter (%c) in str=%s", delim, str); + return false; + } + + // Find the second integer, immediately after the delimeter. + int h = (int)strtol(end+1, &end, 10); + + *first = w; + *second = h; + + return true; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/CameraHalUtilClasses.cpp b/camera/CameraHalUtilClasses.cpp new file mode 100644 index 0000000..53c9a55 --- /dev/null +++ b/camera/CameraHalUtilClasses.cpp @@ -0,0 +1,361 @@ +/* + * 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. + */ + +/** +* @file CameraHalUtilClasses.cpp +* +* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX). +* +*/ + +#include "CameraHal.h" + +namespace Ti { +namespace Camera { + +/*--------------------FrameProvider Class STARTS here-----------------------------*/ + +int FrameProvider::enableFrameNotification(int32_t frameTypes) +{ + LOG_FUNCTION_NAME; + status_t ret = NO_ERROR; + + ///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface) + mFrameNotifier->enableMsgType(frameTypes<disableMsgType(frameTypes<returnFrame(frameBuf, frameType); + + return ret; +} + +void FrameProvider::addFramePointers(CameraBuffer *frameBuf, void *buf) +{ + mFrameNotifier->addFramePointers(frameBuf, buf); + return; +} + +void FrameProvider::removeFramePointers() +{ + mFrameNotifier->removeFramePointers(); + return; +} + +/*--------------------FrameProvider Class ENDS here-----------------------------*/ + +/*--------------------EventProvider Class STARTS here-----------------------------*/ + +int EventProvider::enableEventNotification(int32_t frameTypes) +{ + LOG_FUNCTION_NAME; + status_t ret = NO_ERROR; + + ///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface) + mEventNotifier->enableMsgType(frameTypes<disableMsgType(frameTypes< weight ) || ( CameraArea::WEIGHT_MAX < weight ) ) { + CAMHAL_LOGEB("Camera area weight is invalid %d", weight); + return -EINVAL; + } + + if ( ( CameraArea::TOP > top ) || ( CameraArea::BOTTOM < top ) ) { + CAMHAL_LOGEB("Camera area top coordinate is invalid %d", top ); + return -EINVAL; + } + + if ( ( CameraArea::TOP > bottom ) || ( CameraArea::BOTTOM < bottom ) ) { + CAMHAL_LOGEB("Camera area bottom coordinate is invalid %d", bottom ); + return -EINVAL; + } + + if ( ( CameraArea::LEFT > left ) || ( CameraArea::RIGHT < left ) ) { + CAMHAL_LOGEB("Camera area left coordinate is invalid %d", left ); + return -EINVAL; + } + + if ( ( CameraArea::LEFT > right ) || ( CameraArea::RIGHT < right ) ) { + CAMHAL_LOGEB("Camera area right coordinate is invalid %d", right ); + return -EINVAL; + } + + if ( left >= right ) { + CAMHAL_LOGEA("Camera area left larger than right"); + return -EINVAL; + } + + if ( top >= bottom ) { + CAMHAL_LOGEA("Camera area top larger than bottom"); + return -EINVAL; + } + + return NO_ERROR; +} + +status_t CameraArea::parseAreas(const char *area, + size_t areaLength, + android::Vector > &areas) +{ + status_t ret = NO_ERROR; + char *ctx; + char *pArea = NULL; + char *pStart = NULL; + char *pEnd = NULL; + const char *startToken = "("; + const char endToken = ')'; + const char sep = ','; + ssize_t top, left, bottom, right, weight; + char *tmpBuffer = NULL; + android::sp currentArea; + + LOG_FUNCTION_NAME + + if ( ( NULL == area ) || + ( 0 >= areaLength ) ) + { + return -EINVAL; + } + + tmpBuffer = ( char * ) malloc(areaLength); + if ( NULL == tmpBuffer ) + { + return -ENOMEM; + } + + memcpy(tmpBuffer, area, areaLength); + + pArea = strtok_r(tmpBuffer, startToken, &ctx); + + do + { + + pStart = pArea; + if ( NULL == pStart ) + { + CAMHAL_LOGEA("Parsing of the left area coordinate failed!"); + ret = -EINVAL; + break; + } + else + { + left = static_cast(strtol(pStart, &pEnd, 10)); + } + + if ( sep != *pEnd ) + { + CAMHAL_LOGEA("Parsing of the top area coordinate failed!"); + ret = -EINVAL; + break; + } + else + { + top = static_cast(strtol(pEnd+1, &pEnd, 10)); + } + + if ( sep != *pEnd ) + { + CAMHAL_LOGEA("Parsing of the right area coordinate failed!"); + ret = -EINVAL; + break; + } + else + { + right = static_cast(strtol(pEnd+1, &pEnd, 10)); + } + + if ( sep != *pEnd ) + { + CAMHAL_LOGEA("Parsing of the bottom area coordinate failed!"); + ret = -EINVAL; + break; + } + else + { + bottom = static_cast(strtol(pEnd+1, &pEnd, 10)); + } + + if ( sep != *pEnd ) + { + CAMHAL_LOGEA("Parsing of the weight area coordinate failed!"); + ret = -EINVAL; + break; + } + else + { + weight = static_cast(strtol(pEnd+1, &pEnd, 10)); + } + + if ( endToken != *pEnd ) + { + CAMHAL_LOGEA("Malformed area!"); + ret = -EINVAL; + break; + } + + ret = checkArea(top, left, bottom, right, weight); + if ( NO_ERROR != ret ) { + break; + } + + currentArea = new CameraArea(top, left, bottom, right, weight); + CAMHAL_LOGDB("Area parsed [%dx%d, %dx%d] %d", + ( int ) top, + ( int ) left, + ( int ) bottom, + ( int ) right, + ( int ) weight); + if ( NULL != currentArea.get() ) + { + areas.add(currentArea); + } + else + { + ret = -ENOMEM; + break; + } + + pArea = strtok_r(NULL, startToken, &ctx); + + } + while ( NULL != pArea ); + + if ( NULL != tmpBuffer ) + { + free(tmpBuffer); + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +bool CameraArea::areAreasDifferent(android::Vector< android::sp > &area1, + android::Vector< android::sp > &area2) { + if (area1.size() != area2.size()) { + return true; + } + + // not going to care about sorting order for now + for (int i = 0; i < area1.size(); i++) { + if (!area1.itemAt(i)->compare(area2.itemAt(i))) { + return true; + } + } + + return false; +} + +bool CameraArea::compare(const android::sp &area) { + return ((mTop == area->mTop) && (mLeft == area->mLeft) && + (mBottom == area->mBottom) && (mRight == area->mRight) && + (mWeight == area->mWeight)); +} + + +/*--------------------CameraArea Class ENDS here-----------------------------*/ + +} // namespace Camera +} // namespace Ti diff --git a/camera/CameraHal_Module.cpp b/camera/CameraHal_Module.cpp new file mode 100644 index 0000000..ddddacd --- /dev/null +++ b/camera/CameraHal_Module.cpp @@ -0,0 +1,840 @@ +/* + * 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. + */ + +/** +* @file CameraHal.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + +#include + +#include "CameraHal.h" +#include "CameraProperties.h" +#include "TICameraParameters.h" + + +#ifdef CAMERAHAL_DEBUG_VERBOSE +# define CAMHAL_LOG_MODULE_FUNCTION_NAME LOG_FUNCTION_NAME +#else +# define CAMHAL_LOG_MODULE_FUNCTION_NAME +#endif + + +namespace Ti { +namespace Camera { + +static CameraProperties gCameraProperties; +static CameraHal* gCameraHals[MAX_CAMERAS_SUPPORTED]; +static unsigned int gCamerasOpen = 0; +static android::Mutex gCameraHalDeviceLock; + +static int camera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device); +static int camera_device_close(hw_device_t* device); +static int camera_get_number_of_cameras(void); +static int camera_get_camera_info(int camera_id, struct camera_info *info); + +static struct hw_module_methods_t camera_module_methods = { + open: camera_device_open +}; + +} // namespace Camera +} // namespace Ti + + +camera_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: CAMERA_HARDWARE_MODULE_ID, + name: "TI OMAP CameraHal Module", + author: "TI", + methods: &Ti::Camera::camera_module_methods, + dso: NULL, /* remove compilation warnings */ + reserved: {0}, /* remove compilation warnings */ + }, + get_number_of_cameras: Ti::Camera::camera_get_number_of_cameras, + get_camera_info: Ti::Camera::camera_get_camera_info, +}; + + +namespace Ti { +namespace Camera { + +typedef struct ti_camera_device { + camera_device_t base; + /* TI specific "private" data can go here (base.priv) */ + int cameraid; +} ti_camera_device_t; + + +/******************************************************************* + * implementation of camera_device_ops functions + *******************************************************************/ + +int camera_set_preview_window(struct camera_device * device, + struct preview_stream_ops *window) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->setPreviewWindow(window); + + return rv; +} + +#ifdef OMAP_ENHANCEMENT_CPCAM +int camera_set_extended_preview_ops(struct camera_device * device, + preview_stream_extended_ops_t * extendedOps) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + if (!device) { + return BAD_VALUE; + } + + ti_camera_device_t * const tiDevice = reinterpret_cast(device); + gCameraHals[tiDevice->cameraid]->setExtendedPreviewStreamOps(extendedOps); + + return OK; +} + +int camera_set_buffer_source(struct camera_device * device, + struct preview_stream_ops *tapin, + struct preview_stream_ops *tapout) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->setBufferSource(tapin, tapout); + + return rv; +} + +int camera_release_buffer_source(struct camera_device * device, + struct preview_stream_ops *tapin, + struct preview_stream_ops *tapout) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->releaseBufferSource(tapin, tapout); + + return rv; +} +#endif + +void camera_set_callbacks(struct camera_device * device, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user); +} + +void camera_enable_msg_type(struct camera_device * device, int32_t msg_type) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->enableMsgType(msg_type); +} + +void camera_disable_msg_type(struct camera_device * device, int32_t msg_type) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->disableMsgType(msg_type); +} + +int camera_msg_type_enabled(struct camera_device * device, int32_t msg_type) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return 0; + + ti_dev = (ti_camera_device_t*) device; + + return gCameraHals[ti_dev->cameraid]->msgTypeEnabled(msg_type); +} + +int camera_start_preview(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->startPreview(); + + return rv; +} + +void camera_stop_preview(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->stopPreview(); +} + +int camera_preview_enabled(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->previewEnabled(); + return rv; +} + +int camera_store_meta_data_in_buffers(struct camera_device * device, int enable) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + // TODO: meta data buffer not current supported + rv = gCameraHals[ti_dev->cameraid]->storeMetaDataInBuffers(enable); + return rv; + //return enable ? android::INVALID_OPERATION: android::OK; +} + +int camera_start_recording(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->startRecording(); + return rv; +} + +void camera_stop_recording(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->stopRecording(); +} + +int camera_recording_enabled(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->recordingEnabled(); + return rv; +} + +void camera_release_recording_frame(struct camera_device * device, + const void *opaque) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->releaseRecordingFrame(opaque); +} + +int camera_auto_focus(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->autoFocus(); + return rv; +} + +int camera_cancel_auto_focus(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->cancelAutoFocus(); + return rv; +} + +int camera_take_picture(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->takePicture(0); + return rv; +} + +#ifdef OMAP_ENHANCEMENT_CPCAM +int camera_take_picture_with_parameters(struct camera_device * device, const char *params) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->takePicture(params); + return rv; +} +#endif + +int camera_cancel_picture(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->cancelPicture(); + return rv; +} + +#ifdef OMAP_ENHANCEMENT_CPCAM +int camera_reprocess(struct camera_device * device, const char *params) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->reprocess(params); + return rv; +} + +int camera_cancel_reprocess(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->cancel_reprocess(); + return rv; +} +#endif + +int camera_set_parameters(struct camera_device * device, const char *params) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->setParameters(params); + return rv; +} + +char* camera_get_parameters(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + char* param = NULL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return NULL; + + ti_dev = (ti_camera_device_t*) device; + + param = gCameraHals[ti_dev->cameraid]->getParameters(); + + return param; +} + +static void camera_put_parameters(struct camera_device *device, char *parms) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->putParameters(parms); +} + +int camera_send_command(struct camera_device * device, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + +#ifdef OMAP_ENHANCEMENT_CPCAM + if ( cmd == CAMERA_CMD_SETUP_EXTENDED_OPERATIONS ) { + camera_device_extended_ops_t * const ops = static_cast( + camera_cmd_send_command_args_to_pointer(arg1, arg2)); + + ops->set_extended_preview_ops = camera_set_extended_preview_ops; + ops->set_buffer_source = camera_set_buffer_source; + ops->release_buffer_source = camera_release_buffer_source; + ops->take_picture_with_parameters = camera_take_picture_with_parameters; + ops->reprocess = camera_reprocess; + ops->cancel_reprocess = camera_cancel_reprocess; + return OK; + } +#endif + + rv = gCameraHals[ti_dev->cameraid]->sendCommand(cmd, arg1, arg2); + return rv; +} + +void camera_release(struct camera_device * device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->release(); +} + +int camera_dump(struct camera_device * device, int fd) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->dump(fd); + return rv; +} + +extern "C" void heaptracker_free_leaked_memory(void); + +int camera_device_close(hw_device_t* device) +{ + CAMHAL_LOG_MODULE_FUNCTION_NAME; + + int ret = 0; + ti_camera_device_t* ti_dev = NULL; + + android::AutoMutex lock(gCameraHalDeviceLock); + + if (!device) { + ret = -EINVAL; + goto done; + } + + ti_dev = (ti_camera_device_t*) device; + + if (ti_dev) { + if (gCameraHals[ti_dev->cameraid]) { + delete gCameraHals[ti_dev->cameraid]; + gCameraHals[ti_dev->cameraid] = NULL; + gCamerasOpen--; + } + + if (ti_dev->base.ops) { + free(ti_dev->base.ops); + } + free(ti_dev); + } +done: +#ifdef HEAPTRACKER + heaptracker_free_leaked_memory(); +#endif + return ret; +} + +/******************************************************************* + * implementation of camera_module functions + *******************************************************************/ + +/* open device handle to one of the cameras + * + * assume camera service will keep singleton of each camera + * so this function will always only be called once per camera instance + */ + +int camera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + int rv = 0; + int num_cameras = 0; + int cameraid; + ti_camera_device_t* camera_device = NULL; + camera_device_ops_t* camera_ops = NULL; + CameraHal* camera = NULL; + CameraProperties::Properties* properties = NULL; + + android::AutoMutex lock(gCameraHalDeviceLock); + + CAMHAL_LOGI("camera_device open"); + + if (name != NULL) { + cameraid = atoi(name); + num_cameras = gCameraProperties.camerasSupported(); + + if(cameraid > num_cameras) + { + CAMHAL_LOGE("camera service provided cameraid out of bounds, " + "cameraid = %d, num supported = %d", + cameraid, num_cameras); + rv = -EINVAL; + goto fail; + } + + if(gCamerasOpen >= MAX_SIMUL_CAMERAS_SUPPORTED) + { + CAMHAL_LOGE("maximum number of cameras already open"); + rv = -ENOMEM; + goto fail; + } + + camera_device = (ti_camera_device_t*)malloc(sizeof(*camera_device)); + if(!camera_device) + { + CAMHAL_LOGE("camera_device allocation fail"); + rv = -ENOMEM; + goto fail; + } + + camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops)); + if(!camera_ops) + { + CAMHAL_LOGE("camera_ops allocation fail"); + rv = -ENOMEM; + goto fail; + } + + memset(camera_device, 0, sizeof(*camera_device)); + memset(camera_ops, 0, sizeof(*camera_ops)); + + camera_device->base.common.tag = HARDWARE_DEVICE_TAG; + camera_device->base.common.version = 0; + camera_device->base.common.module = (hw_module_t *)(module); + camera_device->base.common.close = camera_device_close; + camera_device->base.ops = camera_ops; + + camera_ops->set_preview_window = camera_set_preview_window; + camera_ops->set_callbacks = camera_set_callbacks; + camera_ops->enable_msg_type = camera_enable_msg_type; + camera_ops->disable_msg_type = camera_disable_msg_type; + camera_ops->msg_type_enabled = camera_msg_type_enabled; + camera_ops->start_preview = camera_start_preview; + camera_ops->stop_preview = camera_stop_preview; + camera_ops->preview_enabled = camera_preview_enabled; + camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers; + camera_ops->start_recording = camera_start_recording; + camera_ops->stop_recording = camera_stop_recording; + camera_ops->recording_enabled = camera_recording_enabled; + camera_ops->release_recording_frame = camera_release_recording_frame; + camera_ops->auto_focus = camera_auto_focus; + camera_ops->cancel_auto_focus = camera_cancel_auto_focus; + camera_ops->take_picture = camera_take_picture; + camera_ops->cancel_picture = camera_cancel_picture; + camera_ops->set_parameters = camera_set_parameters; + camera_ops->get_parameters = camera_get_parameters; + camera_ops->put_parameters = camera_put_parameters; + camera_ops->send_command = camera_send_command; + camera_ops->release = camera_release; + camera_ops->dump = camera_dump; + + *device = &camera_device->base.common; + + // -------- TI specific stuff -------- + + camera_device->cameraid = cameraid; + + if(gCameraProperties.getProperties(cameraid, &properties) < 0) + { + CAMHAL_LOGE("Couldn't get camera properties"); + rv = -ENOMEM; + goto fail; + } + + camera = new CameraHal(cameraid); + + if(!camera) + { + CAMHAL_LOGE("Couldn't create instance of CameraHal class"); + rv = -ENOMEM; + goto fail; + } + + if(properties && (camera->initialize(properties) != NO_ERROR)) + { + CAMHAL_LOGE("Couldn't initialize camera instance"); + rv = -ENODEV; + goto fail; + } + + gCameraHals[cameraid] = camera; + gCamerasOpen++; + } + + return rv; + +fail: + if(camera_device) { + free(camera_device); + camera_device = NULL; + } + if(camera_ops) { + free(camera_ops); + camera_ops = NULL; + } + if(camera) { + delete camera; + camera = NULL; + } + *device = NULL; + return rv; +} + +int camera_get_number_of_cameras(void) +{ + int num_cameras = MAX_CAMERAS_SUPPORTED; + + // this going to be the first call from camera service + // initialize camera properties here... + if(gCameraProperties.initialize() != NO_ERROR) + { + CAMHAL_LOGEA("Unable to create or initialize CameraProperties"); + return NULL; + } + + num_cameras = gCameraProperties.camerasSupported(); + + return num_cameras; +} + +int camera_get_camera_info(int camera_id, struct camera_info *info) +{ + int rv = 0; + int face_value = CAMERA_FACING_BACK; + int orientation = 0; + const char *valstr = NULL; + CameraProperties::Properties* properties = NULL; + + // this going to be the first call from camera service + // initialize camera properties here... + if(gCameraProperties.initialize() != NO_ERROR) + { + CAMHAL_LOGEA("Unable to create or initialize CameraProperties"); + rv = -EINVAL; + goto end; + } + + //Get camera properties for camera index + if(gCameraProperties.getProperties(camera_id, &properties) < 0) + { + CAMHAL_LOGE("Couldn't get camera properties"); + rv = -EINVAL; + goto end; + } + + if(properties) + { + valstr = properties->get(CameraProperties::FACING_INDEX); + if(valstr != NULL) + { + if (strcmp(valstr, TICameraParameters::FACING_FRONT) == 0) + { +#ifndef TREAT_FRONT_AS_BACK + face_value = CAMERA_FACING_FRONT; +#else + face_value = CAMERA_FACING_BACK; +#endif + } + else if (strcmp(valstr, TICameraParameters::FACING_BACK) == 0) + { + face_value = CAMERA_FACING_BACK; + } + } + + valstr = properties->get(CameraProperties::ORIENTATION_INDEX); + if(valstr != NULL) + { + orientation = atoi(valstr); + } + } + else + { + CAMHAL_LOGEB("getProperties() returned a NULL property set for Camera id %d", camera_id); + } + + info->facing = face_value; + info->orientation = orientation; + +end: + return rv; +} + + +} // namespace Camera +} // namespace Ti diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp new file mode 100644 index 0000000..82b1da4 --- /dev/null +++ b/camera/CameraParameters.cpp @@ -0,0 +1,240 @@ +/* + * 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. + */ + +/** +* @file CameraProperties.cpp +* +* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX). +* +*/ + +#include "CameraProperties.h" + +namespace Ti { +namespace Camera { + +const char CameraProperties::INVALID[]="prop-invalid-key"; +const char CameraProperties::CAMERA_NAME[]="prop-camera-name"; +const char CameraProperties::CAMERA_SENSOR_INDEX[]="prop-sensor-index"; +const char CameraProperties::CAMERA_SENSOR_ID[] = "prop-sensor-id"; +const char CameraProperties::ORIENTATION_INDEX[]="prop-orientation"; +const char CameraProperties::FACING_INDEX[]="prop-facing"; +const char CameraProperties::SUPPORTED_PREVIEW_SIZES[] = "prop-preview-size-values"; +const char CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES[] = "prop-preview-subsampled-size-values"; +const char CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES[] = "prop-preview-topbottom-size-values"; +const char CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES[] = "prop-preview-sidebyside-size-values"; +const char CameraProperties::SUPPORTED_PREVIEW_FORMATS[] = "prop-preview-format-values"; +const char CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES[] = "prop-preview-frame-rate-values"; +const char CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES_EXT[] = "prop-preview-frame-rate-ext-values"; +const char CameraProperties::SUPPORTED_PICTURE_SIZES[] = "prop-picture-size-values"; +const char CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES[] = "prop-picture-subsampled-size-values"; +const char CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES[] = "prop-picture-topbottom-size-values"; +const char CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES[] = "prop-picture-sidebyside-size-values"; +const char CameraProperties::SUPPORTED_PICTURE_FORMATS[] = "prop-picture-format-values"; +const char CameraProperties::SUPPORTED_THUMBNAIL_SIZES[] = "prop-jpeg-thumbnail-size-values"; +const char CameraProperties::SUPPORTED_WHITE_BALANCE[] = "prop-whitebalance-values"; +const char CameraProperties::SUPPORTED_EFFECTS[] = "prop-effect-values"; +const char CameraProperties::SUPPORTED_ANTIBANDING[] = "prop-antibanding-values"; +const char CameraProperties::SUPPORTED_EXPOSURE_MODES[] = "prop-exposure-mode-values"; +const char CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN[] = "prop-manual-exposure-min"; +const char CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MAX[] = "prop-manual-exposure-max"; +const char CameraProperties::SUPPORTED_MANUAL_EXPOSURE_STEP[] = "prop-manual-exposure-step"; +const char CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN[] = "prop-manual-gain-iso-min"; +const char CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MAX[] = "prop-manual-gain-iso-max"; +const char CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_STEP[] = "prop-manual-gain-iso-step"; +const char CameraProperties::SUPPORTED_EV_MAX[] = "prop-ev-compensation-max"; +const char CameraProperties::SUPPORTED_EV_MIN[] = "prop-ev-compensation-min"; +const char CameraProperties::SUPPORTED_EV_STEP[] = "prop-ev-compensation-step"; +const char CameraProperties::SUPPORTED_ISO_VALUES[] = "prop-iso-mode-values"; +const char CameraProperties::SUPPORTED_SCENE_MODES[] = "prop-scene-mode-values"; +const char CameraProperties::SUPPORTED_FLASH_MODES[] = "prop-flash-mode-values"; +const char CameraProperties::SUPPORTED_FOCUS_MODES[] = "prop-focus-mode-values"; +const char CameraProperties::REQUIRED_PREVIEW_BUFS[] = "prop-required-preview-bufs"; +const char CameraProperties::REQUIRED_IMAGE_BUFS[] = "prop-required-image-bufs"; +const char CameraProperties::SUPPORTED_ZOOM_RATIOS[] = "prop-zoom-ratios"; +const char CameraProperties::SUPPORTED_ZOOM_STAGES[] = "prop-zoom-stages"; +const char CameraProperties::SUPPORTED_IPP_MODES[] = "prop-ipp-values"; +const char CameraProperties::SMOOTH_ZOOM_SUPPORTED[] = "prop-smooth-zoom-supported"; +const char CameraProperties::ZOOM_SUPPORTED[] = "prop-zoom-supported"; +const char CameraProperties::PREVIEW_SIZE[] = "prop-preview-size-default"; +const char CameraProperties::PREVIEW_FORMAT[] = "prop-preview-format-default"; +const char CameraProperties::PREVIEW_FRAME_RATE[] = "prop-preview-frame-rate-default"; +const char CameraProperties::ZOOM[] = "prop-zoom-default"; +const char CameraProperties::PICTURE_SIZE[] = "prop-picture-size-default"; +const char CameraProperties::PICTURE_FORMAT[] = "prop-picture-format-default"; +const char CameraProperties::JPEG_THUMBNAIL_SIZE[] = "prop-jpeg-thumbnail-size-default"; +const char CameraProperties::WHITEBALANCE[] = "prop-whitebalance-default"; +const char CameraProperties::EFFECT[] = "prop-effect-default"; +const char CameraProperties::ANTIBANDING[] = "prop-antibanding-default"; +const char CameraProperties::EXPOSURE_MODE[] = "prop-exposure-mode-default"; +const char CameraProperties::EV_COMPENSATION[] = "prop-ev-compensation-default"; +const char CameraProperties::ISO_MODE[] = "prop-iso-mode-default"; +const char CameraProperties::FOCUS_MODE[] = "prop-focus-mode-default"; +const char CameraProperties::SCENE_MODE[] = "prop-scene-mode-default"; +const char CameraProperties::FLASH_MODE[] = "prop-flash-mode-default"; +const char CameraProperties::JPEG_QUALITY[] = "prop-jpeg-quality-default"; +const char CameraProperties::CONTRAST[] = "prop-contrast-default"; +const char CameraProperties::BRIGHTNESS[] = "prop-brightness-default"; +const char CameraProperties::SATURATION[] = "prop-saturation-default"; +const char CameraProperties::SHARPNESS[] = "prop-sharpness-default"; +const char CameraProperties::IPP[] = "prop-ipp-default"; +const char CameraProperties::GBCE[] = "prop-gbce-default"; +const char CameraProperties::SUPPORTED_GBCE[] = "prop-gbce-supported"; +const char CameraProperties::GLBCE[] = "prop-glbce-default"; +const char CameraProperties::SUPPORTED_GLBCE[] = "prop-glbce-supported"; +const char CameraProperties::S3D_PRV_FRAME_LAYOUT[] = "prop-s3d-prv-frame-layout"; +const char CameraProperties::S3D_PRV_FRAME_LAYOUT_VALUES[] = "prop-s3d-prv-frame-layout-values"; +const char CameraProperties::S3D_CAP_FRAME_LAYOUT[] = "prop-s3d-cap-frame-layout"; +const char CameraProperties::S3D_CAP_FRAME_LAYOUT_VALUES[] = "prop-s3d-cap-frame-layout-values"; +const char CameraProperties::AUTOCONVERGENCE_MODE[] = "prop-auto-convergence-mode"; +const char CameraProperties::AUTOCONVERGENCE_MODE_VALUES[] = "prop-auto-convergence-mode-values"; +const char CameraProperties::MANUAL_CONVERGENCE[] = "prop-manual-convergence"; +const char CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MIN[] = "prop-supported-manual-convergence-min"; +const char CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MAX[] = "prop-supported-manual-convergence-max"; +const char CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_STEP[] = "prop-supported-manual-convergence-step"; +const char CameraProperties::VSTAB[] = "prop-vstab-default"; +const char CameraProperties::VSTAB_SUPPORTED[] = "prop-vstab-supported"; +const char CameraProperties::VNF[] = "prop-vnf-default"; +const char CameraProperties::VNF_SUPPORTED[] = "prop-vnf-supported"; +const char CameraProperties::REVISION[] = "prop-revision"; +const char CameraProperties::FOCAL_LENGTH[] = "prop-focal-length"; +const char CameraProperties::HOR_ANGLE[] = "prop-horizontal-angle"; +const char CameraProperties::VER_ANGLE[] = "prop-vertical-angle"; +const char CameraProperties::FRAMERATE_RANGE[] = "prop-framerate-range-default"; +const char CameraProperties::FRAMERATE_RANGE_SUPPORTED[]="prop-framerate-range-values"; +const char CameraProperties::FRAMERATE_RANGE_EXT_SUPPORTED[]="prop-framerate-range-ext-values"; +const char CameraProperties::SENSOR_ORIENTATION[]= "sensor-orientation"; +const char CameraProperties::SENSOR_ORIENTATION_VALUES[]= "sensor-orientation-values"; +const char CameraProperties::EXIF_MAKE[] = "prop-exif-make"; +const char CameraProperties::EXIF_MODEL[] = "prop-exif-model"; +const char CameraProperties::JPEG_THUMBNAIL_QUALITY[] = "prop-jpeg-thumbnail-quality-default"; +const char CameraProperties::MAX_FOCUS_AREAS[] = "prop-max-focus-areas"; +const char CameraProperties::MAX_FD_HW_FACES[] = "prop-max-fd-hw-faces"; +const char CameraProperties::MAX_FD_SW_FACES[] = "prop-max-fd-sw-faces"; +const char CameraProperties::AUTO_EXPOSURE_LOCK[] = "prop-auto-exposure-lock"; +const char CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED[] = "prop-auto-exposure-lock-supported"; +const char CameraProperties::AUTO_WHITEBALANCE_LOCK[] = "prop-auto-whitebalance-lock"; +const char CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "prop-auto-whitebalance-lock-supported"; +const char CameraProperties::MAX_NUM_METERING_AREAS[] = "prop-max-num-metering-areas"; +const char CameraProperties::METERING_AREAS[] = "prop-metering-areas"; +const char CameraProperties::VIDEO_SNAPSHOT_SUPPORTED[] = "prop-video-snapshot-supported"; +const char CameraProperties::VIDEO_SIZE[] = "video-size"; +const char CameraProperties::SUPPORTED_VIDEO_SIZES[] = "video-size-values"; +const char CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED[] = "prop-mechanical-misalignment-correction-supported"; +const char CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION[] = "prop-mechanical-misalignment-correction"; +const char CameraProperties::CAP_MODE_VALUES[] = "prop-mode-values"; +const char CameraProperties::RAW_WIDTH[] = "prop-raw-width-values"; +const char CameraProperties::RAW_HEIGHT[] = "prop-raw-height-values"; +const char CameraProperties::MAX_PICTURE_WIDTH[] = "prop-max-picture-width"; +const char CameraProperties::MAX_PICTURE_HEIGHT[] = "prop-max-picture-height"; + +const char CameraProperties::DEFAULT_VALUE[] = ""; + +const char CameraProperties::PARAMS_DELIMITER []= ","; + +// Returns the properties class for a specific Camera +// Each value is indexed by the CameraProperties::CameraPropertyIndex enum +int CameraProperties::getProperties(int cameraIndex, CameraProperties::Properties** properties) +{ + LOG_FUNCTION_NAME; + + if(cameraIndex >= mCamerasSupported) + { + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + *properties = mCameraProps+cameraIndex; + + LOG_FUNCTION_NAME_EXIT; + return 0; +} + +void CameraProperties::Properties::set(const char * const prop, const char * const value) { + CAMHAL_ASSERT(prop); + + if ( !value ) { + mProperties[mCurrentMode].removeItem(android::String8(prop)); + } else { + mProperties[mCurrentMode].replaceValueFor(android::String8(prop), android::String8(value)); + } +} + +void CameraProperties::Properties::set(const char * const prop, const int value) { + char s_val[30]; + sprintf(s_val, "%d", value); + set(prop, s_val); +} + +const char* CameraProperties::Properties::get(const char * prop) const { + return mProperties[mCurrentMode].valueFor(android::String8(prop)).string(); +} + +int CameraProperties::Properties::getInt(const char * prop) const { + android::String8 value = mProperties[mCurrentMode].valueFor(android::String8(prop)); + if (value.isEmpty()) { + return -1; + } + return strtol(value, 0, 0); +} + +void CameraProperties::Properties::setSensorIndex(int idx) { + OperatingMode originalMode = getMode(); + for ( int i = 0 ; i < MODE_MAX ; i++ ) { + setMode(static_cast(i)); + set(CAMERA_SENSOR_INDEX, idx); + } + setMode(originalMode); +} + +void CameraProperties::Properties::setMode(OperatingMode mode) { + CAMHAL_ASSERT(mode >= 0 && mode < MODE_MAX); + mCurrentMode = mode; +} + +OperatingMode CameraProperties::Properties::getMode() const { + return mCurrentMode; +} + +void CameraProperties::Properties::dump() { + CAMHAL_LOGD("================================"); + CAMHAL_LOGD("Dumping properties for camera: %d", getInt("prop-sensor-index")); + + for (size_t i = 0; i < mProperties[mCurrentMode].size(); i++) { + CAMHAL_LOGD("%s = %s", + mProperties[mCurrentMode].keyAt(i).string(), + mProperties[mCurrentMode].valueAt(i).string()); + } + + CAMHAL_LOGD("--------------------------------"); +} + +const char* CameraProperties::Properties::keyAt(const unsigned int index) const { + if (index < mProperties[mCurrentMode].size()) { + return mProperties[mCurrentMode].keyAt(index).string(); + } + return NULL; +} + +const char* CameraProperties::Properties::valueAt(const unsigned int index) const { + if (index < mProperties[mCurrentMode].size()) { + return mProperties[mCurrentMode].valueAt(index).string(); + } + return NULL; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/CameraProperties.cpp b/camera/CameraProperties.cpp new file mode 100644 index 0000000..93bc953 --- /dev/null +++ b/camera/CameraProperties.cpp @@ -0,0 +1,135 @@ +/* + * 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. + */ + +/** +* @file CameraProperties.cpp +* +* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX). +* +*/ + +#include "CameraProperties.h" + +#define CAMERA_ROOT "CameraRoot" +#define CAMERA_INSTANCE "CameraInstance" + +namespace Ti { +namespace Camera { + +// lower entries have higher priority +static const char* g_camera_adapters[] = { +#ifdef OMAP4_SUPPORT_OMX_CAMERA_ADAPTER + "libomxcameraadapter.so", +#endif +#ifdef OMAP4_SUPPORT_USB_CAMERA_ADAPTER + "libusbcameraadapter.so" +#endif +}; + +/********************************************************* + CameraProperties - public function implemetation +**********************************************************/ + +CameraProperties::CameraProperties() : mCamerasSupported(0) +{ + LOG_FUNCTION_NAME; + + mCamerasSupported = 0; + mInitialized = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +CameraProperties::~CameraProperties() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + + +// Initializes the CameraProperties class +status_t CameraProperties::initialize() +{ + LOG_FUNCTION_NAME; + + status_t ret; + + android::AutoMutex lock(mLock); + + if(mInitialized) + return NO_ERROR; + + ret = loadProperties(); + + if (ret == NO_ERROR) { + mInitialized = 1; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +extern "C" status_t CameraAdapter_Capabilities(CameraProperties::Properties* properties_array, + int starting_camera, int max_camera, int & supported_cameras); + +///Loads all the Camera related properties +status_t CameraProperties::loadProperties() +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + + //Must be re-initialized here, since loadProperties() could potentially be called more than once. + mCamerasSupported = 0; + + // adapter updates capabilities and we update camera count + const status_t err = CameraAdapter_Capabilities(mCameraProps, mCamerasSupported, + MAX_CAMERAS_SUPPORTED, mCamerasSupported); + + if(err != NO_ERROR) { + CAMHAL_LOGE("error while getting capabilities"); + ret = UNKNOWN_ERROR; + } else if (mCamerasSupported == 0) { + CAMHAL_LOGE("camera busy. properties not loaded. num_cameras = %d", mCamerasSupported); + ret = UNKNOWN_ERROR; + } else if (mCamerasSupported > MAX_CAMERAS_SUPPORTED) { + CAMHAL_LOGE("returned too many adapaters"); + ret = UNKNOWN_ERROR; + } else { + CAMHAL_LOGI("num_cameras = %d", mCamerasSupported); + + for (int i = 0; i < mCamerasSupported; i++) { + mCameraProps[i].setSensorIndex(i); + mCameraProps[i].dump(); + } + } + + CAMHAL_LOGV("mCamerasSupported = %d", mCamerasSupported); + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +// Returns the number of Cameras found +int CameraProperties::camerasSupported() +{ + LOG_FUNCTION_NAME; + return mCamerasSupported; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/DecoderFactory.cpp b/camera/DecoderFactory.cpp new file mode 100644 index 0000000..846fda4 --- /dev/null +++ b/camera/DecoderFactory.cpp @@ -0,0 +1,59 @@ +/* + * 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 "FrameDecoder.h" +#include "SwFrameDecoder.h" +#include "OmxFrameDecoder.h" +#include "CameraHal.h" +#include "DecoderFactory.h" + +namespace Ti { +namespace Camera { + + +FrameDecoder* DecoderFactory::createDecoderByType(DecoderType type, bool forceSwDecoder) { + FrameDecoder* decoder = NULL; + switch (type) { + case DecoderType_MJPEG: { + + if (!forceSwDecoder) { + decoder = new OmxFrameDecoder(DecoderType_MJPEG); + CAMHAL_LOGD("Using HW Decoder for MJPEG"); + } else { + decoder = new SwFrameDecoder(); + CAMHAL_LOGD("Using SW Decoder for MJPEG"); + } + + //TODO add logic that handle verification is HW Decoder is available ? + // And if no - create SW decoder. + break; + } + case DecoderType_H264: { + decoder = new OmxFrameDecoder(DecoderType_H264); + CAMHAL_LOGD("Using HW Decoder for H264"); + break; + } + default: { + CAMHAL_LOGE("Unrecognized decoder type %d", type); + } + } + + return decoder; +} + +} // namespace Camera +} // namespace Ti + diff --git a/camera/Decoder_libjpeg.cpp b/camera/Decoder_libjpeg.cpp new file mode 100644 index 0000000..35c343f --- /dev/null +++ b/camera/Decoder_libjpeg.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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 "Decoder_libjpeg.h" + +extern "C" { + #include "jpeglib.h" + #include "jerror.h" +} + +#define NUM_COMPONENTS_IN_YUV 3 + +namespace Ti { +namespace Camera { + +/* JPEG DHT Segment omitted from MJPEG data */ +static unsigned char jpeg_odml_dht[0x1a6] = { + 0xff, 0xd8, /* Start of Image */ + 0xff, 0xc4, 0x01, 0xa2, /* Define Huffman Table */ + + 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + + 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + + 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, + + 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +struct libjpeg_source_mgr : jpeg_source_mgr { + libjpeg_source_mgr(unsigned char *buffer_ptr, int len); + ~libjpeg_source_mgr(); + + unsigned char *mBufferPtr; + int mFilledLen; +}; + +static void libjpeg_init_source(j_decompress_ptr cinfo) { + libjpeg_source_mgr* src = (libjpeg_source_mgr*)cinfo->src; + src->next_input_byte = (const JOCTET*)src->mBufferPtr; + src->bytes_in_buffer = 0; + src->current_offset = 0; +} + +static boolean libjpeg_seek_input_data(j_decompress_ptr cinfo, long byte_offset) { + libjpeg_source_mgr* src = (libjpeg_source_mgr*)cinfo->src; + src->current_offset = byte_offset; + src->next_input_byte = (const JOCTET*)src->mBufferPtr + byte_offset; + src->bytes_in_buffer = 0; + return TRUE; +} + +static boolean libjpeg_fill_input_buffer(j_decompress_ptr cinfo) { + libjpeg_source_mgr* src = (libjpeg_source_mgr*)cinfo->src; + src->current_offset += src->mFilledLen; + src->next_input_byte = src->mBufferPtr; + src->bytes_in_buffer = src->mFilledLen; + return TRUE; +} + +static void libjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + libjpeg_source_mgr* src = (libjpeg_source_mgr*)cinfo->src; + + if (num_bytes > (long)src->bytes_in_buffer) { + CAMHAL_LOGEA("\n\n\n libjpeg_skip_input_data - num_bytes > (long)src->bytes_in_buffer \n\n\n"); + } else { + src->next_input_byte += num_bytes; + src->bytes_in_buffer -= num_bytes; + } +} + +static boolean libjpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) { + libjpeg_source_mgr* src = (libjpeg_source_mgr*)cinfo->src; + src->next_input_byte = (const JOCTET*)src->mBufferPtr; + src->bytes_in_buffer = 0; + return TRUE; +} + +static void libjpeg_term_source(j_decompress_ptr /*cinfo*/) {} + +libjpeg_source_mgr::libjpeg_source_mgr(unsigned char *buffer_ptr, int len) : mBufferPtr(buffer_ptr), mFilledLen(len) { + init_source = libjpeg_init_source; + fill_input_buffer = libjpeg_fill_input_buffer; + skip_input_data = libjpeg_skip_input_data; + resync_to_restart = libjpeg_resync_to_restart; + term_source = libjpeg_term_source; + seek_input_data = libjpeg_seek_input_data; +} + +libjpeg_source_mgr::~libjpeg_source_mgr() {} + +Decoder_libjpeg::Decoder_libjpeg() +{ + mWidth = 0; + mHeight = 0; + Y_Plane = NULL; + U_Plane = NULL; + V_Plane = NULL; + UV_Plane = NULL; +} + +Decoder_libjpeg::~Decoder_libjpeg() +{ + release(); +} + +void Decoder_libjpeg::release() +{ + if (Y_Plane) { + free(Y_Plane); + Y_Plane = NULL; + } + if (U_Plane) { + free(U_Plane); + U_Plane = NULL; + } + if (V_Plane) { + free(V_Plane); + V_Plane = NULL; + } + if (UV_Plane) { + free(UV_Plane); + UV_Plane = NULL; + } +} + +int Decoder_libjpeg::readDHTSize() +{ + return sizeof(jpeg_odml_dht); +} + +// 0xFF 0xC4 - DHT (Define Huffman Table) marker +// 0xFF 0xD9 - SOI (Start Of Image) marker +// 0xFF 0xD9 - EOI (End Of Image) marker +// This function return true if if found DHT +bool Decoder_libjpeg::isDhtExist(unsigned char *jpeg_src, int filled_len) { + if (filled_len <= 0) { + return false; + } + + for (int i = 1; i < filled_len; i++) { + if((jpeg_src[i - 1] == 0xFF) && (jpeg_src[i] == 0xC4)) { + CAMHAL_LOGD("Found DHT (Define Huffman Table) marker"); + return true; + } + } + return false; +} + +int Decoder_libjpeg::appendDHT(unsigned char *jpeg_src, int filled_len, unsigned char *jpeg_with_dht_buffer, int buff_size) +{ + /* Appending DHT to JPEG */ + + int len = filled_len + sizeof(jpeg_odml_dht) - 2; // final length of jpeg data + if (len > buff_size) { + CAMHAL_LOGEA("\n\n\n Buffer size too small. filled_len=%d, buff_size=%d, sizeof(jpeg_odml_dht)=%d\n\n\n", filled_len, buff_size, sizeof(jpeg_odml_dht)); + return 0; + } + + memcpy(jpeg_with_dht_buffer, jpeg_odml_dht, sizeof(jpeg_odml_dht)); + memcpy((jpeg_with_dht_buffer + sizeof(jpeg_odml_dht)), jpeg_src + 2, (filled_len - 2)); + return len; +} + + +bool Decoder_libjpeg::decode(unsigned char *jpeg_src, int filled_len, unsigned char *nv12_buffer, int stride) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + struct libjpeg_source_mgr s_mgr(jpeg_src, filled_len); + + if (filled_len == 0) + return false; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + cinfo.src = &s_mgr; + int status = jpeg_read_header(&cinfo, true); + if (status != JPEG_HEADER_OK) { + CAMHAL_LOGEA("jpeg header corrupted"); + return false; + } + + cinfo.out_color_space = JCS_YCbCr; + cinfo.raw_data_out = true; + status = jpeg_start_decompress(&cinfo); + if (!status){ + CAMHAL_LOGEA("jpeg_start_decompress failed"); + return false; + } + + if (mWidth == 0){ + mWidth = cinfo.output_width; + mHeight = cinfo.output_height; + CAMHAL_LOGEA("w x h = %d x %d. stride=%d", cinfo.output_width, cinfo.output_height, stride); + } + else if ((cinfo.output_width > mWidth) || (cinfo.output_height > mHeight)) { + CAMHAL_LOGEA(" Free the existing buffers so that they are reallocated for new w x h. Old WxH = %dx%d. New WxH = %dx%d", + mWidth, mHeight, cinfo.output_width, cinfo.output_height); + release(); + mWidth = cinfo.output_width; + mHeight = cinfo.output_height; + } + + unsigned int decoded_uv_buffer_size = cinfo.output_width * cinfo.output_height / 2; + if (Y_Plane == NULL)Y_Plane = (unsigned char **)malloc(cinfo.output_height * sizeof(unsigned char *)); + if (U_Plane == NULL)U_Plane = (unsigned char **)malloc(cinfo.output_height * sizeof(unsigned char *)); + if (V_Plane == NULL)V_Plane = (unsigned char **)malloc(cinfo.output_height * sizeof(unsigned char *)); + if (UV_Plane == NULL) UV_Plane = (unsigned char *)malloc(decoded_uv_buffer_size); + + unsigned char **YUV_Planes[NUM_COMPONENTS_IN_YUV]; + YUV_Planes[0] = Y_Plane; + YUV_Planes[1] = U_Plane; + YUV_Planes[2] = V_Plane; + + unsigned char *row = &nv12_buffer[0]; + + // Y Component + for (unsigned int j = 0; j < cinfo.output_height; j++, row += stride) + YUV_Planes[0][j] = row; + + row = &UV_Plane[0]; + + // U Component + for (unsigned int j = 0; j < cinfo.output_height; j+=2, row += cinfo.output_width / 2){ + YUV_Planes[1][j+0] = row; + YUV_Planes[1][j+1] = row; + } + + // V Component + for (unsigned int j = 0; j < cinfo.output_height; j+=2, row += cinfo.output_width / 2){ + YUV_Planes[2][j+0] = row; + YUV_Planes[2][j+1] = row; + } + + // Interleaving U and V + for (unsigned int i = 0; i < cinfo.output_height; i += 8) { + jpeg_read_raw_data(&cinfo, YUV_Planes, 8); + YUV_Planes[0] += 8; + YUV_Planes[1] += 8; + YUV_Planes[2] += 8; + } + + unsigned char *uv_ptr = nv12_buffer + (stride * cinfo.output_height); + unsigned char *u_ptr = UV_Plane; + unsigned char *v_ptr = UV_Plane + (decoded_uv_buffer_size / 2); + for(unsigned int i = 0; i < cinfo.output_height / 2; i++){ + for(unsigned int j = 0; j < cinfo.output_width; j+=2){ + *(uv_ptr + j) = *u_ptr; u_ptr++; + *(uv_ptr + j + 1) = *v_ptr; v_ptr++; + } + uv_ptr = uv_ptr + stride; + } + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + return true; +} + +} // namespace Camera +} // namespace Ti + diff --git a/camera/Encoder_libjpeg.cpp b/camera/Encoder_libjpeg.cpp new file mode 100644 index 0000000..1cd09d3 --- /dev/null +++ b/camera/Encoder_libjpeg.cpp @@ -0,0 +1,549 @@ +/* + * 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. + */ + +/** +* @file Encoder_libjpeg.cpp +* +* This file encodes a YUV422I buffer to a jpeg +* TODO(XXX): Need to support formats other than yuv422i +* Change interface to pre/post-proc algo framework +* +*/ + +#include "Encoder_libjpeg.h" +#include "NV12_resize.h" +#include "TICameraParameters.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + #include "jpeglib.h" + #include "jerror.h" +} + +#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) +#define MIN(x,y) ((x < y) ? x : y) + +namespace Ti { +namespace Camera { + +struct integer_string_pair { + unsigned int integer; + const char* string; +}; + +static integer_string_pair degress_to_exif_lut [] = { + // degrees, exif_orientation + {0, "1"}, + {90, "6"}, + {180, "3"}, + {270, "8"}, +}; +struct libjpeg_destination_mgr : jpeg_destination_mgr { + libjpeg_destination_mgr(uint8_t* input, int size); + + uint8_t* buf; + int bufsize; + size_t jpegsize; +}; + +static void libjpeg_init_destination (j_compress_ptr cinfo) { + libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; + + dest->next_output_byte = dest->buf; + dest->free_in_buffer = dest->bufsize; + dest->jpegsize = 0; +} + +static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) { + libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; + + dest->next_output_byte = dest->buf; + dest->free_in_buffer = dest->bufsize; + return TRUE; // ? +} + +static void libjpeg_term_destination (j_compress_ptr cinfo) { + libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; + dest->jpegsize = dest->bufsize - dest->free_in_buffer; +} + +libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) { + this->init_destination = libjpeg_init_destination; + this->empty_output_buffer = libjpeg_empty_output_buffer; + this->term_destination = libjpeg_term_destination; + + this->buf = input; + this->bufsize = size; + + jpegsize = 0; +} + +/* private static functions */ +static void nv21_to_yuv(uint8_t* dst, uint8_t* y, uint8_t* uv, int width) { + if (!dst || !y || !uv) { + return; + } + + while ((width--) > 0) { + uint8_t y0 = y[0]; + uint8_t v0 = uv[0]; + uint8_t u0 = *(uv+1); + dst[0] = y0; + dst[1] = u0; + dst[2] = v0; + dst += 3; + y++; + if(!(width % 2)) uv+=2; + } +} + +static void uyvy_to_yuv(uint8_t* dst, uint32_t* src, int width) { + if (!dst || !src) { + return; + } + + if (width % 2) { + return; // not supporting odd widths + } + +#ifdef ARCH_ARM_HAVE_NEON + // currently, neon routine only supports multiple of 16 width + if ((width % 16) == 0) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #16 \n\t" + " blt 5f \n\t" + "0: @ 16 pixel swap \n\t" + " vld2.8 {q0, q1} , [%[src]]! @ q0 = uv q1 = y \n\t" + " vuzp.8 q0, q2 @ d0 = u d4 = v \n\t" + " vmov d1, d0 @ q0 = u0u1u2..u0u1u2... \n\t" + " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t" + " vzip.8 d0, d1 @ q0 = u0u0u1u1u2u2... \n\t" + " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t" + " vswp q0, q1 @ now q0 = y q1 = u q2 = v \n\t" + " vst3.8 {d0,d2,d4},[%[dst]]! \n\t" + " vst3.8 {d1,d3,d5},[%[dst]]! \n\t" + " sub %[n], %[n], #16 \n\t" + " cmp %[n], #16 \n\t" + " bge 0b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n) + : [src_stride] "r" (width) + : "cc", "memory", "q0", "q1", "q2" + ); + } else +#endif + { + while ((width-=2) >= 0) { + uint8_t u0 = (src[0] >> 0) & 0xFF; + uint8_t y0 = (src[0] >> 8) & 0xFF; + uint8_t v0 = (src[0] >> 16) & 0xFF; + uint8_t y1 = (src[0] >> 24) & 0xFF; + dst[0] = y0; + dst[1] = u0; + dst[2] = v0; + dst[3] = y1; + dst[4] = u0; + dst[5] = v0; + dst += 6; + src++; + } + } +} + +static void yuyv_to_yuv(uint8_t* dst, uint32_t* src, int width) { + if (!dst || !src) { + return; + } + + if (width % 2) { + return; // not supporting odd widths + } + +#ifdef ARCH_ARM_HAVE_NEON + // currently, neon routine only supports multiple of 16 width + if ((width % 16) == 0) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #16 \n\t" + " blt 5f \n\t" + "0: @ 16 pixel swap \n\t" + " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t" + " vuzp.8 q1, q2 @ d2 = u d4 = v \n\t" + " vmov d3, d2 @ q1 = u0u1u2..u0u1u2... \n\t" + " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t" + " vzip.8 d2, d3 @ q1 = u0u0u1u1u2u2... \n\t" + " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t" + " @ now q0 = y q1 = u q2 = v \n\t" + " vst3.8 {d0,d2,d4},[%[dst]]! \n\t" + " vst3.8 {d1,d3,d5},[%[dst]]! \n\t" + " sub %[n], %[n], #16 \n\t" + " cmp %[n], #16 \n\t" + " bge 0b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n) + : [src_stride] "r" (width) + : "cc", "memory", "q0", "q1", "q2" + ); + } else +#endif + { + while ((width-=2) >= 0) { + uint8_t y0 = (src[0] >> 0) & 0xFF; + uint8_t u0 = (src[0] >> 8) & 0xFF; + uint8_t y1 = (src[0] >> 16) & 0xFF; + uint8_t v0 = (src[0] >> 24) & 0xFF; + dst[0] = y0; + dst[1] = u0; + dst[2] = v0; + dst[3] = y1; + dst[4] = u0; + dst[5] = v0; + dst += 6; + src++; + } + } +} + +static void resize_nv12(Encoder_libjpeg::params* params, uint8_t* dst_buffer) { + structConvImage o_img_ptr, i_img_ptr; + + if (!params || !dst_buffer) { + return; + } + + //input + i_img_ptr.uWidth = params->in_width; + i_img_ptr.uStride = i_img_ptr.uWidth; + i_img_ptr.uHeight = params->in_height; + i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; + i_img_ptr.imgPtr = (uint8_t*) params->src; + i_img_ptr.clrPtr = i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight); + i_img_ptr.uOffset = 0; + + //ouput + o_img_ptr.uWidth = params->out_width; + o_img_ptr.uStride = o_img_ptr.uWidth; + o_img_ptr.uHeight = params->out_height; + o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; + o_img_ptr.imgPtr = dst_buffer; + o_img_ptr.clrPtr = o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight); + o_img_ptr.uOffset = 0; + + VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0); +} + +/* public static functions */ +const char* ExifElementsTable::degreesToExifOrientation(unsigned int degrees) { + for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) { + if (degrees == degress_to_exif_lut[i].integer) { + return degress_to_exif_lut[i].string; + } + } + return NULL; +} + +void ExifElementsTable::stringToRational(const char* str, unsigned int* num, unsigned int* den) { + int len; + char * tempVal = NULL; + + if (str != NULL) { + len = strlen(str); + tempVal = (char*) malloc( sizeof(char) * (len + 1)); + } + + if (tempVal != NULL) { + // convert the decimal string into a rational + size_t den_len; + char *ctx; + unsigned int numerator = 0; + unsigned int denominator = 0; + char* temp = NULL; + + memset(tempVal, '\0', len + 1); + strncpy(tempVal, str, len); + temp = strtok_r(tempVal, ".", &ctx); + + if (temp != NULL) + numerator = atoi(temp); + + if (!numerator) + numerator = 1; + + temp = strtok_r(NULL, ".", &ctx); + if (temp != NULL) { + den_len = strlen(temp); + if(HUGE_VAL == den_len ) { + den_len = 0; + } + + denominator = static_cast(pow(10, den_len)); + numerator = numerator * denominator + atoi(temp); + } else { + denominator = 1; + } + + free(tempVal); + + *num = numerator; + *den = denominator; + } +} + +bool ExifElementsTable::isAsciiTag(const char* tag) { + // TODO(XXX): Add tags as necessary + return (strcmp(tag, TAG_GPS_PROCESSING_METHOD) == 0); +} + +void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) { + ReadMode_t read_mode = (ReadMode_t)(READ_METADATA | READ_IMAGE); + + ResetJpgfile(); + if (ReadJpegSectionsFromBuffer(jpeg, jpeg_size, read_mode)) { + jpeg_opened = true; +#ifdef ANDROID_API_JB_OR_LATER + create_EXIF(table, exif_tag_count, gps_tag_count, has_datetime_tag); +#else + create_EXIF(table, exif_tag_count, gps_tag_count); +#endif + } +} + +status_t ExifElementsTable::insertExifThumbnailImage(const char* thumb, int len) { + status_t ret = NO_ERROR; + + if ((len > 0) && jpeg_opened) { + ret = ReplaceThumbnailFromBuffer(thumb, len) ? NO_ERROR : UNKNOWN_ERROR; + CAMHAL_LOGDB("insertExifThumbnailImage. ReplaceThumbnail(). ret=%d", ret); + } + + return ret; +} + +void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) { + if (jpeg_opened) { + WriteJpegToBuffer(jpeg, jpeg_size); + DiscardData(); + jpeg_opened = false; + } +} + +/* public functions */ +ExifElementsTable::~ExifElementsTable() { + int num_elements = gps_tag_count + exif_tag_count; + + for (int i = 0; i < num_elements; i++) { + if (table[i].Value) { + free(table[i].Value); + } + } + + if (jpeg_opened) { + DiscardData(); + } +} + +status_t ExifElementsTable::insertElement(const char* tag, const char* value) { + unsigned int value_length = 0; + status_t ret = NO_ERROR; + + if (!value || !tag) { + return -EINVAL; + } + + if (position >= MAX_EXIF_TAGS_SUPPORTED) { + CAMHAL_LOGEA("Max number of EXIF elements already inserted"); + return NO_MEMORY; + } + + if (isAsciiTag(tag)) { + value_length = sizeof(ExifAsciiPrefix) + strlen(value + sizeof(ExifAsciiPrefix)); + } else { + value_length = strlen(value); + } + + if (IsGpsTag(tag)) { + table[position].GpsTag = TRUE; + table[position].Tag = GpsTagNameToValue(tag); + gps_tag_count++; + } else { + table[position].GpsTag = FALSE; + table[position].Tag = TagNameToValue(tag); + exif_tag_count++; + + if (strcmp(tag, TAG_DATETIME) == 0) { +#ifdef ANDROID_API_JB_OR_LATER + has_datetime_tag = true; +#else + // jhead isn't taking datetime tag...this is a WA + ImageInfo.numDateTimeTags = 1; + memcpy(ImageInfo.DateTime, value, + MIN(ARRAY_SIZE(ImageInfo.DateTime), value_length + 1)); +#endif + } + } + + table[position].DataLength = 0; + table[position].Value = (char*) malloc(sizeof(char) * (value_length + 1)); + + if (table[position].Value) { + memcpy(table[position].Value, value, value_length + 1); + table[position].DataLength = value_length + 1; + } + + position++; + return ret; +} + +/* private member functions */ +size_t Encoder_libjpeg::encode(params* input) { + jpeg_compress_struct cinfo; + jpeg_error_mgr jerr; + jpeg_destination_mgr jdest; + uint8_t* src = NULL, *resize_src = NULL; + uint8_t* row_tmp = NULL; + uint8_t* row_src = NULL; + uint8_t* row_uv = NULL; // used only for NV12 + int out_width = 0, in_width = 0; + int out_height = 0, in_height = 0; + int bpp = 2; // for uyvy + int right_crop = 0, start_offset = 0; + + if (!input) { + return 0; + } + + out_width = input->out_width; + in_width = input->in_width; + out_height = input->out_height; + in_height = input->in_height; + right_crop = input->right_crop; + start_offset = input->start_offset; + src = input->src; + input->jpeg_size = 0; + + libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size); + + // param check... + if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) || + (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) || + (input->dst_size < 1) || (input->format == NULL)) { + goto exit; + } + + if (strcmp(input->format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + bpp = 1; + if ((in_width != out_width) || (in_height != out_height)) { + resize_src = (uint8_t*) malloc(input->dst_size); + resize_nv12(input, resize_src); + if (resize_src) src = resize_src; + } + } else if (strcmp(input->format, android::CameraParameters::PIXEL_FORMAT_YUV422I) && + strcmp(input->format, TICameraParameters::PIXEL_FORMAT_YUV422I_UYVY)) { + // we currently only support yuv422i and yuv420sp + CAMHAL_LOGEB("Encoder: format not supported: %s", input->format); + goto exit; + } else if ((in_width != out_width) || (in_height != out_height)) { + CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format); + goto exit; + } + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_compress(&cinfo); + + CAMHAL_LOGDB("encoding... \n\t" + "width: %d \n\t" + "height:%d \n\t" + "dest %p \n\t" + "dest size:%d \n\t" + "mSrc %p \n\t" + "format: %s", + out_width, out_height, input->dst, + input->dst_size, src, input->format); + + cinfo.dest = &dest_mgr; + cinfo.image_width = out_width - right_crop; + cinfo.image_height = out_height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + cinfo.input_gamma = 1; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, input->quality, TRUE); + cinfo.dct_method = JDCT_IFAST; + + jpeg_start_compress(&cinfo, TRUE); + + row_tmp = (uint8_t*)malloc((out_width - right_crop) * 3); + row_src = src + start_offset; + row_uv = src + out_width * out_height * bpp; + + while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { + JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ + + // convert input yuv format to yuv444 + if (strcmp(input->format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + nv21_to_yuv(row_tmp, row_src, row_uv, out_width - right_crop); + } else if (strcmp(input->format, TICameraParameters::PIXEL_FORMAT_YUV422I_UYVY) == 0) { + uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width - right_crop); + } else if (strcmp(input->format, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width - right_crop); + } + + row[0] = row_tmp; + jpeg_write_scanlines(&cinfo, row, 1); + row_src = row_src + out_width*bpp; + + // move uv row if input format needs it + if (strcmp(input->format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + if (!(cinfo.next_scanline % 2)) + row_uv = row_uv + out_width * bpp; + } + } + + // no need to finish encoding routine if we are prematurely stopping + // we will end up crashing in dest_mgr since data is incomplete + if (!mCancelEncoding) + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + if (resize_src) free(resize_src); + if (row_tmp) free(row_tmp); + + exit: + input->jpeg_size = dest_mgr.jpegsize; + return dest_mgr.jpegsize; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/FrameDecoder.cpp b/camera/FrameDecoder.cpp new file mode 100644 index 0000000..80b4946 --- /dev/null +++ b/camera/FrameDecoder.cpp @@ -0,0 +1,204 @@ +/* + * 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 "Common.h" +#include "FrameDecoder.h" + + +namespace Ti { +namespace Camera { + +FrameDecoder::FrameDecoder() +: mCameraHal(NULL), mState(DecoderState_Uninitialized) { +} + +FrameDecoder::~FrameDecoder() { +} + +status_t FrameDecoder::start() { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + status_t ret; + if (mState == DecoderState_Running) { + return NO_INIT; + } + ret = doStart(); + if (ret == NO_ERROR) { + mState = DecoderState_Running; + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +void FrameDecoder::stop() { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + if (mState >= DecoderState_Requested_Stop) { + return; + } + mState = DecoderState_Requested_Stop; + doStop(); + mState = DecoderState_Stoppped; + + LOG_FUNCTION_NAME_EXIT; +} + +void FrameDecoder::release() { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + if (mState <= DecoderState_Requested_Stop) { + return; + } + doRelease(); + mState = DecoderState_Uninitialized; + + LOG_FUNCTION_NAME_EXIT; +} + +void FrameDecoder::flush() { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + if (mState <= DecoderState_Requested_Stop) { + return; + } + doFlush(); + mInQueue.clear(); + mOutQueue.clear(); + + + LOG_FUNCTION_NAME_EXIT; +} + +void FrameDecoder::configure(const DecoderParameters& params) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + if (mState == DecoderState_Running) { + return; + } + mParams = params; + mInQueue.reserve(mParams.inputBufferCount); + mOutQueue.reserve(mParams.outputBufferCount); + doConfigure(params); + mState = DecoderState_Initialized; + + LOG_FUNCTION_NAME_EXIT; +} + +status_t FrameDecoder::dequeueInputBuffer(int &id) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if (mState != DecoderState_Running) { + CAMHAL_LOGE("Try to use Decoder not in RUNNING state"); + return INVALID_OPERATION; + } + + for (size_t i = 0; i < mInQueue.size(); i++) { + int index = mInQueue[i]; + android::sp& in = mInBuffers->editItemAt(index); + android::AutoMutex bufferLock(in->getLock()); + if (in->getStatus() == BufferStatus_InDecoded) { + id = index; + in->setStatus(BufferStatus_Unknown); + mInQueue.removeAt(i); + return NO_ERROR; + } + } + + LOG_FUNCTION_NAME_EXIT; + return INVALID_OPERATION; +} + +status_t FrameDecoder::dequeueOutputBuffer(int &id) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if (mState != DecoderState_Running) { + CAMHAL_LOGE("Try to use Decoder not in RUNNING state"); + return INVALID_OPERATION; + } + + for (size_t i = 0; i < mOutQueue.size(); i++) { + int index = mOutQueue[i]; + android::sp& out = mOutBuffers->editItemAt(index); + android::AutoMutex bufferLock(out->getLock()); + if (out->getStatus() == BufferStatus_OutFilled) { + id = index; + out->setStatus(BufferStatus_Unknown); + mOutQueue.removeAt(i); + return NO_ERROR; + } + } + + LOG_FUNCTION_NAME_EXIT; + return INVALID_OPERATION; +} + +status_t FrameDecoder::queueOutputBuffer(int index) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + //We queue all available buffers to Decoder not in recording mode - before start + if (mState > DecoderState_Running) { + CAMHAL_LOGE("Try to use Decoder not in RUNNING state"); + return INVALID_OPERATION; + } + + android::sp& out = mOutBuffers->editItemAt(index); + android::AutoMutex bufferLock(out->getLock()); + out->setStatus(BufferStatus_OutQueued); + mOutQueue.push_back(index); + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + +status_t FrameDecoder::queueInputBuffer(int id) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if (mState != DecoderState_Running) { + CAMHAL_LOGE("Try to use Decoder not in RUNNING state"); + return INVALID_OPERATION; + } + + { + android::sp& in = mInBuffers->editItemAt(id); + android::AutoMutex bufferLock(in->getLock()); + in->setStatus(BufferStatus_InQueued); + mInQueue.push_back(id); + } + + // Since we got queued buffer - we can process it + doProcessInputBuffer(); + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + + +} // namespace Camera +} // namespace Ti diff --git a/camera/MemoryManager.cpp b/camera/MemoryManager.cpp new file mode 100644 index 0000000..b684203 --- /dev/null +++ b/camera/MemoryManager.cpp @@ -0,0 +1,237 @@ +/* + * 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 "CameraHal.h" +#include "TICameraParameters.h" + +extern "C" { + +//#include +//#include + + +}; + +namespace Ti { +namespace Camera { + +///@todo Move these constants to a common header file, preferably in tiler.h +#define STRIDE_8BIT (4 * 1024) +#define STRIDE_16BIT (4 * 1024) + +#define ALLOCATION_2D 2 + +///Utility Macro Declarations + +/*--------------------MemoryManager Class STARTS here-----------------------------*/ +MemoryManager::MemoryManager() { + mIonFd = -1; +} + +MemoryManager::~MemoryManager() { + if ( mIonFd >= 0 ) { + ion_close(mIonFd); + mIonFd = -1; + } +} + +status_t MemoryManager::initialize() { + if ( mIonFd == -1 ) { + mIonFd = ion_open(); + if ( mIonFd < 0 ) { + CAMHAL_LOGE("ion_open() failed, error: %d", mIonFd); + mIonFd = -1; + return NO_INIT; + } + } + + return OK; +} + +CameraBuffer* MemoryManager::allocateBufferList(int width, int height, const char* format, int &size, int numBufs) +{ + LOG_FUNCTION_NAME; + + CAMHAL_ASSERT(mIonFd != -1); + + ///We allocate numBufs+1 because the last entry will be marked NULL to indicate end of array, which is used when freeing + ///the buffers + const uint numArrayEntriesC = (uint)(numBufs+1); + + ///Allocate a buffer array + CameraBuffer *buffers = new CameraBuffer [numArrayEntriesC]; + if(!buffers) { + CAMHAL_LOGEB("Allocation failed when creating buffers array of %d CameraBuffer elements", numArrayEntriesC); + goto error; + } + + ///Initialize the array with zeros - this will help us while freeing the array in case of error + ///If a value of an array element is NULL, it means we didnt allocate it + memset(buffers, 0, sizeof(CameraBuffer) * numArrayEntriesC); + + //2D Allocations are not supported currently + if(size != 0) { + struct ion_handle *handle; + int mmap_fd; + size_t stride; + + ///1D buffers + for (int i = 0; i < numBufs; i++) { + unsigned char *data; +#ifdef USE_LIBION_TI + int ret = ion_alloc(mIonFd, size, 0, 1 << ION_HEAP_TYPE_CARVEOUT, + &handle); +#else + int ret = ion_alloc(mIonFd, size, 0, 1 << ION_HEAP_TYPE_CARVEOUT, 0, + &handle); +#endif + if((ret < 0) || ((int)handle == -ENOMEM)) { + ret = ion_alloc_tiler(mIonFd, (size_t)size, 1, TILER_PIXEL_FMT_PAGE, + OMAP_ION_HEAP_TILER_MASK, &handle, &stride); + } + + if((ret < 0) || ((int)handle == -ENOMEM)) { + CAMHAL_LOGEB("FAILED to allocate ion buffer of size=%d. ret=%d(0x%x)", size, ret, ret); + goto error; + } + + CAMHAL_LOGDB("Before mapping, handle = %p, nSize = %d", handle, size); + if ((ret = ion_map(mIonFd, handle, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0, + &data, &mmap_fd)) < 0) { + CAMHAL_LOGEB("Userspace mapping of ION buffers returned error %d", ret); + ion_free(mIonFd, handle); + goto error; + } + + buffers[i].type = CAMERA_BUFFER_ION; + buffers[i].opaque = data; + buffers[i].mapped = data; + buffers[i].ion_handle = handle; + buffers[i].ion_fd = mIonFd; + buffers[i].fd = mmap_fd; + buffers[i].size = size; + buffers[i].format = CameraHal::getPixelFormatConstant(format); + + } + } + + LOG_FUNCTION_NAME_EXIT; + + return buffers; + +error: + + CAMHAL_LOGE("Freeing buffers already allocated after error occurred"); + if(buffers) + freeBufferList(buffers); + + if ( NULL != mErrorNotifier.get() ) + mErrorNotifier->errorNotify(-ENOMEM); + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +CameraBuffer* MemoryManager::getBufferList(int *numBufs) { + LOG_FUNCTION_NAME; + if (numBufs) *numBufs = -1; + + return NULL; +} + +//TODO: Get needed data to map tiler buffers +//Return dummy data for now +uint32_t * MemoryManager::getOffsets() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +int MemoryManager::getFd() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return -1; +} + +int MemoryManager::freeBufferList(CameraBuffer *buffers) +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + int i; + + if(!buffers) + { + CAMHAL_LOGEA("NULL pointer passed to freebuffer"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + i = 0; + while(buffers[i].type == CAMERA_BUFFER_ION) + { + if(buffers[i].size) + { + munmap(buffers[i].opaque, buffers[i].size); + close(buffers[i].fd); + ion_free(mIonFd, buffers[i].ion_handle); + } + else + { + CAMHAL_LOGEA("Not a valid Memory Manager buffer"); + } + i++; + } + + delete [] buffers; + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t MemoryManager::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; +} + +} // namespace Camera +} // namespace Ti + + +/*--------------------MemoryManager Class ENDS here-----------------------------*/ diff --git a/camera/NV12_resize.cpp b/camera/NV12_resize.cpp new file mode 100644 index 0000000..971ee38 --- /dev/null +++ b/camera/NV12_resize.cpp @@ -0,0 +1,290 @@ +/* + * 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 "NV12_resize.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "NV12_resize" + +#define STRIDE 4096 + +/*========================================================================== +* Function Name : VT_resizeFrame_Video_opt2_lp +* +* Description : Resize a yuv frame. +* +* Input(s) : input_img_ptr -> Input Image Structure +* : output_img_ptr -> Output Image Structure +* : cropout -> crop structure +* +* Value Returned : mmBool -> FALSE on error TRUE on success +* NOTE: +* Not tested for crop funtionallity. +* faster version. +============================================================================*/ +mmBool +VT_resizeFrame_Video_opt2_lp( + structConvImage* i_img_ptr, /* Points to the input image */ + structConvImage* o_img_ptr, /* Points to the output image */ + IC_rect_type* cropout, /* how much to resize to in final image */ + mmUint16 dummy /* Transparent pixel value */ + ) { + LOG_FUNCTION_NAME; + + mmUint16 row,col; + mmUint32 resizeFactorX; + mmUint32 resizeFactorY; + + mmUint16 x, y; + + mmUchar* ptr8; + mmUchar *ptr8Cb, *ptr8Cr; + + mmUint16 xf, yf; + mmUchar* inImgPtrY; + mmUchar* inImgPtrU; + mmUchar* inImgPtrV; + mmUint32 cox, coy, codx, cody; + mmUint16 idx,idy, idxC; + + if ( i_img_ptr->uWidth == o_img_ptr->uWidth ) { + if ( i_img_ptr->uHeight == o_img_ptr->uHeight ) { + CAMHAL_LOGV("************************f(i_img_ptr->uHeight == o_img_ptr->uHeight) are same *********************\n"); + CAMHAL_LOGV("************************(i_img_ptr->width == %d" , i_img_ptr->uWidth ); + CAMHAL_LOGV("************************(i_img_ptr->uHeight == %d" , i_img_ptr->uHeight ); + CAMHAL_LOGV("************************(o_img_ptr->width == %d" ,o_img_ptr->uWidth ); + CAMHAL_LOGV("************************(o_img_ptr->uHeight == %d" , o_img_ptr->uHeight ); + } + } + + if ( !i_img_ptr || !i_img_ptr->imgPtr || !o_img_ptr || !o_img_ptr->imgPtr ) { + CAMHAL_LOGE("Image Point NULL"); + return false; + } + + inImgPtrY = (mmUchar *) i_img_ptr->imgPtr + i_img_ptr->uOffset; + inImgPtrU = (mmUchar *) i_img_ptr->clrPtr + i_img_ptr->uOffset/2; + inImgPtrV = (mmUchar*)inImgPtrU + 1; + + if ( !cropout ) { + cox = 0; + coy = 0; + codx = o_img_ptr->uWidth; + cody = o_img_ptr->uHeight; + } else { + cox = cropout->x; + coy = cropout->y; + codx = cropout->uWidth; + cody = cropout->uHeight; + } + idx = i_img_ptr->uWidth; + idy = i_img_ptr->uHeight; + + /* make sure valid input size */ + if ( idx < 1 || idy < 1 || i_img_ptr->uStride < 1 ) { + CAMHAL_LOGE("idx or idy less then 1 idx = %d idy = %d stride = %d", idx, idy, i_img_ptr->uStride); + return false; + } + + resizeFactorX = ((idx-1)<<9) / codx; + resizeFactorY = ((idy-1)<<9) / cody; + + if( i_img_ptr->eFormat != IC_FORMAT_YCbCr420_lp || + o_img_ptr->eFormat != IC_FORMAT_YCbCr420_lp ) { + CAMHAL_LOGE("eFormat not supported"); + return false; + } + + ptr8 = (mmUchar*)o_img_ptr->imgPtr + cox + coy*o_img_ptr->uWidth; + + ////////////////////////////for Y////////////////////////// + for ( row = 0; row < cody; row++ ) { + mmUchar *pu8Yrow1 = NULL; + mmUchar *pu8Yrow2 = NULL; + y = (mmUint16) ((mmUint32) (row*resizeFactorY) >> 9); + yf = (mmUchar) ((mmUint32)((row*resizeFactorY) >> 6) & 0x7); + pu8Yrow1 = inImgPtrY + (y) * i_img_ptr->uStride; + pu8Yrow2 = pu8Yrow1 + i_img_ptr->uStride; + + for ( col = 0; col < codx; col++ ) { + mmUchar in11, in12, in21, in22; + mmUchar *pu8ptr1 = NULL; + mmUchar *pu8ptr2 = NULL; + mmUchar w; + mmUint16 accum_1; + //mmUint32 accum_W; + + x = (mmUint16) ((mmUint32) (col*resizeFactorX) >> 9); + xf = (mmUchar) ((mmUint32) ((col*resizeFactorX) >> 6) & 0x7); + + //accum_W = 0; + accum_1 = 0; + + pu8ptr1 = pu8Yrow1 + (x); + pu8ptr2 = pu8Yrow2 + (x); + + /* A pixel */ + //in = *(inImgPtrY + (y)*idx + (x)); + in11 = *(pu8ptr1); + + w = bWeights[xf][yf][0]; + accum_1 = (w * in11); + //accum_W += (w); + + /* B pixel */ + //in = *(inImgPtrY + (y)*idx + (x+1)); + in12 = *(pu8ptr1+1); + w = bWeights[xf][yf][1]; + accum_1 += (w * in12); + //accum_W += (w); + + /* C pixel */ + //in = *(inImgPtrY + (y+1)*idx + (x)); + in21 = *(pu8ptr2); + w = bWeights[xf][yf][3]; + accum_1 += (w * in21); + //accum_W += (w); + + /* D pixel */ + //in = *(inImgPtrY + (y+1)*idx + (x+1)); + in22 = *(pu8ptr2+1); + w = bWeights[xf][yf][2]; + accum_1 += (w * in22); + //accum_W += (w); + + /* divide by sum of the weights */ + //accum_1 /= (accum_W); + //accum_1 = (accum_1/64); + accum_1 = (accum_1>>6); + *ptr8 = (mmUchar)accum_1 ; + + ptr8++; + } + ptr8 = ptr8 + (o_img_ptr->uStride - codx); + } + ////////////////////////////for Y////////////////////////// + + ///////////////////////////////for Cb-Cr////////////////////// + + ptr8Cb = (mmUchar*)o_img_ptr->clrPtr + cox + coy*o_img_ptr->uWidth; + + ptr8Cr = (mmUchar*)(ptr8Cb+1); + + idxC = (idx>>1); + for ( row = 0; row < (((cody)>>1)); row++ ) { + mmUchar *pu8Cbr1 = NULL; + mmUchar *pu8Cbr2 = NULL; + mmUchar *pu8Crr1 = NULL; + mmUchar *pu8Crr2 = NULL; + + y = (mmUint16) ((mmUint32) (row*resizeFactorY) >> 9); + yf = (mmUchar) ((mmUint32)((row*resizeFactorY) >> 6) & 0x7); + + pu8Cbr1 = inImgPtrU + (y) * i_img_ptr->uStride; + pu8Cbr2 = pu8Cbr1 + i_img_ptr->uStride; + pu8Crr1 = inImgPtrV + (y) * i_img_ptr->uStride; + pu8Crr2 = pu8Crr1 + i_img_ptr->uStride; + + for ( col = 0; col < (((codx)>>1)); col++ ) { + mmUchar in11, in12, in21, in22; + mmUchar *pu8Cbc1 = NULL; + mmUchar *pu8Cbc2 = NULL; + mmUchar *pu8Crc1 = NULL; + mmUchar *pu8Crc2 = NULL; + + mmUchar w; + mmUint16 accum_1Cb, accum_1Cr; + //mmUint32 accum_WCb, accum_WCr; + + x = (mmUint16) ((mmUint32) (col*resizeFactorX) >> 9); + xf = (mmUchar) ((mmUint32) ((col*resizeFactorX) >> 6) & 0x7); + + //accum_WCb = accum_WCr = 0; + accum_1Cb = accum_1Cr = 0; + + pu8Cbc1 = pu8Cbr1 + (x*2); + pu8Cbc2 = pu8Cbr2 + (x*2); + pu8Crc1 = pu8Crr1 + (x*2); + pu8Crc2 = pu8Crr2 + (x*2); + + /* A pixel */ + w = bWeights[xf][yf][0]; + + in11 = *(pu8Cbc1); + accum_1Cb = (w * in11); + // accum_WCb += (w); + + in11 = *(pu8Crc1); + accum_1Cr = (w * in11); + //accum_WCr += (w); + + /* B pixel */ + w = bWeights[xf][yf][1]; + + in12 = *(pu8Cbc1+2); + accum_1Cb += (w * in12); + //accum_WCb += (w); + + in12 = *(pu8Crc1+2); + accum_1Cr += (w * in12); + //accum_WCr += (w); + + /* C pixel */ + w = bWeights[xf][yf][3]; + + in21 = *(pu8Cbc2); + accum_1Cb += (w * in21); + //accum_WCb += (w); + + in21 = *(pu8Crc2); + accum_1Cr += (w * in21); + //accum_WCr += (w); + + /* D pixel */ + w = bWeights[xf][yf][2]; + + in22 = *(pu8Cbc2+2); + accum_1Cb += (w * in22); + //accum_WCb += (w); + + in22 = *(pu8Crc2+2); + accum_1Cr += (w * in22); + //accum_WCr += (w); + + /* divide by sum of the weights */ + //accum_1Cb /= (accum_WCb); + accum_1Cb = (accum_1Cb>>6); + *ptr8Cb = (mmUchar)accum_1Cb ; + + accum_1Cr = (accum_1Cr >> 6); + *ptr8Cr = (mmUchar)accum_1Cr ; + + ptr8Cb++; + ptr8Cr++; + + ptr8Cb++; + ptr8Cr++; + } + ptr8Cb = ptr8Cb + (o_img_ptr->uStride-codx); + ptr8Cr = ptr8Cr + (o_img_ptr->uStride-codx); + } + ///////////////////For Cb- Cr//////////////////////////////////////// + + CAMHAL_LOGV("success"); + return true; +} diff --git a/camera/OMXCameraAdapter/OMX3A.cpp b/camera/OMXCameraAdapter/OMX3A.cpp new file mode 100644 index 0000000..8e6437a --- /dev/null +++ b/camera/OMXCameraAdapter/OMX3A.cpp @@ -0,0 +1,2161 @@ +/* + * 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. + */ + +/** +* @file OMX3A.cpp +* +* This file contains functionality for handling 3A configurations. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +#include + +#define METERING_AREAS_RANGE 0xFF + +static const char PARAM_SEP[] = ","; + +namespace Ti { +namespace Camera { + +const SceneModesEntry* OMXCameraAdapter::getSceneModeEntry(const char* name, + OMX_SCENEMODETYPE scene) { + const SceneModesEntry* cameraLUT = NULL; + const SceneModesEntry* entry = NULL; + unsigned int numEntries = 0; + + // 1. Find camera's scene mode LUT + for (unsigned int i = 0; i < ARRAY_SIZE(CameraToSensorModesLUT); i++) { + if (strcmp(CameraToSensorModesLUT[i].name, name) == 0) { + cameraLUT = CameraToSensorModesLUT[i].Table; + numEntries = CameraToSensorModesLUT[i].size; + break; + } + } + + // 2. Find scene mode entry in table + if (!cameraLUT) { + goto EXIT; + } + + for (unsigned int i = 0; i < numEntries; i++) { + if(cameraLUT[i].scene == scene) { + entry = cameraLUT + i; + break; + } + } + EXIT: + return entry; +} + +status_t OMXCameraAdapter::setParameters3A(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + int mode = 0; + const char *str = NULL; + int varint = 0; + BaseCameraAdapter::AdapterState nextState; + BaseCameraAdapter::getNextState(nextState); + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(m3ASettingsUpdateLock); + + str = params.get(android::CameraParameters::KEY_SCENE_MODE); + mode = getLUTvalue_HALtoOMX( str, SceneLUT); + if ( mFirstTimeInit || ((str != NULL) && ( mParameters3A.SceneMode != mode )) ) { + if ( 0 <= mode ) { + mParameters3A.SceneMode = mode; + if ((mode == OMX_Manual) && (mFirstTimeInit == false)){//Auto mode + mFirstTimeInit = true; + } + if ((mode != OMX_Manual) && + (state & PREVIEW_ACTIVE) && !(nextState & CAPTURE_ACTIVE)) { + // if setting preset scene mode, previewing, and not in the middle of capture + // set preset scene mode immediately instead of in next FBD + // for feedback params to work properly since they need to be read + // by application in subsequent getParameters() + ret |= setScene(mParameters3A); + // re-apply EV compensation after setting scene mode since it probably reset it + if(mParameters3A.EVCompensation) { + setEVCompensation(mParameters3A); + } + return ret; + } else { + mPending3Asettings |= SetSceneMode; + } + } else { + mParameters3A.SceneMode = OMX_Manual; + } + CAMHAL_LOGVB("SceneMode %d", mParameters3A.SceneMode); + } + +#ifdef OMAP_ENHANCEMENT + if ( (str = params.get(TICameraParameters::KEY_EXPOSURE_MODE)) != NULL ) { + mode = getLUTvalue_HALtoOMX(str, ExpLUT); + if ( mParameters3A.Exposure != mode ) { + // If either the new or the old exposure mode is manual set also + // the SetManualExposure flag to call setManualExposureVal where + // the auto gain and exposure flags are configured + if ( mParameters3A.Exposure == OMX_ExposureControlOff || + mode == OMX_ExposureControlOff ) { + mPending3Asettings |= SetManualExposure; + } + mParameters3A.Exposure = mode; + CAMHAL_LOGDB("Exposure mode %d", mode); + if ( 0 <= mParameters3A.Exposure ) { + mPending3Asettings |= SetExpMode; + } + } + if ( mode == OMX_ExposureControlOff ) { + mode = params.getInt(TICameraParameters::KEY_MANUAL_EXPOSURE); + if ( mParameters3A.ManualExposure != mode ) { + mParameters3A.ManualExposure = mode; + CAMHAL_LOGDB("Manual Exposure = %d", mode); + mPending3Asettings |= SetManualExposure; + } + mode = params.getInt(TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT); + if ( mParameters3A.ManualExposureRight != mode ) { + mParameters3A.ManualExposureRight = mode; + CAMHAL_LOGDB("Manual Exposure right = %d", mode); + mPending3Asettings |= SetManualExposure; + } + mode = params.getInt(TICameraParameters::KEY_MANUAL_GAIN_ISO); + if ( mParameters3A.ManualGain != mode ) { + mParameters3A.ManualGain = mode; + CAMHAL_LOGDB("Manual Gain = %d", mode); + mPending3Asettings |= SetManualExposure; + } + mode = params.getInt(TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT); + if ( mParameters3A.ManualGainRight != mode ) { + mParameters3A.ManualGainRight = mode; + CAMHAL_LOGDB("Manual Gain right = %d", mode); + mPending3Asettings |= SetManualExposure; + } + } + } +#endif + + str = params.get(android::CameraParameters::KEY_WHITE_BALANCE); + mode = getLUTvalue_HALtoOMX( str, WBalLUT); + if (mFirstTimeInit || ((str != NULL) && (mode != mParameters3A.WhiteBallance))) + { + mParameters3A.WhiteBallance = mode; + CAMHAL_LOGDB("Whitebalance mode %d", mode); + if ( 0 <= mParameters3A.WhiteBallance ) + { + mPending3Asettings |= SetWhiteBallance; + } + } + +#ifdef OMAP_ENHANCEMENT + varint = params.getInt(TICameraParameters::KEY_CONTRAST); + if ( 0 <= varint ) + { + if ( mFirstTimeInit || + ( (mParameters3A.Contrast + CONTRAST_OFFSET) != varint ) ) + { + mParameters3A.Contrast = varint - CONTRAST_OFFSET; + CAMHAL_LOGDB("Contrast %d", mParameters3A.Contrast); + mPending3Asettings |= SetContrast; + } + } + + varint = params.getInt(TICameraParameters::KEY_SHARPNESS); + if ( 0 <= varint ) + { + if ( mFirstTimeInit || + ((mParameters3A.Sharpness + SHARPNESS_OFFSET) != varint )) + { + mParameters3A.Sharpness = varint - SHARPNESS_OFFSET; + CAMHAL_LOGDB("Sharpness %d", mParameters3A.Sharpness); + mPending3Asettings |= SetSharpness; + } + } + + varint = params.getInt(TICameraParameters::KEY_SATURATION); + if ( 0 <= varint ) + { + if ( mFirstTimeInit || + ((mParameters3A.Saturation + SATURATION_OFFSET) != varint ) ) + { + mParameters3A.Saturation = varint - SATURATION_OFFSET; + CAMHAL_LOGDB("Saturation %d", mParameters3A.Saturation); + mPending3Asettings |= SetSaturation; + } + } + + varint = params.getInt(TICameraParameters::KEY_BRIGHTNESS); + if ( 0 <= varint ) + { + if ( mFirstTimeInit || + (( mParameters3A.Brightness != varint )) ) + { + mParameters3A.Brightness = (unsigned) varint; + CAMHAL_LOGDB("Brightness %d", mParameters3A.Brightness); + mPending3Asettings |= SetBrightness; + } + } +#endif + + str = params.get(android::CameraParameters::KEY_ANTIBANDING); + mode = getLUTvalue_HALtoOMX(str,FlickerLUT); + if ( mFirstTimeInit || ( ( str != NULL ) && ( mParameters3A.Flicker != mode ) )) + { + mParameters3A.Flicker = mode; + CAMHAL_LOGDB("Flicker %d", mParameters3A.Flicker); + if ( 0 <= mParameters3A.Flicker ) + { + mPending3Asettings |= SetFlicker; + } + } + +#ifdef OMAP_ENHANCEMENT + str = params.get(TICameraParameters::KEY_ISO); + mode = getLUTvalue_HALtoOMX(str, IsoLUT); + CAMHAL_LOGVB("ISO mode arrived in HAL : %s", str); + if ( mFirstTimeInit || ( ( str != NULL ) && ( mParameters3A.ISO != mode )) ) + { + mParameters3A.ISO = mode; + CAMHAL_LOGDB("ISO %d", mParameters3A.ISO); + if ( 0 <= mParameters3A.ISO ) + { + mPending3Asettings |= SetISO; + } + } +#endif + + str = params.get(android::CameraParameters::KEY_FOCUS_MODE); + mode = getLUTvalue_HALtoOMX(str, FocusLUT); + if ( (mFirstTimeInit || ((str != NULL) && (mParameters3A.Focus != mode)))) + { + mPending3Asettings |= SetFocus; + + mParameters3A.Focus = mode; + + // if focus mode is set to infinity...update focus distance immediately + if (mode == OMX_IMAGE_FocusControlAutoInfinity) { + updateFocusDistances(mParameters); + } + + CAMHAL_LOGDB("Focus %x", mParameters3A.Focus); + } + + str = params.get(android::CameraParameters::KEY_EXPOSURE_COMPENSATION); + varint = params.getInt(android::CameraParameters::KEY_EXPOSURE_COMPENSATION); + if ( mFirstTimeInit || (str && (mParameters3A.EVCompensation != varint))) { + CAMHAL_LOGDB("Setting EV Compensation to %d", varint); + mParameters3A.EVCompensation = varint; + mPending3Asettings |= SetEVCompensation; + } + + str = params.get(android::CameraParameters::KEY_FLASH_MODE); + mode = getLUTvalue_HALtoOMX( str, FlashLUT); + if ( mFirstTimeInit || (( str != NULL ) && ( mParameters3A.FlashMode != mode )) ) + { + if ( 0 <= mode ) + { + mParameters3A.FlashMode = mode; + mPending3Asettings |= SetFlash; + } + else + { + mParameters3A.FlashMode = OMX_IMAGE_FlashControlAuto; + } + } + + CAMHAL_LOGVB("Flash Setting %s", str); + CAMHAL_LOGVB("FlashMode %d", mParameters3A.FlashMode); + + str = params.get(android::CameraParameters::KEY_EFFECT); + mode = getLUTvalue_HALtoOMX( str, EffLUT); + if ( mFirstTimeInit || (( str != NULL ) && ( mParameters3A.Effect != mode )) ) + { + mParameters3A.Effect = mode; + CAMHAL_LOGDB("Effect %d", mParameters3A.Effect); + if ( 0 <= mParameters3A.Effect ) + { + mPending3Asettings |= SetEffect; + } + } + + str = params.get(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, android::CameraParameters::TRUE)) ) + { + OMX_BOOL lock = OMX_FALSE; + mUserSetExpLock = OMX_FALSE; + str = params.get(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK); + if (str && ((strcmp(str, android::CameraParameters::TRUE)) == 0)) + { + CAMHAL_LOGVA("Locking Exposure"); + lock = OMX_TRUE; + mUserSetExpLock = OMX_TRUE; + } + else + { + CAMHAL_LOGVA("UnLocking Exposure"); + } + + if (mParameters3A.ExposureLock != lock) + { + mParameters3A.ExposureLock = lock; + CAMHAL_LOGDB("ExposureLock %d", lock); + mPending3Asettings |= SetExpLock; + } + } + + str = params.get(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, android::CameraParameters::TRUE)) ) + { + OMX_BOOL lock = OMX_FALSE; + mUserSetWbLock = OMX_FALSE; + str = params.get(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); + if (str && ((strcmp(str, android::CameraParameters::TRUE)) == 0)) + { + CAMHAL_LOGVA("Locking WhiteBalance"); + lock = OMX_TRUE; + mUserSetWbLock = OMX_TRUE; + } + else + { + CAMHAL_LOGVA("UnLocking WhiteBalance"); + } + if (mParameters3A.WhiteBalanceLock != lock) + { + mParameters3A.WhiteBalanceLock = lock; + CAMHAL_LOGDB("WhiteBalanceLock %d", lock); + mPending3Asettings |= SetWBLock; + } + } + + str = params.get(TICameraParameters::KEY_AUTO_FOCUS_LOCK); + if (str && (strcmp(str, android::CameraParameters::TRUE) == 0) && (mParameters3A.FocusLock != OMX_TRUE)) { + CAMHAL_LOGVA("Locking Focus"); + mParameters3A.FocusLock = OMX_TRUE; + setFocusLock(mParameters3A); + } else if (str && (strcmp(str, android::CameraParameters::FALSE) == 0) && (mParameters3A.FocusLock != OMX_FALSE)) { + CAMHAL_LOGVA("UnLocking Focus"); + mParameters3A.FocusLock = OMX_FALSE; + setFocusLock(mParameters3A); + } + + str = params.get(android::CameraParameters::KEY_METERING_AREAS); + if ( (str != NULL) ) { + size_t MAX_METERING_AREAS; + android::Vector > tempAreas; + + MAX_METERING_AREAS = atoi(params.get(android::CameraParameters::KEY_MAX_NUM_METERING_AREAS)); + + android::AutoMutex lock(mMeteringAreasLock); + + ret = CameraArea::parseAreas(str, ( strlen(str) + 1 ), tempAreas); + + CAMHAL_LOGVB("areAreasDifferent? = %d", + CameraArea::areAreasDifferent(mMeteringAreas, tempAreas)); + + if ( (NO_ERROR == ret) && CameraArea::areAreasDifferent(mMeteringAreas, tempAreas) ) { + mMeteringAreas.clear(); + mMeteringAreas = tempAreas; + + if ( MAX_METERING_AREAS >= mMeteringAreas.size() ) { + CAMHAL_LOGDB("Setting Metering Areas %s", + params.get(android::CameraParameters::KEY_METERING_AREAS)); + + mPending3Asettings |= SetMeteringAreas; + } else { + CAMHAL_LOGEB("Metering areas supported %d, metering areas set %d", + MAX_METERING_AREAS, mMeteringAreas.size()); + ret = -EINVAL; + } + } + } + +#ifndef MOTOROLA_CAMERA +// TI extensions for enable/disable algos + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_EXTERNAL_GAMMA, + mParameters3A.AlgoExternalGamma, SetAlgoExternalGamma, "External Gamma"); + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_NSF1, + mParameters3A.AlgoNSF1, SetAlgoNSF1, "NSF1"); + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_NSF2, + mParameters3A.AlgoNSF2, SetAlgoNSF2, "NSF2"); + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_SHARPENING, + mParameters3A.AlgoSharpening, SetAlgoSharpening, "Sharpening"); + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_THREELINCOLORMAP, + mParameters3A.AlgoThreeLinColorMap, SetAlgoThreeLinColorMap, "ThreeLinColorMap"); + declareParameter3ABool(params, TICameraParameters::KEY_ALGO_GIC, mParameters3A.AlgoGIC, SetAlgoGIC, "GIC"); + + // Gamma table + str = params.get(TICameraParameters::KEY_GAMMA_TABLE); + updateGammaTable(str); +#endif + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +#ifndef MOTOROLA_CAMERA +void OMXCameraAdapter::updateGammaTable(const char* gamma) +{ + unsigned int plane = 0; + unsigned int i = 0; + bool gamma_changed = false; + const char *a = gamma; + OMX_TI_GAMMATABLE_ELEM_TYPE *elem[3] = { mParameters3A.mGammaTable.pR, + mParameters3A.mGammaTable.pG, + mParameters3A.mGammaTable.pB}; + + if (!gamma) return; + + mPending3Asettings &= ~SetGammaTable; + memset(&mParameters3A.mGammaTable, 0, sizeof(mParameters3A.mGammaTable)); + for (plane = 0; plane < 3; plane++) { + a = strchr(a, '('); + if (NULL != a) { + a++; + for (i = 0; i < OMX_TI_GAMMATABLE_SIZE; i++) { + char *b; + int newVal; + newVal = strtod(a, &b); + if (newVal != elem[plane][i].nOffset) { + elem[plane][i].nOffset = newVal; + gamma_changed = true; + } + a = strpbrk(b, ",:)"); + if ((NULL != a) && (':' == *a)) { + a++; + } else if ((NULL != a) && (',' == *a)){ + a++; + break; + } else if ((NULL != a) && (')' == *a)){ + a++; + break; + } else { + CAMHAL_LOGE("Error while parsing values"); + gamma_changed = false; + break; + } + newVal = strtod(a, &b); + if (newVal != elem[plane][i].nSlope) { + elem[plane][i].nSlope = newVal; + gamma_changed = true; + } + a = strpbrk(b, ",:)"); + if ((NULL != a) && (',' == *a)) { + a++; + } else if ((NULL != a) && (':' == *a)){ + a++; + break; + } else if ((NULL != a) && (')' == *a)){ + a++; + break; + } else { + CAMHAL_LOGE("Error while parsing values"); + gamma_changed = false; + break; + } + } + if ((OMX_TI_GAMMATABLE_SIZE - 1) != i) { + CAMHAL_LOGE("Error while parsing values (incorrect count %u)", i); + gamma_changed = false; + break; + } + } else { + CAMHAL_LOGE("Error while parsing planes (%u)", plane); + gamma_changed = false; + break; + } + } + + if (gamma_changed) { + mPending3Asettings |= SetGammaTable; + } +} +#endif + +void OMXCameraAdapter::declareParameter3ABool(const android::CameraParameters ¶ms, const char *key, + OMX_BOOL ¤t_setting, E3ASettingsFlags pending, + const char *msg) +{ + OMX_BOOL val = OMX_TRUE; + const char *str = params.get(key); + + if (str && ((strcmp(str, android::CameraParameters::FALSE)) == 0)) + { + CAMHAL_LOGVB("Disabling %s", msg); + val = OMX_FALSE; + } + else + { + CAMHAL_LOGVB("Enabling %s", msg); + } + if (current_setting != val) + { + current_setting = val; + CAMHAL_LOGDB("%s %s", msg, current_setting ? "enabled" : "disabled"); + mPending3Asettings |= pending; + } +} + +int OMXCameraAdapter::getLUTvalue_HALtoOMX(const char * HalValue, LUTtype LUT) +{ + int LUTsize = LUT.size; + if( HalValue ) + for(int i = 0; i < LUTsize; i++) + if( 0 == strcmp(LUT.Table[i].userDefinition, HalValue) ) + return LUT.Table[i].omxDefinition; + + return -ENOENT; +} + +const char* OMXCameraAdapter::getLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT) +{ + int LUTsize = LUT.size; + for(int i = 0; i < LUTsize; i++) + if( LUT.Table[i].omxDefinition == OMXValue ) + return LUT.Table[i].userDefinition; + + return NULL; +} + +int OMXCameraAdapter::getMultipleLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT, char * supported) +{ + int num = 0; + int remaining_size; + int LUTsize = LUT.size; + for(int i = 0; i < LUTsize; i++) + if( LUT.Table[i].omxDefinition == OMXValue ) + { + num++; + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + remaining_size = ((((int)MAX_PROP_VALUE_LENGTH - 1 - (int)strlen(supported)) < 0) ? 0 : (MAX_PROP_VALUE_LENGTH - 1 - strlen(supported))); + strncat(supported, LUT.Table[i].userDefinition, remaining_size); + } + + return num; +} + +status_t OMXCameraAdapter::setExposureMode(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSURECONTROLTYPE exp; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&exp, OMX_CONFIG_EXPOSURECONTROLTYPE); + exp.nPortIndex = OMX_ALL; + exp.eExposureControl = (OMX_EXPOSURECONTROLTYPE)Gen3A.Exposure; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposure, + &exp); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring exposure mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera exposure mode configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +static bool isFlashDisabled() { +#if (PROPERTY_VALUE_MAX < 5) +#error "PROPERTY_VALUE_MAX must be at least 5" +#endif + + // Ignore flash_off system property for user build. + char buildType[PROPERTY_VALUE_MAX]; + if (property_get("ro.build.type", buildType, NULL) && + !strcasecmp(buildType, "user")) { + return false; + } + + char value[PROPERTY_VALUE_MAX]; + if (property_get("camera.flash_off", value, NULL) && + (!strcasecmp(value, android::CameraParameters::TRUE) || !strcasecmp(value, "1"))) { + CAMHAL_LOGW("flash is disabled for testing purpose"); + return true; + } + + return false; +} + +status_t OMXCameraAdapter::setManualExposureVal(Gen3A_settings& Gen3A) { + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expVal; + OMX_TI_CONFIG_EXPOSUREVALUERIGHTTYPE expValRight; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expVal, OMX_CONFIG_EXPOSUREVALUETYPE); + OMX_INIT_STRUCT_PTR (&expValRight, OMX_TI_CONFIG_EXPOSUREVALUERIGHTTYPE); + expVal.nPortIndex = OMX_ALL; + expValRight.nPortIndex = OMX_ALL; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expVal); + if ( OMX_ErrorNone == eError ) { + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigRightExposureValue, + &expValRight); + } + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("OMX_GetConfig error 0x%x (manual exposure values)", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + if ( Gen3A.Exposure != OMX_ExposureControlOff ) { + expVal.bAutoShutterSpeed = OMX_TRUE; + expVal.bAutoSensitivity = OMX_TRUE; + } else { + expVal.bAutoShutterSpeed = OMX_FALSE; + expVal.nShutterSpeedMsec = Gen3A.ManualExposure; + expValRight.nShutterSpeedMsec = Gen3A.ManualExposureRight; + if ( Gen3A.ManualGain <= 0 || Gen3A.ManualGainRight <= 0 ) { + expVal.bAutoSensitivity = OMX_TRUE; + } else { + expVal.bAutoSensitivity = OMX_FALSE; + expVal.nSensitivity = Gen3A.ManualGain; + expValRight.nSensitivity = Gen3A.ManualGainRight; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expVal); + if ( OMX_ErrorNone == eError ) { + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigRightExposureValue, + &expValRight); + } + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error 0x%x while configuring manual exposure values", eError); + } else { + CAMHAL_LOGDA("Camera manual exposure values configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setFlashMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_PARAM_FLASHCONTROLTYPE flash; + OMX_CONFIG_FOCUSASSISTTYPE focusAssist; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&flash, OMX_IMAGE_PARAM_FLASHCONTROLTYPE); + flash.nPortIndex = OMX_ALL; + + if (isFlashDisabled()) { + flash.eFlashControl = ( OMX_IMAGE_FLASHCONTROLTYPE ) OMX_IMAGE_FlashControlOff; + } else { + flash.eFlashControl = ( OMX_IMAGE_FLASHCONTROLTYPE ) Gen3A.FlashMode; + } + + CAMHAL_LOGDB("Configuring flash mode 0x%x", flash.eFlashControl); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigFlashControl, + &flash); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring flash mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera flash mode configured successfully"); + } + + if ( OMX_ErrorNone == eError ) + { + OMX_INIT_STRUCT_PTR (&focusAssist, OMX_CONFIG_FOCUSASSISTTYPE); + focusAssist.nPortIndex = OMX_ALL; + if ( flash.eFlashControl == OMX_IMAGE_FlashControlOff ) + { + focusAssist.bFocusAssist = OMX_FALSE; + } + else + { + focusAssist.bFocusAssist = OMX_TRUE; + } + + CAMHAL_LOGDB("Configuring AF Assist mode 0x%x", focusAssist.bFocusAssist); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigFocusAssist, + &focusAssist); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring AF Assist mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera AF Assist mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getFlashMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_PARAM_FLASHCONTROLTYPE flash; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&flash, OMX_IMAGE_PARAM_FLASHCONTROLTYPE); + flash.nPortIndex = OMX_ALL; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigFlashControl, + &flash); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while getting flash mode 0x%x", eError); + } else { + Gen3A.FlashMode = flash.eFlashControl; + CAMHAL_LOGDB("Gen3A.FlashMode 0x%x", Gen3A.FlashMode); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setFocusMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focus; + size_t top, left, width, height, weight; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + + ///Face detection takes precedence over touch AF + if ( mFaceDetectionRunning ) + { + //Disable region priority first + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + + //Enable face algorithm priority for focus + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO , true); + + //Do normal focus afterwards + ////FIXME: Check if the extended focus control is needed? this overrides caf + //focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; + } + else if ( (!mFocusAreas.isEmpty()) && (!mFocusAreas.itemAt(0)->isZeroArea()) ) + { + + //Disable face priority first + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + + //Enable region algorithm priority + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true); + + + //Do normal focus afterwards + //FIXME: Check if the extended focus control is needed? this overrides caf + //focus.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; + + } + else + { + + //Disable both region and face priority + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + + } + + if ( NO_ERROR == ret && ((state & AF_ACTIVE) == 0) ) + { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + + if ( Gen3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) + { + // Don't lock at infinity, otherwise the AF cannot drive + // the lens at infinity position + if( set3ALock(mUserSetExpLock, mUserSetWbLock, OMX_FALSE) != NO_ERROR) + { + CAMHAL_LOGEA("Error Applying 3A locks"); + } else { + CAMHAL_LOGDA("Focus locked. Applied focus locks successfully"); + } + } + if ( Gen3A.Focus == OMX_IMAGE_FocusControlAuto || + Gen3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) + { + // Run focus scanning if switching to continuous infinity focus mode + bOMX.bEnabled = OMX_TRUE; + } + else + { + bOMX.bEnabled = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutofocusEnable, + &bOMX); + + OMX_INIT_STRUCT_PTR (&focus, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focus.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + focus.eFocusControl = (OMX_IMAGE_FOCUSCONTROLTYPE)Gen3A.Focus; + + CAMHAL_LOGDB("Configuring focus mode 0x%x", focus.eFocusControl); + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigFocusControl, &focus); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring focus mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera focus mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getFocusMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focus; + size_t top, left, width, height, weight; + + LOG_FUNCTION_NAME; + + if (OMX_StateInvalid == mComponentState) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&focus, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focus.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, &focus); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while configuring focus mode 0x%x", eError); + } else { + Gen3A.Focus = focus.eFocusControl; + CAMHAL_LOGDB("Gen3A.Focus 0x%x", Gen3A.Focus); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setScene(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SCENEMODETYPE scene; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&scene, OMX_CONFIG_SCENEMODETYPE); + scene.nPortIndex = OMX_ALL; + scene.eSceneMode = ( OMX_SCENEMODETYPE ) Gen3A.SceneMode; + + CAMHAL_LOGDB("Configuring scene mode 0x%x", scene.eSceneMode); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSceneMode, + &scene); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while configuring scene mode 0x%x", eError); + } else { + CAMHAL_LOGDA("Camera scene configured successfully"); + if (Gen3A.SceneMode != OMX_Manual) { + // Get preset scene mode feedback + getFocusMode(Gen3A); + getFlashMode(Gen3A); + getWBMode(Gen3A); + + // TODO(XXX): Re-enable these for mainline + // getSharpness(Gen3A); + // getSaturation(Gen3A); + // getISO(Gen3A); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setEVCompensation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + CAMHAL_LOGDB("old EV Compensation for OMX = 0x%x", (int)expValues.xEVCompensation); + CAMHAL_LOGDB("EV Compensation for HAL = %d", Gen3A.EVCompensation); + + expValues.xEVCompensation = ( Gen3A.EVCompensation * ( 1 << Q16_OFFSET ) ) / 10; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + CAMHAL_LOGDB("new EV Compensation for OMX = 0x%x", (int)expValues.xEVCompensation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring EV Compensation 0x%x error = 0x%x", + ( unsigned int ) expValues.xEVCompensation, + eError); + } + else + { + CAMHAL_LOGDB("EV Compensation 0x%x configured successfully", + ( unsigned int ) expValues.xEVCompensation); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getEVCompensation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while getting EV Compensation error = 0x%x", eError); + } else { + Gen3A.EVCompensation = (10 * expValues.xEVCompensation) / (1 << Q16_OFFSET); + CAMHAL_LOGDB("Gen3A.EVCompensation 0x%x", Gen3A.EVCompensation); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setWBMode(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_WHITEBALCONTROLTYPE wb; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&wb, OMX_CONFIG_WHITEBALCONTROLTYPE); + wb.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + wb.eWhiteBalControl = ( OMX_WHITEBALCONTROLTYPE ) Gen3A.WhiteBallance; + + // disable face and region priorities + setAlgoPriority(FACE_PRIORITY, WHITE_BALANCE_ALGO, false); + setAlgoPriority(REGION_PRIORITY, WHITE_BALANCE_ALGO, false); + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonWhiteBalance, + &wb); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Whitebalance mode 0x%x error = 0x%x", + ( unsigned int ) wb.eWhiteBalControl, + eError); + } + else + { + CAMHAL_LOGDB("Whitebalance mode 0x%x configured successfully", + ( unsigned int ) wb.eWhiteBalControl); + } + + LOG_FUNCTION_NAME_EXIT; + + return eError; +} + +status_t OMXCameraAdapter::getWBMode(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_WHITEBALCONTROLTYPE wb; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&wb, OMX_CONFIG_WHITEBALCONTROLTYPE); + wb.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonWhiteBalance, + &wb); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while getting Whitebalance mode error = 0x%x", eError); + } else { + Gen3A.WhiteBallance = wb.eWhiteBalControl; + CAMHAL_LOGDB("Gen3A.WhiteBallance 0x%x", Gen3A.WhiteBallance); + } + + LOG_FUNCTION_NAME_EXIT; + + return eError; +} + +status_t OMXCameraAdapter::setFlicker(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_FLICKERCANCELTYPE flicker; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&flicker, OMX_CONFIG_FLICKERCANCELTYPE); + flicker.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + flicker.eFlickerCancel = (OMX_COMMONFLICKERCANCELTYPE)Gen3A.Flicker; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigFlickerCancel, + &flicker ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Flicker mode 0x%x error = 0x%x", + ( unsigned int ) flicker.eFlickerCancel, + eError); + } + else + { + CAMHAL_LOGDB("Flicker mode 0x%x configured successfully", + ( unsigned int ) flicker.eFlickerCancel); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setBrightness(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BRIGHTNESSTYPE brightness; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&brightness, OMX_CONFIG_BRIGHTNESSTYPE); + brightness.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + brightness.nBrightness = Gen3A.Brightness; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonBrightness, + &brightness); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Brightness 0x%x error = 0x%x", + ( unsigned int ) brightness.nBrightness, + eError); + } + else + { + CAMHAL_LOGDB("Brightness 0x%x configured successfully", + ( unsigned int ) brightness.nBrightness); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setContrast(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CONTRASTTYPE contrast; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&contrast, OMX_CONFIG_CONTRASTTYPE); + contrast.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + contrast.nContrast = Gen3A.Contrast; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonContrast, + &contrast); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Contrast 0x%x error = 0x%x", + ( unsigned int ) contrast.nContrast, + eError); + } + else + { + CAMHAL_LOGDB("Contrast 0x%x configured successfully", + ( unsigned int ) contrast.nContrast); + } + + LOG_FUNCTION_NAME_EXIT; + + return eError; +} + +status_t OMXCameraAdapter::setSharpness(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE procSharpness; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&procSharpness, OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE); + procSharpness.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + procSharpness.nLevel = Gen3A.Sharpness; + + if( procSharpness.nLevel == 0 ) + { + procSharpness.bAuto = OMX_TRUE; + } + else + { + procSharpness.bAuto = OMX_FALSE; + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigSharpeningLevel, + &procSharpness); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Sharpness 0x%x error = 0x%x", + ( unsigned int ) procSharpness.nLevel, + eError); + } + else + { + CAMHAL_LOGDB("Sharpness 0x%x configured successfully", + ( unsigned int ) procSharpness.nLevel); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getSharpness(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE procSharpness; + + LOG_FUNCTION_NAME; + + if (OMX_StateInvalid == mComponentState) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&procSharpness, OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE); + procSharpness.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigSharpeningLevel, + &procSharpness); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while configuring Sharpness error = 0x%x", eError); + } else { + Gen3A.Sharpness = procSharpness.nLevel; + CAMHAL_LOGDB("Gen3A.Sharpness 0x%x", Gen3A.Sharpness); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setSaturation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SATURATIONTYPE saturation; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&saturation, OMX_CONFIG_SATURATIONTYPE); + saturation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + saturation.nSaturation = Gen3A.Saturation; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonSaturation, + &saturation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Saturation 0x%x error = 0x%x", + ( unsigned int ) saturation.nSaturation, + eError); + } + else + { + CAMHAL_LOGDB("Saturation 0x%x configured successfully", + ( unsigned int ) saturation.nSaturation); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getSaturation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SATURATIONTYPE saturation; + + LOG_FUNCTION_NAME; + + if (OMX_StateInvalid == mComponentState) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&saturation, OMX_CONFIG_SATURATIONTYPE); + saturation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonSaturation, + &saturation); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while getting Saturation error = 0x%x", eError); + } else { + Gen3A.Saturation = saturation.nSaturation; + CAMHAL_LOGDB("Gen3A.Saturation 0x%x", Gen3A.Saturation); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setISO(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + OMX_TI_CONFIG_EXPOSUREVALUERIGHTTYPE expValRight; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + // In case of manual exposure Gain is applied from setManualExposureVal + if ( Gen3A.Exposure == OMX_ExposureControlOff ) { + return NO_ERROR; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + OMX_INIT_STRUCT_PTR (&expValRight, OMX_TI_CONFIG_EXPOSUREVALUERIGHTTYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + expValRight.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + + if ( OMX_ErrorNone == eError ) { + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigRightExposureValue, + &expValRight); + } + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("OMX_GetConfig error 0x%x (manual exposure values)", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + if( 0 == Gen3A.ISO ) { + expValues.bAutoSensitivity = OMX_TRUE; + } else { + expValues.bAutoSensitivity = OMX_FALSE; + expValues.nSensitivity = Gen3A.ISO; + expValRight.nSensitivity = expValues.nSensitivity; + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + + if ( OMX_ErrorNone == eError ) { + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigRightExposureValue, + &expValRight); + } + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring ISO 0x%x error = 0x%x", + ( unsigned int ) expValues.nSensitivity, + eError); + } else { + CAMHAL_LOGDB("ISO 0x%x configured successfully", + ( unsigned int ) expValues.nSensitivity); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::getISO(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + + LOG_FUNCTION_NAME; + + if (OMX_StateInvalid == mComponentState) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while getting ISO error = 0x%x", eError); + } else { + Gen3A.ISO = expValues.nSensitivity; + CAMHAL_LOGDB("Gen3A.ISO %d", Gen3A.ISO); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setEffect(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_IMAGEFILTERTYPE effect; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&effect, OMX_CONFIG_IMAGEFILTERTYPE); + effect.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + effect.eImageFilter = (OMX_IMAGEFILTERTYPE ) Gen3A.Effect; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonImageFilter, + &effect); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Effect 0x%x error = 0x%x", + ( unsigned int ) effect.eImageFilter, + eError); + } + else + { + CAMHAL_LOGDB("Effect 0x%x configured successfully", + ( unsigned int ) effect.eImageFilter); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setWhiteBalanceLock(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + lock.bLock = Gen3A.WhiteBalanceLock; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageWhiteBalanceLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring WhiteBalance Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDB("WhiteBalance Lock configured successfully %d ", lock.bLock); + } + LOG_FUNCTION_NAME_EXIT + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setExposureLock(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + lock.bLock = Gen3A.ExposureLock; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageExposureLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Exposure Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDB("Exposure Lock configured successfully %d ", lock.bLock); + } + LOG_FUNCTION_NAME_EXIT + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setFocusLock(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + lock.bLock = Gen3A.FocusLock; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageFocusLock, + &lock); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring Focus Lock error = 0x%x", eError); + } else { + CAMHAL_LOGDB("Focus Lock configured successfully %d ", lock.bLock); + } + + LOG_FUNCTION_NAME_EXIT + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::set3ALock(OMX_BOOL toggleExp, OMX_BOOL toggleWb, OMX_BOOL toggleFocus) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + mParameters3A.ExposureLock = toggleExp; + mParameters3A.FocusLock = toggleFocus; + mParameters3A.WhiteBalanceLock = toggleWb; + + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageExposureLock, + &lock); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error GetConfig Exposure Lock error = 0x%x", eError); + goto EXIT; + } + else + { + CAMHAL_LOGDA("Exposure Lock GetConfig successfull"); + + /* Apply locks only when not applied already */ + if ( lock.bLock != toggleExp ) + { + setExposureLock(mParameters3A); + } + + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageFocusLock, + &lock); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error GetConfig Focus Lock error = 0x%x", eError); + goto EXIT; + } + else + { + CAMHAL_LOGDB("Focus Lock GetConfig successfull bLock(%d)", lock.bLock); + + /* Apply locks only when not applied already */ + if ( lock.bLock != toggleFocus ) + { + setFocusLock(mParameters3A); + } + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageWhiteBalanceLock, + &lock); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error GetConfig WhiteBalance Lock error = 0x%x", eError); + goto EXIT; + } + else + { + CAMHAL_LOGDA("WhiteBalance Lock GetConfig successfull"); + + /* Apply locks only when not applied already */ + if ( lock.bLock != toggleWb ) + { + setWhiteBalanceLock(mParameters3A); + } + + } + EXIT: + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setMeteringAreas(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + CameraBuffer *bufferlist; + OMX_ALGOAREASTYPE *meteringAreas; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + int areasSize = 0; + + LOG_FUNCTION_NAME + + android::AutoMutex lock(mMeteringAreasLock); + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + areasSize = ((sizeof(OMX_ALGOAREASTYPE)+4095)/4096)*4096; + bufferlist = mMemMgr.allocateBufferList(0, 0, NULL, areasSize, 1); + meteringAreas = (OMX_ALGOAREASTYPE *)bufferlist[0].opaque; + + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + if (!meteringAreas) + { + CAMHAL_LOGEB("Error allocating buffer for metering areas %d", eError); + return -ENOMEM; + } + + OMX_INIT_STRUCT_PTR (meteringAreas, OMX_ALGOAREASTYPE); + + meteringAreas->nPortIndex = OMX_ALL; + meteringAreas->nNumAreas = mMeteringAreas.size(); + meteringAreas->nAlgoAreaPurpose = OMX_AlgoAreaExposure; + + for ( unsigned int n = 0; n < mMeteringAreas.size(); n++) + { + int widthDivisor = 1; + int heightDivisor = 1; + + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutTopBottom) { + heightDivisor = 2; + } + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutLeftRight) { + widthDivisor = 2; + } + + // transform the coordinates to 3A-type coordinates + mMeteringAreas.itemAt(n)->transfrom((size_t)mPreviewData->mWidth/widthDivisor, + (size_t)mPreviewData->mHeight/heightDivisor, + (size_t&)meteringAreas->tAlgoAreas[n].nTop, + (size_t&)meteringAreas->tAlgoAreas[n].nLeft, + (size_t&)meteringAreas->tAlgoAreas[n].nWidth, + (size_t&)meteringAreas->tAlgoAreas[n].nHeight); + + meteringAreas->tAlgoAreas[n].nLeft = + ( meteringAreas->tAlgoAreas[n].nLeft * METERING_AREAS_RANGE ) / mPreviewData->mWidth; + meteringAreas->tAlgoAreas[n].nTop = + ( meteringAreas->tAlgoAreas[n].nTop* METERING_AREAS_RANGE ) / mPreviewData->mHeight; + meteringAreas->tAlgoAreas[n].nWidth = + ( meteringAreas->tAlgoAreas[n].nWidth * METERING_AREAS_RANGE ) / mPreviewData->mWidth; + meteringAreas->tAlgoAreas[n].nHeight = + ( meteringAreas->tAlgoAreas[n].nHeight * METERING_AREAS_RANGE ) / mPreviewData->mHeight; + + meteringAreas->tAlgoAreas[n].nPriority = mMeteringAreas.itemAt(n)->getWeight(); + + CAMHAL_LOGDB("Metering area %d : top = %d left = %d width = %d height = %d prio = %d", + n, (int)meteringAreas->tAlgoAreas[n].nTop, (int)meteringAreas->tAlgoAreas[n].nLeft, + (int)meteringAreas->tAlgoAreas[n].nWidth, (int)meteringAreas->tAlgoAreas[n].nHeight, + (int)meteringAreas->tAlgoAreas[n].nPriority); + + } + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = areasSize; + sharedBuffer.pSharedBuff = (OMX_U8 *)camera_buffer_get_omx_ptr (&bufferlist[0]); + + if ( NULL == sharedBuffer.pSharedBuff ) + { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = -ENOMEM; + goto EXIT; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigAlgoAreas, &sharedBuffer); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting Focus Areas configuration 0x%x", eError); + ret = -EINVAL; + } + else + { + CAMHAL_LOGDA("Metering Areas SetConfig successfull."); + } + + EXIT: + if (NULL != bufferlist) + { + mMemMgr.freeBufferList(bufferlist); + } + + return ret; +} + +//TI extensions for enable/disable algos +status_t OMXCameraAdapter::setParameter3ABoolInvert(const OMX_INDEXTYPE omx_idx, + const OMX_BOOL data, const char *msg) +{ + OMX_BOOL inv_data; + + if (OMX_TRUE == data) + { + inv_data = OMX_FALSE; + } + else if (OMX_FALSE == data) + { + inv_data = OMX_TRUE; + } + else + { + return BAD_VALUE; + } + return setParameter3ABool(omx_idx, inv_data, msg); +} + +status_t OMXCameraAdapter::setParameter3ABool(const OMX_INDEXTYPE omx_idx, + const OMX_BOOL data, const char *msg) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE cfgdata; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&cfgdata, OMX_CONFIG_BOOLEANTYPE); + cfgdata.bEnabled = data; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + omx_idx, + &cfgdata); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring %s error = 0x%x", msg, eError); + } + else + { + CAMHAL_LOGDB("%s configured successfully %d ", msg, cfgdata.bEnabled); + } + + LOG_FUNCTION_NAME_EXIT + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +#ifndef MOTOROLA_CAMERA +status_t OMXCameraAdapter::setAlgoExternalGamma(Gen3A_settings& Gen3A) +{ + return setParameter3ABool((OMX_INDEXTYPE) OMX_TI_IndexConfigExternalGamma, Gen3A.AlgoExternalGamma, "External Gamma"); +} + +status_t OMXCameraAdapter::setAlgoNSF1(Gen3A_settings& Gen3A) +{ + return setParameter3ABoolInvert((OMX_INDEXTYPE) OMX_TI_IndexConfigDisableNSF1, Gen3A.AlgoNSF1, "NSF1"); +} + +status_t OMXCameraAdapter::setAlgoNSF2(Gen3A_settings& Gen3A) +{ + return setParameter3ABoolInvert((OMX_INDEXTYPE) OMX_TI_IndexConfigDisableNSF2, Gen3A.AlgoNSF2, "NSF2"); +} + +status_t OMXCameraAdapter::setAlgoSharpening(Gen3A_settings& Gen3A) +{ + return setParameter3ABoolInvert((OMX_INDEXTYPE) OMX_TI_IndexConfigDisableSharpening, Gen3A.AlgoSharpening, "Sharpening"); +} + +status_t OMXCameraAdapter::setAlgoThreeLinColorMap(Gen3A_settings& Gen3A) +{ + return setParameter3ABoolInvert((OMX_INDEXTYPE) OMX_TI_IndexConfigDisableThreeLinColorMap, Gen3A.AlgoThreeLinColorMap, "Color Conversion"); +} + +status_t OMXCameraAdapter::setAlgoGIC(Gen3A_settings& Gen3A) +{ + return setParameter3ABoolInvert((OMX_INDEXTYPE) OMX_TI_IndexConfigDisableGIC, Gen3A.AlgoGIC, "Green Inballance Correction"); +} + +status_t OMXCameraAdapter::setGammaTable(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + CameraBuffer *bufferlist = NULL; + OMX_TI_CONFIG_GAMMATABLE_TYPE *gammaTable = NULL; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + int tblSize = 0; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = NO_INIT; + goto EXIT; + } + + tblSize = ((sizeof(OMX_TI_CONFIG_GAMMATABLE_TYPE)+4095)/4096)*4096; + bufferlist = mMemMgr.allocateBufferList(0, 0, NULL, tblSize, 1); + if (NULL == bufferlist) { + CAMHAL_LOGEB("Error allocating buffer for gamma table"); + ret = NO_MEMORY; + goto EXIT; + } + gammaTable = (OMX_TI_CONFIG_GAMMATABLE_TYPE *)bufferlist[0].mapped; + if (NULL == gammaTable) { + CAMHAL_LOGEB("Error allocating buffer for gamma table (wrong data pointer)"); + ret = NO_MEMORY; + goto EXIT; + } + + memcpy(gammaTable, &mParameters3A.mGammaTable, sizeof(OMX_TI_CONFIG_GAMMATABLE_TYPE)); + +#ifdef CAMERAHAL_DEBUG + { + android::String8 DmpR; + android::String8 DmpG; + android::String8 DmpB; + for (unsigned int i=0; ipR[i].nOffset, (int)(int)gammaTable->pR[i].nSlope); + DmpG.appendFormat(" %d:%d;", (int)gammaTable->pG[i].nOffset, (int)(int)gammaTable->pG[i].nSlope); + DmpB.appendFormat(" %d:%d;", (int)gammaTable->pB[i].nOffset, (int)(int)gammaTable->pB[i].nSlope); + } + CAMHAL_LOGE("Gamma table R:%s", DmpR.string()); + CAMHAL_LOGE("Gamma table G:%s", DmpG.string()); + CAMHAL_LOGE("Gamma table B:%s", DmpB.string()); + } +#endif + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = sizeof(OMX_TI_CONFIG_GAMMATABLE_TYPE); + sharedBuffer.pSharedBuff = (OMX_U8 *)camera_buffer_get_omx_ptr (&bufferlist[0]); + if ( NULL == sharedBuffer.pSharedBuff ) { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = NO_MEMORY; + goto EXIT; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigGammaTable, &sharedBuffer); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while setting Gamma Table configuration 0x%x", eError); + ret = BAD_VALUE; + goto EXIT; + } else { + CAMHAL_LOGDA("Gamma Table SetConfig successfull."); + } + +EXIT: + + if (NULL != bufferlist) { + mMemMgr.freeBufferList(bufferlist); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} +#endif + +status_t OMXCameraAdapter::apply3Asettings( Gen3A_settings& Gen3A ) +{ + status_t ret = NO_ERROR; + unsigned int currSett; // 32 bit + int portIndex; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(m3ASettingsUpdateLock); + + /* + * Scenes have a priority during the process + * of applying 3A related parameters. + * They can override pretty much all other 3A + * settings and similarly get overridden when + * for instance the focus mode gets switched. + * There is only one exception to this rule, + * the manual a.k.a. auto scene. + */ + if (SetSceneMode & mPending3Asettings) { + mPending3Asettings &= ~SetSceneMode; + ret |= setScene(Gen3A); + // re-apply EV compensation after setting scene mode since it probably reset it + if(Gen3A.EVCompensation) { + setEVCompensation(Gen3A); + } + return ret; + } else if (OMX_Manual != Gen3A.SceneMode) { + // only certain settings are allowed when scene mode is set + mPending3Asettings &= (SetEVCompensation | SetFocus | SetWBLock | + SetExpLock | SetWhiteBallance | SetFlash); + if ( mPending3Asettings == 0 ) return NO_ERROR; + } + + for( currSett = 1; currSett < E3aSettingMax; currSett <<= 1) + { + if( currSett & mPending3Asettings ) + { + switch( currSett ) + { + case SetEVCompensation: + { + ret |= setEVCompensation(Gen3A); + break; + } + + case SetWhiteBallance: + { + ret |= setWBMode(Gen3A); + break; + } + + case SetFlicker: + { + ret |= setFlicker(Gen3A); + break; + } + + case SetBrightness: + { + ret |= setBrightness(Gen3A); + break; + } + + case SetContrast: + { + ret |= setContrast(Gen3A); + break; + } + + case SetSharpness: + { + ret |= setSharpness(Gen3A); + break; + } + + case SetSaturation: + { + ret |= setSaturation(Gen3A); + break; + } + + case SetISO: + { + ret |= setISO(Gen3A); + break; + } + + case SetEffect: + { + ret |= setEffect(Gen3A); + break; + } + + case SetFocus: + { + ret |= setFocusMode(Gen3A); + break; + } + + case SetExpMode: + { + ret |= setExposureMode(Gen3A); + break; + } + + case SetManualExposure: { + ret |= setManualExposureVal(Gen3A); + break; + } + + case SetFlash: + { + ret |= setFlashMode(Gen3A); + break; + } + + case SetExpLock: + { + ret |= setExposureLock(Gen3A); + break; + } + + case SetWBLock: + { + ret |= setWhiteBalanceLock(Gen3A); + break; + } + case SetMeteringAreas: + { + ret |= setMeteringAreas(Gen3A); + } + break; + +#ifndef MOTOROLA_CAMERA + //TI extensions for enable/disable algos + case SetAlgoExternalGamma: + { + ret |= setAlgoExternalGamma(Gen3A); + } + break; + + case SetAlgoNSF1: + { + ret |= setAlgoNSF1(Gen3A); + } + break; + + case SetAlgoNSF2: + { + ret |= setAlgoNSF2(Gen3A); + } + break; + + case SetAlgoSharpening: + { + ret |= setAlgoSharpening(Gen3A); + } + break; + + case SetAlgoThreeLinColorMap: + { + ret |= setAlgoThreeLinColorMap(Gen3A); + } + break; + + case SetAlgoGIC: + { + ret |= setAlgoGIC(Gen3A); + } + break; + + case SetGammaTable: + { + ret |= setGammaTable(Gen3A); + } + break; +#endif + + default: + CAMHAL_LOGEB("this setting (0x%x) is still not supported in CameraAdapter ", + currSett); + break; + } + mPending3Asettings &= ~currSett; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXAlgo.cpp b/camera/OMXCameraAdapter/OMXAlgo.cpp new file mode 100644 index 0000000..72ce1f6 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXAlgo.cpp @@ -0,0 +1,1355 @@ +/* + * 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. + */ + +/** +* @file OMXAlgo.cpp +* +* This file contains functionality for handling algorithm configurations. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +#undef TRUE + +namespace Ti { +namespace Camera { + +status_t OMXCameraAdapter::setParametersAlgo(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + const char *valManualStr = NULL; + const char *oldstr = NULL; + OMXCameraPortParameters *cap; + BrightnessMode gbce = BRIGHTNESS_OFF; + BrightnessMode glbce = BRIGHTNESS_OFF; + + LOG_FUNCTION_NAME; + + CaptureMode capMode; + CAMHAL_LOGDB("Capture mode %s", params.get(TICameraParameters::KEY_CAP_MODE)); + if ( (valstr = params.get(TICameraParameters::KEY_CAP_MODE)) != NULL ) { + if (strcmp(valstr, (const char *) TICameraParameters::HIGH_PERFORMANCE_MODE) == 0) { + capMode = OMXCameraAdapter::HIGH_SPEED; + mCapabilitiesOpMode = MODE_HIGH_SPEED; + } else if (strcmp(valstr, (const char *) TICameraParameters::EXPOSURE_BRACKETING) == 0) { + capMode = OMXCameraAdapter::HIGH_SPEED; + mCapabilitiesOpMode = MODE_HIGH_SPEED; + } else if (strcmp(valstr, (const char *) TICameraParameters::ZOOM_BRACKETING) == 0) { + capMode = OMXCameraAdapter::HIGH_SPEED; + mCapabilitiesOpMode = MODE_HIGH_SPEED; + } else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_MODE) == 0) { + capMode = OMXCameraAdapter::HIGH_QUALITY; + mCapabilitiesOpMode = MODE_HIGH_QUALITY; + } else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_ZSL_MODE) == 0) { + capMode = OMXCameraAdapter::HIGH_QUALITY_ZSL; + mCapabilitiesOpMode = MODE_ZEROSHUTTERLAG; + } else if (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) == 0) { + capMode = OMXCameraAdapter::VIDEO_MODE; + mCapabilitiesOpMode = MODE_VIDEO; + } else if (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE_HQ) == 0) { + capMode = OMXCameraAdapter::VIDEO_MODE_HQ; + mCapabilitiesOpMode = MODE_VIDEO_HIGH_QUALITY; + } else if (strcmp(valstr, (const char *) TICameraParameters::CP_CAM_MODE) == 0) { + capMode = OMXCameraAdapter::CP_CAM; + mCapabilitiesOpMode = MODE_CPCAM; + } else if (strcmp(valstr, (const char *) TICameraParameters::TEMP_BRACKETING) == 0) { + capMode = OMXCameraAdapter::HIGH_SPEED; + mCapabilitiesOpMode = MODE_HIGH_SPEED; + } else { + capMode = OMXCameraAdapter::HIGH_QUALITY; + mCapabilitiesOpMode = MODE_HIGH_QUALITY; + } + + } else { + capMode = OMXCameraAdapter::HIGH_QUALITY; + mCapabilitiesOpMode = MODE_HIGH_QUALITY; + } + + if ( mSensorIndex == 2 ) { + mCapabilitiesOpMode = MODE_STEREO; + } + + if ( mCapMode != capMode ) { + mCapMode = capMode; + mOMXStateSwitch = true; + mPendingPreviewSettings |= SetCapMode; + } + + CAMHAL_LOGDB("Capture Mode set %d", mCapMode); + + /// Configure IPP, LDCNSF, GBCE and GLBCE only in HQ mode + IPPMode ipp; + if((mCapMode == OMXCameraAdapter::HIGH_QUALITY) || (mCapMode == OMXCameraAdapter::HIGH_QUALITY_ZSL) + || (mCapMode == OMXCameraAdapter::VIDEO_MODE) + || (mCapMode == OMXCameraAdapter::CP_CAM)) + { + if ( (valstr = params.get(TICameraParameters::KEY_IPP)) != NULL ) + { + if (strcmp(valstr, (const char *) TICameraParameters::IPP_LDCNSF) == 0) + { + ipp = OMXCameraAdapter::IPP_LDCNSF; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_LDC) == 0) + { + ipp = OMXCameraAdapter::IPP_LDC; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_NSF) == 0) + { + ipp = OMXCameraAdapter::IPP_NSF; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_NONE) == 0) + { + ipp = OMXCameraAdapter::IPP_NONE; + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + + CAMHAL_LOGVB("IPP Mode set %d", ipp); + + if (((valstr = params.get(TICameraParameters::KEY_GBCE)) != NULL) ) { + if (strcmp(valstr, android::CameraParameters::TRUE ) == 0) { + gbce = BRIGHTNESS_ON; + } else { + gbce = BRIGHTNESS_OFF; + } + + if ( gbce != mGBCE ) { + mGBCE = gbce; + setGBCE(mGBCE); + } + + } else if(mFirstTimeInit) { + //Disable GBCE by default + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + + if ( ( valstr = params.get(TICameraParameters::KEY_GLBCE) ) != NULL ) { + + if (strcmp(valstr, android::CameraParameters::TRUE) == 0) { + glbce = BRIGHTNESS_ON; + } else { + glbce = BRIGHTNESS_OFF; + } + + if ( glbce != mGLBCE ) { + mGLBCE = glbce; + setGLBCE(mGLBCE); + } + + } else if(mFirstTimeInit) { + //Disable GLBCE by default + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + + } else { + ipp = OMXCameraAdapter::IPP_NONE; + } + + if ( mIPP != ipp ) + { + mIPP = ipp; + mOMXStateSwitch = true; + mPendingPreviewSettings |= SetLDC; + mPendingPreviewSettings |= SetNSF; + } + + ///Set VNF Configuration + bool vnfEnabled = false; + valstr = params.get(TICameraParameters::KEY_VNF); + if (valstr && strcmp(valstr, android::CameraParameters::TRUE) == 0) + { + CAMHAL_LOGDA("VNF Enabled"); + vnfEnabled = true; + } + else + { + CAMHAL_LOGDA("VNF Disabled"); + vnfEnabled = false; + } + + if ( mVnfEnabled != vnfEnabled ) + { + mVnfEnabled = vnfEnabled; + mOMXStateSwitch = true; + mPendingPreviewSettings |= SetVNF; + } + + ///Set VSTAB Configuration + bool vstabEnabled = false; + valstr = params.get(android::CameraParameters::KEY_VIDEO_STABILIZATION); + if (valstr && strcmp(valstr, android::CameraParameters::TRUE) == 0) { + CAMHAL_LOGDA("VSTAB Enabled"); + vstabEnabled = true; + } + else + { + CAMHAL_LOGDA("VSTAB Disabled"); + vstabEnabled = false; + } + + if ( mVstabEnabled != vstabEnabled ) + { + mVstabEnabled = vstabEnabled; + mOMXStateSwitch = true; + mPendingPreviewSettings |= SetVSTAB; + } + + //A work-around for a failing call to OMX flush buffers + if ( ( capMode = OMXCameraAdapter::VIDEO_MODE ) && + ( mVstabEnabled ) ) + { + mOMXStateSwitch = true; + } + +#ifdef OMAP_ENHANCEMENT + + //Set Auto Convergence Mode + valstr = params.get((const char *) TICameraParameters::KEY_AUTOCONVERGENCE_MODE); + valManualStr = params.get(TICameraParameters::KEY_MANUAL_CONVERGENCE); + + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + if (cap->mFrameLayoutType != OMX_TI_StereoFrameLayout2D) { + if ((valstr != NULL) || (valManualStr != NULL)) { + setAutoConvergence(valstr, valManualStr, params); + if (valstr != NULL) { + CAMHAL_LOGDB("AutoConvergenceMode %s", valstr); + } + if (valManualStr != NULL) { + CAMHAL_LOGDB("Manual Convergence %s", valManualStr); + } + } + + //Set Mechanical Misalignment Correction + valstr = params.get(TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION); + if ( valstr != NULL ) { + setMechanicalMisalignmentCorrection(strcmp(valstr, android::CameraParameters::TRUE) == 0); + CAMHAL_LOGDB("Mechanical Misalignment Correction %s", valstr); + } + } + +#endif + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Set AutoConvergence +status_t OMXCameraAdapter::setAutoConvergence(const char *pValstr, const char *pValManualstr, const android::CameraParameters ¶ms) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_CONVERGENCETYPE ACParams; + const char *str = NULL; + android::Vector > tempAreas; + int mode; + int changed = 0; + + LOG_FUNCTION_NAME; + + if ( pValManualstr != NULL ) { + OMX_S32 manualConvergence = (OMX_S32)strtol(pValManualstr ,0 ,0); + + if (mManualConv != manualConvergence) { + mManualConv = manualConvergence; + changed = 1; + } + } + + if ( pValstr != NULL ) { + mode = getLUTvalue_HALtoOMX(pValstr, mAutoConvergenceLUT); + + if ( NAME_NOT_FOUND == mode ) { + CAMHAL_LOGEB("Wrong convergence mode: %s", pValstr); + LOG_FUNCTION_NAME_EXIT; + return mode; + } + + if ( mAutoConv != static_cast (mode) ) { + mAutoConv = static_cast (mode); + changed = 1; + } + } + + if ( OMX_TI_AutoConvergenceModeFocusFaceTouch == mAutoConv ) { + android::AutoMutex lock(mTouchAreasLock); + + str = params.get(android::CameraParameters::KEY_METERING_AREAS); + + if ( NULL != str ) { + ret = CameraArea::parseAreas(str, ( strlen(str) + 1 ), tempAreas); + } else { + CAMHAL_LOGEB("Touch areas not received in %s", + android::CameraParameters::KEY_METERING_AREAS); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + if ( CameraArea::areAreasDifferent(mTouchAreas, tempAreas) ) { + mTouchAreas.clear(); + mTouchAreas = tempAreas; + changed = 1; + } + } + + if (!changed) { + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + OMXCameraPortParameters * mPreviewData; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + ACParams.nSize = (OMX_U32)sizeof(OMX_TI_CONFIG_CONVERGENCETYPE); + ACParams.nVersion = mLocalVersionParam; + ACParams.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutoConvergence, + &ACParams); + + ACParams.eACMode = mAutoConv; + ACParams.nManualConverence = mManualConv; + + if (1 == mTouchAreas.size()) { + int widthDivisor = 1; + int heightDivisor = 1; + + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutTopBottom) { + heightDivisor = 2; + } + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutLeftRight) { + widthDivisor = 2; + } + + // transform the coordinates to 3A-type coordinates + mTouchAreas.itemAt(0)->transfrom((size_t)mPreviewData->mWidth/widthDivisor, + (size_t)mPreviewData->mHeight/heightDivisor, + (size_t&) ACParams.nACProcWinStartY, + (size_t&) ACParams.nACProcWinStartX, + (size_t&) ACParams.nACProcWinWidth, + (size_t&) ACParams.nACProcWinHeight); + } + + CAMHAL_LOGDB("nSize %d", (int)ACParams.nSize); + CAMHAL_LOGDB("nPortIndex %d", (int)ACParams.nPortIndex); + CAMHAL_LOGDB("nManualConverence %d", (int)ACParams.nManualConverence); + CAMHAL_LOGDB("eACMode %d", (int)ACParams.eACMode); + CAMHAL_LOGDB("nACProcWinStartX %d", (int)ACParams.nACProcWinStartX); + CAMHAL_LOGDB("nACProcWinStartY %d", (int)ACParams.nACProcWinStartY); + CAMHAL_LOGDB("nACProcWinWidth %d", (int)ACParams.nACProcWinWidth); + CAMHAL_LOGDB("nACProcWinHeight %d", (int)ACParams.nACProcWinHeight); + CAMHAL_LOGDB("bACStatus %d", (int)ACParams.bACStatus); + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutoConvergence, + &ACParams); + + if ( eError != OMX_ErrorNone ) { + CAMHAL_LOGEB("Error while setting AutoConvergence 0x%x", eError); + ret = BAD_VALUE; + } else { + CAMHAL_LOGDA("AutoConvergence applied successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::enableVideoNoiseFilter(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_VIDEONOISEFILTERTYPE vnfCfg; + + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&vnfCfg, OMX_PARAM_VIDEONOISEFILTERTYPE); + + if ( enable ) + { + CAMHAL_LOGDA("VNF is enabled"); + vnfCfg.eMode = OMX_VideoNoiseFilterModeOn; + } + else + { + CAMHAL_LOGDA("VNF is disabled"); + vnfCfg.eMode = OMX_VideoNoiseFilterModeOff; + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamVideoNoiseFilter, + &vnfCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video noise filter 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video noise filter is configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::enableVideoStabilization(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_FRAMESTABTYPE frameStabCfg; + + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + OMX_CONFIG_BOOLEANTYPE vstabp; + OMX_INIT_STRUCT_PTR (&vstabp, OMX_CONFIG_BOOLEANTYPE); + if(enable) + { + vstabp.bEnabled = OMX_TRUE; + } + else + { + vstabp.bEnabled = OMX_FALSE; + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexParamFrameStabilisation, + &vstabp); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video stabilization param 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video stabilization param configured successfully"); + } + + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&frameStabCfg, OMX_CONFIG_FRAMESTABTYPE); + + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCommonFrameStabilisation, + &frameStabCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while getting video stabilization mode 0x%x", + (unsigned int)eError); + ret = -1; + } + + CAMHAL_LOGDB("VSTAB Port Index = %d", (int)frameStabCfg.nPortIndex); + + frameStabCfg.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + if ( enable ) + { + CAMHAL_LOGDA("VSTAB is enabled"); + frameStabCfg.bStab = OMX_TRUE; + } + else + { + CAMHAL_LOGDA("VSTAB is disabled"); + frameStabCfg.bStab = OMX_FALSE; + + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCommonFrameStabilisation, + &frameStabCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video stabilization mode 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video stabilization mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setGBCE(OMXCameraAdapter::BrightnessMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE bControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bControl, OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE); + + bControl.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::BRIGHTNESS_ON: + { + bControl.eControl = OMX_TI_BceModeOn; + break; + } + case OMXCameraAdapter::BRIGHTNESS_AUTO: + { + bControl.eControl = OMX_TI_BceModeAuto; + break; + } + case OMXCameraAdapter::BRIGHTNESS_OFF: + default: + { + bControl.eControl = OMX_TI_BceModeOff; + break; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigGlobalBrightnessContrastEnhance, + &bControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting GBCE 0x%x", eError); + } + else + { + CAMHAL_LOGDB("GBCE configured successfully 0x%x", mode); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setGLBCE(OMXCameraAdapter::BrightnessMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE bControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bControl, OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE); + bControl.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::BRIGHTNESS_ON: + { + bControl.eControl = OMX_TI_BceModeOn; + break; + } + case OMXCameraAdapter::BRIGHTNESS_AUTO: + { + bControl.eControl = OMX_TI_BceModeAuto; + break; + } + case OMXCameraAdapter::BRIGHTNESS_OFF: + default: + { + bControl.eControl = OMX_TI_BceModeOff; + break; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigLocalBrightnessContrastEnhance, + &bControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configure GLBCE 0x%x", eError); + } + else + { + CAMHAL_LOGDA("GLBCE configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setCaptureMode(OMXCameraAdapter::CaptureMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAMOPERATINGMODETYPE camMode; + OMX_CONFIG_BOOLEANTYPE bCAC; + OMX_TI_CONFIG_SINGLEPREVIEWMODETYPE singlePrevMode; + + LOG_FUNCTION_NAME; + + //CAC is disabled by default + OMX_INIT_STRUCT_PTR (&bCAC, OMX_CONFIG_BOOLEANTYPE); + OMX_INIT_STRUCT_PTR (&singlePrevMode, OMX_TI_CONFIG_SINGLEPREVIEWMODETYPE); + bCAC.bEnabled = OMX_FALSE; + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&camMode, OMX_CONFIG_CAMOPERATINGMODETYPE); + if ( mSensorIndex == OMX_TI_StereoSensor ) { + if ( OMXCameraAdapter::VIDEO_MODE == mode ) { + CAMHAL_LOGDA("Camera mode: STEREO VIDEO"); + camMode.eCamOperatingMode = OMX_TI_StereoVideo; + } else { + CAMHAL_LOGDA("Camera mode: STEREO"); + camMode.eCamOperatingMode = OMX_CaptureStereoImageCapture; + } + } else if ( OMXCameraAdapter::HIGH_SPEED == mode ) { + CAMHAL_LOGDA("Camera mode: HIGH SPEED"); + camMode.eCamOperatingMode = OMX_CaptureImageHighSpeedTemporalBracketing; + } else if ( OMXCameraAdapter::CP_CAM == mode ) { + CAMHAL_LOGDA("Camera mode: CP CAM"); + camMode.eCamOperatingMode = OMX_TI_CPCam; + // TODO(XXX): Hardcode for now until we implement re-proc pipe + singlePrevMode.eMode = OMX_TI_SinglePreviewMode_ImageCaptureHighSpeed; + } else if( OMXCameraAdapter::HIGH_QUALITY == mode ) { + CAMHAL_LOGDA("Camera mode: HIGH QUALITY"); + camMode.eCamOperatingMode = OMX_CaptureImageProfileBase; + } else if( OMXCameraAdapter::HIGH_QUALITY_ZSL== mode ) { + const char* valstr = NULL; + CAMHAL_LOGDA("Camera mode: HIGH QUALITY_ZSL"); + camMode.eCamOperatingMode = OMX_TI_CaptureImageProfileZeroShutterLag; + +#ifdef CAMERAHAL_TUNA + if ( !mIternalRecordingHint ) { + zslHistoryLen.nHistoryLen = 5; + } +#endif + + } else if( OMXCameraAdapter::VIDEO_MODE == mode ) { + CAMHAL_LOGDA("Camera mode: VIDEO MODE"); + camMode.eCamOperatingMode = OMX_CaptureVideo; + } else if( OMXCameraAdapter::VIDEO_MODE_HQ == mode ) { + CAMHAL_LOGDA("Camera mode: VIDEO MODE HQ"); + camMode.eCamOperatingMode = OMX_CaptureHighQualityVideo; + } else { + CAMHAL_LOGEA("Camera mode: INVALID mode passed!"); + return BAD_VALUE; + } + + if( NO_ERROR == ret ) + { + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexCameraOperatingMode, + &camMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring camera mode 0x%x", eError); + ret = Utils::ErrorUtils::omxToAndroidError(eError); + } + else + { + CAMHAL_LOGDA("Camera mode configured successfully"); + } + } + + if((NO_ERROR == ret) && (OMXCameraAdapter::CP_CAM == mode)) { + //Configure Single Preview Mode + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSinglePreviewMode, + &singlePrevMode); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring single preview mode 0x%x", eError); + ret = Utils::ErrorUtils::omxToAndroidError(eError); + } else { + CAMHAL_LOGDA("single preview mode configured successfully"); + } + } + + + if( NO_ERROR == ret ) + { + //Configure CAC + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigChromaticAberrationCorrection, + &bCAC); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring CAC 0x%x", eError); + ret = Utils::ErrorUtils::omxToAndroidError(eError); + } + else + { + CAMHAL_LOGDA("CAC configured successfully"); + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setLDC(OMXCameraAdapter::IPPMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in loaded state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + + switch ( mode ) + { + case OMXCameraAdapter::IPP_LDCNSF: + case OMXCameraAdapter::IPP_LDC: + { + bOMX.bEnabled = OMX_TRUE; + break; + } + case OMXCameraAdapter::IPP_NONE: + case OMXCameraAdapter::IPP_NSF: + default: + { + bOMX.bEnabled = OMX_FALSE; + break; + } + } + + CAMHAL_LOGVB("Configuring LDC mode 0x%x", bOMX.bEnabled); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamLensDistortionCorrection, + &bOMX); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEA("Error while setting LDC"); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setNSF(OMXCameraAdapter::IPPMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_ISONOISEFILTERTYPE nsf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in loaded state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&nsf, OMX_PARAM_ISONOISEFILTERTYPE); + nsf.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::IPP_LDCNSF: + case OMXCameraAdapter::IPP_NSF: + { + nsf.eMode = OMX_ISONoiseFilterModeOn; + break; + } + case OMXCameraAdapter::IPP_LDC: + case OMXCameraAdapter::IPP_NONE: + default: + { + nsf.eMode = OMX_ISONoiseFilterModeOff; + break; + } + } + + CAMHAL_LOGVB("Configuring NSF mode 0x%x", nsf.eMode); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexParamHighISONoiseFiler, + &nsf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEA("Error while setting NSF"); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setImageQuality(unsigned int quality) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_PARAM_QFACTORTYPE jpegQualityConf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(jpegQualityConf, OMX_IMAGE_PARAM_QFACTORTYPE); + jpegQualityConf.nQFactor = quality; + jpegQualityConf.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamQFactor, + &jpegQualityConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring jpeg Quality 0x%x", eError); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setThumbnailParams(unsigned int width, + unsigned int height, + unsigned int quality) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_THUMBNAILTYPE thumbConf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(thumbConf, OMX_PARAM_THUMBNAILTYPE); + thumbConf.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamThumbnail, + &thumbConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving thumbnail size 0x%x", eError); + ret = -1; + } + + //CTS Requirement: width or height equal to zero should + //result in absent EXIF thumbnail + if ( ( 0 == width ) || ( 0 == height ) ) + { + thumbConf.nWidth = mThumbRes[0].width; + thumbConf.nHeight = mThumbRes[0].height; + thumbConf.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + else + { + thumbConf.nWidth = width; + thumbConf.nHeight = height; + thumbConf.nQuality = quality; + thumbConf.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + + CAMHAL_LOGDB("Thumbnail width = %d, Thumbnail Height = %d", width, height); + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamThumbnail, + &thumbConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring thumbnail size 0x%x", eError); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setAlgoPriority(AlgoPriority priority, + Algorithm3A algo, + bool enable) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + if ( FACE_PRIORITY == priority ) { + + if ( algo & WHITE_BALANCE_ALGO ) { + if ( enable ) { + mFacePriority.bAwbFaceEnable = OMX_TRUE; + } else { + mFacePriority.bAwbFaceEnable = OMX_FALSE; + } + } + + if ( algo & EXPOSURE_ALGO ) { + if ( enable ) { + mFacePriority.bAeFaceEnable = OMX_TRUE; + } else { + mFacePriority.bAeFaceEnable = OMX_FALSE; + } + } + + if ( algo & FOCUS_ALGO ) { + if ( enable ) { + mFacePriority.bAfFaceEnable = OMX_TRUE; + } else { + mFacePriority.bAfFaceEnable = OMX_FALSE; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFacePriority3a, + &mFacePriority); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring face priority 0x%x", eError); + } else { + CAMHAL_LOGDB("Face priority for algorithms set successfully 0x%x, 0x%x, 0x%x", + mFacePriority.bAfFaceEnable, + mFacePriority.bAeFaceEnable, + mFacePriority.bAwbFaceEnable); + } + + } else if ( REGION_PRIORITY == priority ) { + + if ( algo & WHITE_BALANCE_ALGO ) { + if ( enable ) { + mRegionPriority.bAwbRegionEnable= OMX_TRUE; + } else { + mRegionPriority.bAwbRegionEnable = OMX_FALSE; + } + } + + if ( algo & EXPOSURE_ALGO ) { + if ( enable ) { + mRegionPriority.bAeRegionEnable = OMX_TRUE; + } else { + mRegionPriority.bAeRegionEnable = OMX_FALSE; + } + } + + if ( algo & FOCUS_ALGO ) { + if ( enable ) { + mRegionPriority.bAfRegionEnable = OMX_TRUE; + } else { + mRegionPriority.bAfRegionEnable = OMX_FALSE; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigRegionPriority3a, + &mRegionPriority); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring region priority 0x%x", eError); + } else { + CAMHAL_LOGDB("Region priority for algorithms set successfully 0x%x, 0x%x, 0x%x", + mRegionPriority.bAfRegionEnable, + mRegionPriority.bAeRegionEnable, + mRegionPriority.bAwbRegionEnable); + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setPictureRotation(unsigned int degree) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_ROTATIONTYPE rotation; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(rotation, OMX_CONFIG_ROTATIONTYPE); + rotation.nRotation = degree; + rotation.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &rotation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring rotation 0x%x", eError); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setSensorOrientation(unsigned int degree) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_ROTATIONTYPE sensorOrientation; + int tmpHeight, tmpWidth; + OMXCameraPortParameters *mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + LOG_FUNCTION_NAME; + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + /* Set Temproary Port resolution. + * For resolution with height >= 720, + * resolution cannot be set without configuring orientation. + * So we first set a temp resolution. We have used VGA + */ + if ( mPreviewData->mHeight >= 720 ) { + tmpHeight = mPreviewData->mHeight; + tmpWidth = mPreviewData->mWidth; + mPreviewData->mWidth = 640; + mPreviewData->mHeight = 480; + + ret = setFormat(OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, *mPreviewData); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error while configuring format 0x%x", ret); + return ret; + } + + mPreviewData->mWidth = tmpWidth; + mPreviewData->mHeight = tmpHeight; + mPreviewPortInitialized = true; + } + else if (!mPreviewPortInitialized) { + ret = setFormat(OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, *mPreviewData); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error while configuring format 0x%x", ret); + return ret; + } + mPreviewPortInitialized = true; + } + + /* Now set Required Orientation*/ + if ( NO_ERROR == ret ) { + OMX_INIT_STRUCT(sensorOrientation, OMX_CONFIG_ROTATIONTYPE); + sensorOrientation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + sensorOrientation.nRotation = degree; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring rotation 0x%x", eError); + } + CAMHAL_LOGVB(" Currently Sensor Orientation is set to : %d", + ( unsigned int ) sensorOrientation.nRotation); + CAMHAL_LOGVB(" Sensor Configured for Port : %d", + ( unsigned int ) sensorOrientation.nPortIndex); + } + + /* Now set the required resolution as requested */ + if ( NO_ERROR == ret ) { + bool portConfigured = false; + ret = setSensorQuirks(degree, + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex], + portConfigured); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error while configuring setSensorQuirks 0x%x", ret); + return ret; + } + + if ( !portConfigured ) { + ret = setFormat (mCameraAdapterParameters.mPrevPortIndex, + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error while configuring format 0x%x", ret); + return ret; + } + + // Another WA: Setting the port definition will reset the VFR + // configuration. + setVFramerate(mPreviewData->mMinFrameRate, + mPreviewData->mMaxFrameRate); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setVFramerate(OMX_U32 minFrameRate, OMX_U32 maxFrameRate) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_VARFRMRANGETYPE vfr; + OMXCameraPortParameters * mPreviewData = + &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( !mSetFormatDone ) { + return NO_INIT; + } + + if ( NO_ERROR == ret ) { + OMX_INIT_STRUCT_PTR (&vfr, OMX_TI_CONFIG_VARFRMRANGETYPE); + + vfr.xMin = minFrameRate<<16; + vfr.xMax = maxFrameRate<<16; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigVarFrmRange, + &vfr); + if(OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while setting VFR min = %d, max = %d, error = 0x%x", + ( unsigned int ) minFrameRate, + ( unsigned int ) maxFrameRate, + eError); + ret = -1; + } else { + CAMHAL_LOGDB("VFR Configured Successfully [%d:%d]", + ( unsigned int ) minFrameRate, + ( unsigned int ) maxFrameRate); + } + } + + return ret; + } + +status_t OMXCameraAdapter::setMechanicalMisalignmentCorrection(const bool enable) +{ + status_t ret = NO_ERROR; +#ifndef MOTOROLA_CAMERA + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_MM mm; + + LOG_FUNCTION_NAME; + + mm.nVersion = mLocalVersionParam; + mm.nSize = sizeof(OMX_TI_CONFIG_MM); + mm.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + mm.bMM = enable ? OMX_TRUE : OMX_FALSE; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigMechanicalMisalignment, + &mm); + + if(OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while enabling mechanical misalignment correction. error = 0x%x", eError); + ret = -1; + } + + LOG_FUNCTION_NAME_EXIT; +#endif + + return ret; +} + +#ifdef MOTOROLA_CAMERA +// This function is used when setting LedFlash Intensity +status_t OMXCameraAdapter::setLedFlash(int nLedFlashIntensP) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_LEDINTESITY LedIntensity; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&LedIntensity, OMX_CONFIG_LEDINTESITY); + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE) OMX_IndexConfigLedIntensity, &LedIntensity); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMXGetConfig() returned error 0x%x on index==%08x", eError, OMX_IndexConfigLedIntensity); + ret = -1; + } + if (NO_ERROR == ret) + { + CAMHAL_LOGEB("old LedIntensity.nLedFlashIntens is: %d ", LedIntensity.nLedFlashIntens); + + LedIntensity.nLedFlashIntens = (OMX_U32)nLedFlashIntensP; + CAMHAL_LOGDB("new LedIntensity.nLedFlashIntens is: %d ", LedIntensity.nLedFlashIntens); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE) OMX_IndexConfigLedIntensity, &LedIntensity); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring LedFlash Intensity. " + "OMXSetConfig() returned error 0x%x", eError); + ret = -1; + } + } + + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +// This function is used when setting LedTorch Intensity +status_t OMXCameraAdapter::setLedTorch(int nLedTorchIntensP) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_LEDINTESITY LedIntensity; + char value[PROPERTY_VALUE_MAX]; + unsigned int torchIntensity = DEFAULT_INTENSITY; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&LedIntensity, OMX_CONFIG_LEDINTESITY); + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE) OMX_IndexConfigLedIntensity, &LedIntensity); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMXGetConfig() returned error 0x%x", eError); + ret = -1; + } + if (NO_ERROR == ret) + { + CAMHAL_LOGEB("old LedIntensity.nLedTorchIntens is: %d ", LedIntensity.nLedTorchIntens); + + // read product specific torvh value + if (property_get("ro.media.capture.torchIntensity", value, 0) > 0) + { + torchIntensity = atoi(value); + if ((torchIntensity < 0) || (torchIntensity > DEFAULT_INTENSITY)) + { + torchIntensity = DEFAULT_INTENSITY; + } + } + else + { + torchIntensity = nLedTorchIntensP; + } + + LedIntensity.nLedTorchIntens = (OMX_U32)torchIntensity; + CAMHAL_LOGEB("new LedIntensity.nLedTorchIntens is: %d ", LedIntensity.nLedTorchIntens); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE) OMX_IndexConfigLedIntensity, &LedIntensity); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring LedTorch Intensity. " + "OMXSetConfig() returned error 0x%x", eError); + ret = -1; + } + } + + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} +#endif + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXCameraAdapter.cpp b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp new file mode 100644 index 0000000..a52654a --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp @@ -0,0 +1,4534 @@ +/* + * 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. + */ + +/** +* @file OMXCameraAdapter.cpp +* +* This file maps the Camera Hardware Interface to OMX. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#ifndef USES_LEGACY_DOMX_DCC +#include "OMXDCC.h" +#endif +#include "ErrorUtils.h" +#include "TICameraParameters.h" +#include +#include + +#include +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +static int mDebugFps = 0; +static int mDebugFcs = 0; + +#define HERE(Msg) {CAMHAL_LOGEB("--===line %d, %s===--\n", __LINE__, Msg);} + +namespace Ti { +namespace Camera { + +#ifdef CAMERAHAL_OMX_PROFILING + +const char OMXCameraAdapter::DEFAULT_PROFILE_PATH[] = "/data/dbg/profile_data.bin"; + +#endif + +//frames skipped before recalculating the framerate +#define FPS_PERIOD 30 + +android::Mutex gAdapterLock; +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +status_t OMXCameraAdapter::initialize(CameraProperties::Properties* caps) +{ + LOG_FUNCTION_NAME; + + char value[PROPERTY_VALUE_MAX]; + const char *mountOrientationString = NULL; + + property_get("debug.camera.showfps", value, "0"); + mDebugFps = atoi(value); + property_get("debug.camera.framecounts", value, "0"); + mDebugFcs = atoi(value); + +#ifdef CAMERAHAL_OMX_PROFILING + + property_get("debug.camera.profile", value, "0"); + mDebugProfile = atoi(value); + +#endif + + TIMM_OSAL_ERRORTYPE osalError = OMX_ErrorNone; + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + mLocalVersionParam.s.nVersionMajor = 0x1; + mLocalVersionParam.s.nVersionMinor = 0x1; + mLocalVersionParam.s.nRevision = 0x0 ; + mLocalVersionParam.s.nStep = 0x0; + + mPending3Asettings = 0;//E3AsettingsAll; + mPendingCaptureSettings = 0; + mPendingPreviewSettings = 0; + mPendingReprocessSettings = 0; + + ret = mMemMgr.initialize(); + if ( ret != OK ) { + CAMHAL_LOGE("MemoryManager initialization failed, error: %d", ret); + return ret; + } + + if ( 0 != mInitSem.Count() ) + { + CAMHAL_LOGEB("Error mInitSem semaphore count %d", mInitSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + ///Update the preview and image capture port indexes + mCameraAdapterParameters.mPrevPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW; + // temp changed in order to build OMX_CAMERA_PORT_VIDEO_OUT_IMAGE; + mCameraAdapterParameters.mImagePortIndex = OMX_CAMERA_PORT_IMAGE_OUT_IMAGE; + mCameraAdapterParameters.mMeasurementPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT; + //currently not supported use preview port instead + mCameraAdapterParameters.mVideoPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_VIDEO; + mCameraAdapterParameters.mVideoInPortIndex = OMX_CAMERA_PORT_VIDEO_IN_VIDEO; + + eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_Init() failed, error: 0x%x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + mOmxInitialized = true; + + // Initialize the callback handles + OMX_CALLBACKTYPE callbacks; + callbacks.EventHandler = Camera::OMXCameraAdapterEventHandler; + callbacks.EmptyBufferDone = Camera::OMXCameraAdapterEmptyBufferDone; + callbacks.FillBufferDone = Camera::OMXCameraAdapterFillBufferDone; + + ///Get the handle to the OMX Component + eError = OMXCameraAdapter::OMXCameraGetHandle(&mCameraAdapterParameters.mHandleComp, this, callbacks); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError); + } + GOTO_EXIT_IF((eError != OMX_ErrorNone), eError); + + mComponentState = OMX_StateLoaded; + + CAMHAL_LOGVB("OMX_GetHandle -0x%x sensor_index = %lu", eError, mSensorIndex); + initDccFileDataSave(&mCameraAdapterParameters.mHandleComp, mCameraAdapterParameters.mPrevPortIndex); + + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + OMX_ALL, + NULL); + + if(eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortDisable) -0x%x", eError); + } + GOTO_EXIT_IF((eError != OMX_ErrorNone), eError); + + // Register for port enable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mInitSem); + if(ret != NO_ERROR) { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + // Enable PREVIEW Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + // Wait for the port enable event to occur + ret = mInitSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("-Port enable event arrived"); + } else { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Timeout for enabling preview port expired!"); + goto EXIT; + } + + // Select the sensor + OMX_CONFIG_SENSORSELECTTYPE sensorSelect; + OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE); + sensorSelect.eSensor = (OMX_SENSORSELECT) mSensorIndex; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSensorSelect, &sensorSelect); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while selecting the sensor index as %d - 0x%x", mSensorIndex, eError); + return BAD_VALUE; + } else { + CAMHAL_LOGDB("Sensor %d selected successfully", mSensorIndex); + } + +#ifdef CAMERAHAL_DEBUG + + printComponentVersion(mCameraAdapterParameters.mHandleComp); + +#endif + + mBracketingEnabled = false; + mZoomBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mBracketingRange = 1; + mLastBracetingBufferIdx = 0; + mBracketingBuffersQueued = NULL; + mOMXStateSwitch = false; + mBracketingSet = false; +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + mRawCapture = false; + mYuvCapture = false; +#endif + + mCaptureSignalled = false; + mCaptureConfigured = false; + mReprocConfigured = false; + mRecording = false; + mWaitingForSnapshot = false; + mPictureFormatFromClient = NULL; + + mCapabilitiesOpMode = MODE_MAX; + mCapMode = INITIAL_MODE; + mIPP = IPP_NULL; + mVstabEnabled = false; + mVnfEnabled = false; + mBurstFrames = 1; + mFlushShotConfigQueue = false; + mPictureQuality = 100; + mCurrentZoomIdx = 0; + mTargetZoomIdx = 0; + mPreviousZoomIndx = 0; + mReturnZoomStatus = false; + mZoomInc = 1; + mZoomParameterIdx = 0; + mExposureBracketingValidEntries = 0; + mZoomBracketingValidEntries = 0; + mSensorOverclock = false; + mAutoConv = OMX_TI_AutoConvergenceModeMax; + mManualConv = 0; + +#ifdef CAMERAHAL_TUNA + mIternalRecordingHint = false; +#endif + + mDeviceOrientation = 0; + mFaceOrientation = 0; + mCapabilities = caps; + mZoomUpdating = false; + mZoomUpdate = false; + mGBCE = BRIGHTNESS_OFF; + mGLBCE = BRIGHTNESS_OFF; + mParameters3A.ExposureLock = OMX_FALSE; + mParameters3A.WhiteBalanceLock = OMX_FALSE; + + mEXIFData.mGPSData.mAltitudeValid = false; + mEXIFData.mGPSData.mDatestampValid = false; + mEXIFData.mGPSData.mLatValid = false; + mEXIFData.mGPSData.mLongValid = false; + mEXIFData.mGPSData.mMapDatumValid = false; + mEXIFData.mGPSData.mProcMethodValid = false; + mEXIFData.mGPSData.mVersionIdValid = false; + mEXIFData.mGPSData.mTimeStampValid = false; + mEXIFData.mModelValid = false; + mEXIFData.mMakeValid = false; + + mCapturedFrames = 0; + mBurstFramesAccum = 0; + mBurstFramesQueued = 0; + + //update the mDeviceOrientation with the sensor mount orientation. + //So that the face detect will work before onOrientationEvent() + //get triggered. + CAMHAL_ASSERT(mCapabilities); + mountOrientationString = mCapabilities->get(CameraProperties::ORIENTATION_INDEX); + CAMHAL_ASSERT(mountOrientationString); + mDeviceOrientation = atoi(mountOrientationString); + mFaceOrientation = atoi(mountOrientationString); + + if (mSensorIndex != 2) { + mCapabilities->setMode(MODE_HIGH_SPEED); + } + + if (mCapabilities->get(CameraProperties::SUPPORTED_ZOOM_STAGES) != NULL) { + mMaxZoomSupported = mCapabilities->getInt(CameraProperties::SUPPORTED_ZOOM_STAGES) + 1; + } else { + mMaxZoomSupported = 1; + } + + // initialize command handling thread + if(mCommandHandler.get() == NULL) + mCommandHandler = new CommandHandler(this); + + if ( NULL == mCommandHandler.get() ) + { + CAMHAL_LOGEA("Couldn't create command handler"); + return NO_MEMORY; + } + + ret = mCommandHandler->run("CallbackThread", android::PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + if( ret == INVALID_OPERATION){ + CAMHAL_LOGDA("command handler thread already runnning!!"); + ret = NO_ERROR; + } else { + CAMHAL_LOGEA("Couldn't run command handlerthread"); + return ret; + } + } + + // initialize omx callback handling thread + if(mOMXCallbackHandler.get() == NULL) + mOMXCallbackHandler = new OMXCallbackHandler(this); + + if ( NULL == mOMXCallbackHandler.get() ) + { + CAMHAL_LOGEA("Couldn't create omx callback handler"); + return NO_MEMORY; + } + + ret = mOMXCallbackHandler->run("OMXCallbackThread", android::PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + if( ret == INVALID_OPERATION){ + CAMHAL_LOGDA("omx callback handler thread already runnning!!"); + ret = NO_ERROR; + } else { + CAMHAL_LOGEA("Couldn't run omx callback handler thread"); + return ret; + } + } + + OMX_INIT_STRUCT_PTR (&mRegionPriority, OMX_TI_CONFIG_3A_REGION_PRIORITY); + OMX_INIT_STRUCT_PTR (&mFacePriority, OMX_TI_CONFIG_3A_FACE_PRIORITY); + mRegionPriority.nPortIndex = OMX_ALL; + mFacePriority.nPortIndex = OMX_ALL; + + //Setting this flag will that the first setParameter call will apply all 3A settings + //and will not conditionally apply based on current values. + mFirstTimeInit = true; + + //Flag to avoid calling setVFramerate() before OMX_SetParameter(OMX_IndexParamPortDefinition) + //Ducati will return an error otherwise. + mSetFormatDone = false; + + memset(mExposureBracketingValues, 0, EXP_BRACKET_RANGE*sizeof(int)); + memset(mZoomBracketingValues, 0, ZOOM_BRACKET_RANGE*sizeof(int)); + mMeasurementEnabled = false; + mFaceDetectionRunning = false; + mFaceDetectionPaused = false; + mFDSwitchAlgoPriority = false; + + metadataLastAnalogGain = -1; + metadataLastExposureTime = -1; + + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex], 0, sizeof(OMXCameraPortParameters)); + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex], 0, sizeof(OMXCameraPortParameters)); + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex], 0, sizeof(OMXCameraPortParameters)); + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex], 0, sizeof(OMXCameraPortParameters)); + + // initialize 3A defaults + mParameters3A.Effect = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EFFECT, EffLUT); + mParameters3A.FlashMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FLASH_MODE, FlashLUT); + mParameters3A.SceneMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_SCENE_MODE, SceneLUT); + mParameters3A.EVCompensation = atoi(OMXCameraAdapter::DEFAULT_EV_COMPENSATION); + mParameters3A.Focus = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FOCUS_MODE, FocusLUT); + mParameters3A.ISO = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ISO_MODE, IsoLUT); + mParameters3A.Flicker = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ANTIBANDING, FlickerLUT); + mParameters3A.Brightness = atoi(OMXCameraAdapter::DEFAULT_BRIGHTNESS); + mParameters3A.Saturation = atoi(OMXCameraAdapter::DEFAULT_SATURATION) - SATURATION_OFFSET; + mParameters3A.Sharpness = atoi(OMXCameraAdapter::DEFAULT_SHARPNESS) - SHARPNESS_OFFSET; + mParameters3A.Contrast = atoi(OMXCameraAdapter::DEFAULT_CONTRAST) - CONTRAST_OFFSET; + mParameters3A.WhiteBallance = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_WB, WBalLUT); + mParameters3A.Exposure = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EXPOSURE_MODE, ExpLUT); + mParameters3A.ExposureLock = OMX_FALSE; + mParameters3A.FocusLock = OMX_FALSE; + mParameters3A.WhiteBalanceLock = OMX_FALSE; + + mParameters3A.ManualExposure = 0; + mParameters3A.ManualExposureRight = 0; + mParameters3A.ManualGain = 0; + mParameters3A.ManualGainRight = 0; + + mParameters3A.AlgoExternalGamma = OMX_FALSE; + mParameters3A.AlgoNSF1 = OMX_TRUE; + mParameters3A.AlgoNSF2 = OMX_TRUE; + mParameters3A.AlgoSharpening = OMX_TRUE; + mParameters3A.AlgoThreeLinColorMap = OMX_TRUE; + mParameters3A.AlgoGIC = OMX_TRUE; + memset(&mParameters3A.mGammaTable, 0, sizeof(mParameters3A.mGammaTable)); + + LOG_FUNCTION_NAME_EXIT; + return Utils::ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGDB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +void OMXCameraAdapter::performCleanupAfterError() +{ + if(mCameraAdapterParameters.mHandleComp) + { + ///Free the OMX component handle in case of error + OMX_FreeHandle(mCameraAdapterParameters.mHandleComp); + mCameraAdapterParameters.mHandleComp = NULL; + } + + ///De-init the OMX + OMX_Deinit(); + mComponentState = OMX_StateInvalid; + mOmxInitialized = false; +} + +OMXCameraAdapter::OMXCameraPortParameters *OMXCameraAdapter::getPortParams(CameraFrame::FrameType frameType) +{ + OMXCameraAdapter::OMXCameraPortParameters *ret = NULL; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + break; + case CameraFrame::RAW_FRAME: +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + if (mRawCapture) { + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex]; + } else { +#endif + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + } +#endif + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + case CameraFrame::SNAPSHOT_FRAME: + case CameraFrame::VIDEO_FRAME_SYNC: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + break; + case CameraFrame::FRAME_DATA_SYNC: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + break; + default: + break; + }; + + return ret; +} + +status_t OMXCameraAdapter::fillThisBuffer(CameraBuffer * frameBuf, CameraFrame::FrameType frameType) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMXCameraPortParameters *port = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + bool isCaptureFrame = false; + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return NO_INIT; + } + + if ( NULL == frameBuf ) + { + return -EINVAL; + } + + isCaptureFrame = (CameraFrame::IMAGE_FRAME == frameType) || + (CameraFrame::RAW_FRAME == frameType); + + if ( NO_ERROR == ret ) + { + port = getPortParams(frameType); + if ( NULL == port ) + { + CAMHAL_LOGEB("Invalid frameType 0x%x", frameType); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) { + for ( int i = 0 ; i < port->mNumBufs ; i++) { + if ((CameraBuffer *) port->mBufferHeader[i]->pAppPrivate == frameBuf) { + if ( isCaptureFrame && !mBracketingEnabled ) { + android::AutoMutex lock(mBurstLock); + if ((1 > mCapturedFrames) && !mBracketingEnabled && (mCapMode != CP_CAM)) { + // Signal end of image capture + if ( NULL != mEndImageCaptureCallback) { + mEndImageCaptureCallback(mEndCaptureData); + } + port->mStatus[i] = OMXCameraPortParameters::IDLE; + return NO_ERROR; + } else if (mBurstFramesQueued >= mBurstFramesAccum) { + port->mStatus[i] = OMXCameraPortParameters::IDLE; + return NO_ERROR; + } + mBurstFramesQueued++; + } + port->mStatus[i] = OMXCameraPortParameters::FILL; + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, port->mBufferHeader[i]); + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGEB("OMX_FillThisBuffer 0x%x", eError); + goto EXIT; + } + mFramesWithDucati++; + break; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + return ret; + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + //Since fillthisbuffer is called asynchronously, make sure to signal error to the app + mErrorNotifier->errorNotify(CAMERA_ERROR_HARD); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +void OMXCameraAdapter::setParamS3D(OMX_U32 port, const char *valstr) +{ + OMXCameraPortParameters *cap; + + LOG_FUNCTION_NAME; + + cap = &mCameraAdapterParameters.mCameraPortParams[port]; + if (valstr != NULL) + { + if (strcmp(valstr, TICameraParameters::S3D_TB_FULL) == 0) + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayoutTopBottom; + } + else if (strcmp(valstr, TICameraParameters::S3D_SS_FULL) == 0) + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayoutLeftRight; + } + else if (strcmp(valstr, TICameraParameters::S3D_TB_SUBSAMPLED) == 0) + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayoutTopBottomSubsample; + } + else if (strcmp(valstr, TICameraParameters::S3D_SS_SUBSAMPLED) == 0) + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayoutLeftRightSubsample; + } + else + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayout2D; + } + } + else + { + cap->mFrameLayoutType = OMX_TI_StereoFrameLayout2D; + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OMXCameraAdapter::setParameters(const android::CameraParameters ¶ms) +{ + LOG_FUNCTION_NAME; + + int mode = 0; + status_t ret = NO_ERROR; + bool updateImagePortParams = false; + int minFramerate, maxFramerate, frameRate; + const char *valstr = NULL; + int w, h; + OMX_COLOR_FORMATTYPE pixFormat; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + ///@todo Include more camera parameters + if ( (valstr = params.getPreviewFormat()) != NULL ) { + if(strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV420P) == 0 || + strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420PackedSemiPlanar; + } else if(strcmp(valstr, android::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; + } + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + params.getPreviewSize(&w, &h); + frameRate = params.getPreviewFrameRate(); + + const char *frameRateRange = params.get(TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE); + bool fpsRangeParsed = CameraHal::parsePair(frameRateRange, &minFramerate, &maxFramerate, ','); + CAMHAL_ASSERT(fpsRangeParsed); + + minFramerate /= CameraHal::VFR_SCALE; + maxFramerate /= CameraHal::VFR_SCALE; + + frameRate = maxFramerate; + + if ( ( cap->mMinFrameRate != (OMX_U32) minFramerate ) || + ( cap->mMaxFrameRate != (OMX_U32) maxFramerate ) ) { + cap->mMinFrameRate = minFramerate; + cap->mMaxFrameRate = maxFramerate; + setVFramerate(cap->mMinFrameRate, cap->mMaxFrameRate); + } + + cap->mColorFormat = pixFormat; + cap->mWidth = w; + cap->mHeight = h; + cap->mFrameRate = frameRate; + + CAMHAL_LOGVB("Prev: cap.mColorFormat = %d", (int)cap->mColorFormat); + CAMHAL_LOGVB("Prev: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Prev: cap.mHeight = %d", (int)cap->mHeight); + CAMHAL_LOGVB("Prev: cap.mFrameRate = %d", (int)cap->mFrameRate); + + ///mStride is set from setBufs() while passing the APIs + cap->mStride = 4096; + cap->mBufSize = cap->mStride * cap->mHeight; + + + if ( ( cap->mWidth >= 1920 ) && + ( cap->mHeight >= 1080 ) && + ( cap->mFrameRate >= FRAME_RATE_FULL_HD ) && + ( !mSensorOverclock ) ) + { + mOMXStateSwitch = true; + } + else if ( ( ( cap->mWidth < 1920 ) || + ( cap->mHeight < 1080 ) || + ( cap->mFrameRate < FRAME_RATE_FULL_HD ) ) && + ( mSensorOverclock ) ) + { + mOMXStateSwitch = true; + } + +#ifdef CAMERAHAL_TUNA + valstr = params.get(TICameraParameters::KEY_RECORDING_HINT); + if (!valstr || (valstr && (strcmp(valstr, android::CameraParameters::FALSE)))) { + mIternalRecordingHint = false; + } else { + mIternalRecordingHint = true; + } +#endif + +#ifdef OMAP_ENHANCEMENT + if ( (valstr = params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)) != NULL ) + { + if (strcmp(valstr, android::CameraParameters::TRUE) == 0) + { + mMeasurementEnabled = true; + } + else if (strcmp(valstr, android::CameraParameters::FALSE) == 0) + { + mMeasurementEnabled = false; + } + else + { + mMeasurementEnabled = false; + } + } + else + { + //Disable measurement data by default + mMeasurementEnabled = false; + } +#endif + +#ifdef OMAP_ENHANCEMENT_S3D + setParamS3D(mCameraAdapterParameters.mPrevPortIndex, + params.get(TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT)); +#endif + + ret |= setParametersCapture(params, state); + + ret |= setParameters3A(params, state); + + ret |= setParametersAlgo(params, state); + + ret |= setParametersFocus(params, state); + + ret |= setParametersFD(params, state); + + ret |= setParametersZoom(params, state); + + ret |= setParametersEXIF(params, state); + +#ifdef MOTOROLA_CAMERA + CAMHAL_LOGDA("Start setting of Motorola specific parameters"); + if (NULL != params.get(TICameraParameters::KEY_MOT_LEDFLASH)) { + setLedFlash((unsigned int) (params.getInt(TICameraParameters::KEY_MOT_LEDFLASH))); + } + if (NULL != params.get(TICameraParameters::KEY_MOT_LEDTORCH)) { + setLedTorch((unsigned int) (params.getInt(TICameraParameters::KEY_MOT_LEDTORCH))); + } +#endif + + mParams = params; + mFirstTimeInit = false; + + if ( MODE_MAX != mCapabilitiesOpMode ) { + mCapabilities->setMode(mCapabilitiesOpMode); + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +void saveFile(unsigned char *buff, int width, int height, int format) { + static int counter = 1; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + + fn[0] = 0; + sprintf(fn, "/preview%03d.yuv", counter); + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + if(fd < 0) { + CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd)); + return; + } + + CAMHAL_LOGVB("Copying from 0x%x, size=%d x %d", buff, width, height); + + //method currently supports only nv12 dumping + int stride = width; + uint8_t *bf = (uint8_t*) buff; + for(int i=0;iget(CameraProperties::CAMERA_NAME), + (OMX_SCENEMODETYPE) mParameters3A.SceneMode); + if(entry) { + mParameters3A.Focus = entry->focus; + mParameters3A.FlashMode = entry->flash; + mParameters3A.WhiteBallance = entry->wb; + } + } + + valstr = getLUTvalue_OMXtoHAL(mParameters3A.WhiteBallance, WBalLUT); + valstr_supported = mParams.get(android::CameraParameters::KEY_SUPPORTED_WHITE_BALANCE); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(android::CameraParameters::KEY_WHITE_BALANCE , valstr); + + valstr = getLUTvalue_OMXtoHAL(mParameters3A.FlashMode, FlashLUT); + valstr_supported = mParams.get(android::CameraParameters::KEY_SUPPORTED_FLASH_MODES); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(android::CameraParameters::KEY_FLASH_MODE, valstr); + + if ((mParameters3A.Focus == OMX_IMAGE_FocusControlAuto) && + ( (mCapMode != OMXCameraAdapter::VIDEO_MODE) && + (mCapMode != OMXCameraAdapter::VIDEO_MODE_HQ) ) ) { + valstr = android::CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE; + } else { + valstr = getLUTvalue_OMXtoHAL(mParameters3A.Focus, FocusLUT); + } + valstr_supported = mParams.get(android::CameraParameters::KEY_SUPPORTED_FOCUS_MODES); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(android::CameraParameters::KEY_FOCUS_MODE, valstr); + } + + //Query focus distances only when focus is running + if ( ( AF_ACTIVE & state ) || + ( NULL == mParameters.get(android::CameraParameters::KEY_FOCUS_DISTANCES) ) ) + { + updateFocusDistances(params); + } + else + { + params.set(android::CameraParameters::KEY_FOCUS_DISTANCES, + mParameters.get(android::CameraParameters::KEY_FOCUS_DISTANCES)); + } + +#ifdef OMAP_ENHANCEMENT + OMX_INIT_STRUCT_PTR (&exp, OMX_CONFIG_EXPOSUREVALUETYPE); + exp.nPortIndex = OMX_ALL; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &exp); + if ( OMX_ErrorNone == eError ) + { + params.set(TICameraParameters::KEY_CURRENT_ISO, exp.nSensitivity); + } + else + { + CAMHAL_LOGEB("OMX error 0x%x, while retrieving current ISO value", eError); + } +#endif + + { + android::AutoMutex lock(mZoomLock); + //Immediate zoom should not be avaialable while smooth zoom is running + if ( ZOOM_ACTIVE & state ) + { + if ( mZoomParameterIdx != mCurrentZoomIdx ) + { + mZoomParameterIdx += mZoomInc; + } + params.set(android::CameraParameters::KEY_ZOOM, mZoomParameterIdx); + if ( ( mCurrentZoomIdx == mTargetZoomIdx ) && + ( mZoomParameterIdx == mCurrentZoomIdx ) ) + { + + if ( NO_ERROR == ret ) + { + + ret = BaseCameraAdapter::setState(CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + + } + + CAMHAL_LOGDB("CameraParameters Zoom = %d", mCurrentZoomIdx); + } + else + { + params.set(android::CameraParameters::KEY_ZOOM, mCurrentZoomIdx); + } + } + + //Populate current lock status + if ( mUserSetExpLock || mParameters3A.ExposureLock ) { + params.set(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK, + android::CameraParameters::TRUE); + } else { + params.set(android::CameraParameters::KEY_AUTO_EXPOSURE_LOCK, + android::CameraParameters::FALSE); + } + + if ( mUserSetWbLock || mParameters3A.WhiteBalanceLock ) { + params.set(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, + android::CameraParameters::TRUE); + } else { + params.set(android::CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, + android::CameraParameters::FALSE); + } + + // Update Picture size capabilities dynamically + params.set(android::CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + mCapabilities->get(CameraProperties::SUPPORTED_PICTURE_SIZES)); + + // Update framerate capabilities dynamically + params.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, + mCapabilities->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES)); + + params.set(TICameraParameters::KEY_FRAMERATES_EXT_SUPPORTED, + mCapabilities->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES_EXT)); + + params.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, + mCapabilities->get(CameraProperties::FRAMERATE_RANGE_SUPPORTED)); + + params.set(TICameraParameters::KEY_FRAMERATE_RANGES_EXT_SUPPORTED, + mCapabilities->get(CameraProperties::FRAMERATE_RANGE_EXT_SUPPORTED)); + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OMXCameraAdapter::setupTunnel(uint32_t SliceHeight, uint32_t EncoderHandle, uint32_t width, uint32_t height) { + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_HANDLETYPE *encoderHandle = (OMX_HANDLETYPE *)EncoderHandle; + + CAMHAL_LOGDB("\n %s: SliceHeight:%d, EncoderHandle:%d width:%d height:%d \n", __FUNCTION__, SliceHeight, EncoderHandle, width, height); + + if (SliceHeight == 0){ + CAMHAL_LOGEA("\n\n #### Encoder Slice Height Not received, Dont Setup Tunnel $$$$\n\n"); + return BAD_VALUE; + } + + if (encoderHandle == NULL) { + CAMHAL_LOGEA("Encoder Handle not set \n\n"); + return BAD_VALUE; + } + + if ( 0 != mInitSem.Count() ) { + CAMHAL_LOGEB("Error mInitSem semaphore count %d", mInitSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + // Register for port enable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoPortIndex, + mInitSem); + if(ret != NO_ERROR) { + CAMHAL_LOGEB("Error in registering for event %d", ret); + return UNKNOWN_ERROR; + } + + // Enable VIDEO Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoPortIndex, + NULL); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + return BAD_VALUE; + } + + // Wait for the port enable event to occur + ret = mInitSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("-Port enable event arrived"); + } else { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoPortIndex, + NULL); + CAMHAL_LOGEA("Timeout for enabling preview port expired!"); + return UNKNOWN_ERROR; + } + + //Set the Video Port Params + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + OMX_INIT_STRUCT_PTR (&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + portCheck.nPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_VIDEO; + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetParameter OMX_IndexParamPortDefinition Error - %x", eError); + } + + portCheck.format.video.nFrameWidth = width; + portCheck.format.video.nFrameHeight = height; + portCheck.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedSemiPlanar; + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter OMX_IndexParamPortDefinition Error- %x", eError); + } + +#ifndef MOTOROLA_CAMERA + //Slice Configuration + OMX_TI_PARAM_VTCSLICE VTCSlice; + OMX_INIT_STRUCT_PTR(&VTCSlice, OMX_TI_PARAM_VTCSLICE); + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_TI_IndexParamVtcSlice, &VTCSlice); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetParameter OMX_TI_IndexParamVtcSlice Error - %x", eError); + } + + VTCSlice.nSliceHeight = SliceHeight; + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_TI_IndexParamVtcSlice, &VTCSlice); + if (OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("OMX_SetParameter on OMX_TI_IndexParamVtcSlice returned error: 0x%x", eError); + return BAD_VALUE; + } + + eError = OMX_SetupTunnel(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mVideoPortIndex, encoderHandle, 0); + if (OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("OMX_SetupTunnel returned error: 0x%x", eError); + return BAD_VALUE; + } +#endif + + return NO_ERROR; +} + +status_t OMXCameraAdapter::setSensorQuirks(int orientation, + OMXCameraPortParameters &portParams, + bool &portConfigured) +{ + status_t overclockStatus = NO_ERROR; + int sensorID = -1; + size_t overclockWidth; + size_t overclockHeight; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + + LOG_FUNCTION_NAME; + + portConfigured = false; + OMX_INIT_STRUCT_PTR (&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + + portCheck.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetParameter (mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, + &portCheck); + + if ( eError != OMX_ErrorNone ) { + CAMHAL_LOGEB("OMX_GetParameter - %x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + if ( ( orientation == 90 ) || ( orientation == 270 ) ) { + overclockWidth = 1080; + overclockHeight = 1920; + } else { + overclockWidth = 1920; + overclockHeight = 1080; + } + + sensorID = mCapabilities->getInt(CameraProperties::CAMERA_SENSOR_ID); + if( ( ( sensorID == SENSORID_IMX060 ) && + ( portParams.mWidth >= overclockWidth ) && + ( portParams.mHeight >= overclockHeight ) && + ( portParams.mFrameRate >= FRAME_RATE_FULL_HD ) ) || + (( sensorID == SENSORID_OV14825) && + ( portParams.mFrameRate >= FRAME_RATE_HIGH_HD ))|| + ( ( sensorID == SENSORID_OV5640 ) && + ( portParams.mWidth >= overclockWidth ) && + ( portParams.mHeight >= overclockHeight ) ) ) { + overclockStatus = setSensorOverclock(true); + } else { + + //WA: If the next port resolution doesn't require + // sensor overclocking, but the previous resolution + // needed it, then we have to first set new port + // resolution and then disable sensor overclocking. + if( ( ( sensorID == SENSORID_IMX060 ) && + ( portCheck.format.video.nFrameWidth >= overclockWidth ) && + ( portCheck.format.video.nFrameHeight >= overclockHeight ) && + ( ( portCheck.format.video.xFramerate >> 16 ) >= FRAME_RATE_FULL_HD ) ) || + (( sensorID == SENSORID_OV14825) && + (( portCheck.format.video.xFramerate >> 16) >= FRAME_RATE_HIGH_HD ))|| + ( ( sensorID == SENSORID_OV5640 ) && + ( portCheck.format.video.nFrameWidth >= overclockWidth ) && + ( portCheck.format.video.nFrameHeight >= overclockHeight ) ) ) { + status_t ret = setFormat(mCameraAdapterParameters.mPrevPortIndex, + portParams); + if ( NO_ERROR != ret ) { + return ret; + } + + // Another WA: Setting the port definition will reset the VFR + // configuration. + setVFramerate(portParams.mMinFrameRate, portParams.mMaxFrameRate); + + portConfigured = true; + } + + overclockStatus = setSensorOverclock(false); + } + + LOG_FUNCTION_NAME_EXIT; + + return overclockStatus; +} +status_t OMXCameraAdapter::setFormat(OMX_U32 port, OMXCameraPortParameters &portParams) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + size_t bufferCount; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + + OMX_INIT_STRUCT_PTR (&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + + portCheck.nPortIndex = port; + + eError = OMX_GetParameter (mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + if (OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW == port) { + portCheck.format.video.nFrameWidth = portParams.mWidth; + portCheck.format.video.nFrameHeight = portParams.mHeight; + portCheck.format.video.eColorFormat = portParams.mColorFormat; + portCheck.format.video.nStride = portParams.mStride; + + portCheck.format.video.xFramerate = portParams.mFrameRate<<16; + portCheck.nBufferSize = portParams.mStride * portParams.mHeight; + portCheck.nBufferCountActual = portParams.mNumBufs; + mFocusThreshold = FOCUS_THRESHOLD * portParams.mFrameRate; + // Used for RAW capture + } else if (OMX_CAMERA_PORT_VIDEO_OUT_VIDEO == port) { + portCheck.format.video.nFrameWidth = portParams.mWidth; + portCheck.format.video.nFrameHeight = portParams.mHeight; + portCheck.format.video.eColorFormat = OMX_COLOR_FormatRawBayer10bit; // portParams.mColorFormat; + portCheck.nBufferCountActual = 1; // portParams.mNumBufs; + } else if (OMX_CAMERA_PORT_IMAGE_OUT_IMAGE == port) { + portCheck.format.image.nFrameWidth = portParams.mWidth; + portCheck.format.image.nFrameHeight = portParams.mHeight; + if (OMX_COLOR_FormatUnused == portParams.mColorFormat) { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + if (mCodingMode == CodingJPEG) { + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } else if (mCodingMode == CodingJPS) { + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingJPS; + } else if (mCodingMode == CodingMPO) { + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingMPO; + } else { + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + } else { + portCheck.format.image.eColorFormat = portParams.mColorFormat; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + // RAW + YUV Capture + if (mYuvCapture) { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; + } +#endif + //Stride for 1D tiler buffer is zero + portCheck.format.image.nStride = 0; + portCheck.nBufferCountActual = portParams.mNumBufs; + } else if (OMX_CAMERA_PORT_VIDEO_IN_VIDEO == port) { + portCheck.format.video.nFrameWidth = portParams.mWidth; + portCheck.format.video.nStride = portParams.mStride; + portCheck.format.video.nFrameHeight = portParams.mHeight; + portCheck.format.video.eColorFormat = portParams.mColorFormat; + portCheck.format.video.xFramerate = 30 << 16; + portCheck.nBufferCountActual = portParams.mNumBufs; + } else { + CAMHAL_LOGEB("Unsupported port index (%lu)", port); + } + + if (( mSensorIndex == OMX_TI_StereoSensor ) && (OMX_CAMERA_PORT_VIDEO_OUT_VIDEO != port)) { + ret = setS3DFrameLayout(port); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Error configuring stereo 3D frame layout"); + return ret; + } + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + /* check if parameters are set correctly by calling GetParameter() */ + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + portParams.mBufSize = portCheck.nBufferSize; + portParams.mStride = portCheck.format.image.nStride; + + if (OMX_CAMERA_PORT_IMAGE_OUT_IMAGE == port) { + CAMHAL_LOGDB("\n *** IMG Width = %ld", portCheck.format.image.nFrameWidth); + CAMHAL_LOGDB("\n *** IMG Height = %ld", portCheck.format.image.nFrameHeight); + + CAMHAL_LOGDB("\n *** IMG IMG FMT = %x", portCheck.format.image.eColorFormat); + CAMHAL_LOGDB("\n *** IMG portCheck.nBufferSize = %ld\n",portCheck.nBufferSize); + CAMHAL_LOGDB("\n *** IMG portCheck.nBufferCountMin = %ld\n", + portCheck.nBufferCountMin); + CAMHAL_LOGDB("\n *** IMG portCheck.nBufferCountActual = %ld\n", + portCheck.nBufferCountActual); + CAMHAL_LOGDB("\n *** IMG portCheck.format.image.nStride = %ld\n", + portCheck.format.image.nStride); + } else if (OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW == port) { + CAMHAL_LOGDB("\n *** PRV Width = %ld", portCheck.format.video.nFrameWidth); + CAMHAL_LOGDB("\n *** PRV Height = %ld", portCheck.format.video.nFrameHeight); + + CAMHAL_LOGDB("\n *** PRV IMG FMT = %x", portCheck.format.video.eColorFormat); + CAMHAL_LOGDB("\n *** PRV portCheck.nBufferSize = %ld\n",portCheck.nBufferSize); + CAMHAL_LOGDB("\n *** PRV portCheck.nBufferCountMin = %ld\n", + portCheck.nBufferCountMin); + CAMHAL_LOGDB("\n *** PRV portCheck.nBufferCountActual = %ld\n", + portCheck.nBufferCountActual); + CAMHAL_LOGDB("\n ***PRV portCheck.format.video.nStride = %ld\n", + portCheck.format.video.nStride); + } else { + CAMHAL_LOGDB("\n *** VID Width = %ld", portCheck.format.video.nFrameWidth); + CAMHAL_LOGDB("\n *** VID Height = %ld", portCheck.format.video.nFrameHeight); + + CAMHAL_LOGDB("\n *** VID IMG FMT = %x", portCheck.format.video.eColorFormat); + CAMHAL_LOGDB("\n *** VID portCheck.nBufferSize = %ld\n",portCheck.nBufferSize); + CAMHAL_LOGDB("\n *** VID portCheck.nBufferCountMin = %ld\n", + portCheck.nBufferCountMin); + CAMHAL_LOGDB("\n *** VID portCheck.nBufferCountActual = %ld\n", + portCheck.nBufferCountActual); + CAMHAL_LOGDB("\n *** VID portCheck.format.video.nStride = %ld\n", + portCheck.format.video.nStride); + } + + mSetFormatDone = true; + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of eError = 0x%x", __FUNCTION__, eError); + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::flushBuffers(OMX_U32 nPort) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + if ( 0 != mFlushSem.Count() ) + { + CAMHAL_LOGEB("Error mFlushSem semaphore count %d", mFlushSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[nPort]; + + ///Register for the FLUSH event + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandFlush, + nPort, + mFlushSem); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Send FLUSH command to preview port + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandFlush, + nPort, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandFlush)-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + CAMHAL_LOGDA("Waiting for flush event"); + + ///Wait for the FLUSH event to occur + ret = mFlushSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after Flush Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Flush event received"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandFlush, + nPort, + NULL); + CAMHAL_LOGDA("Flush event timeout expired"); + goto EXIT; + } + + mOMXCallbackHandler->flush(); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + + EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +///API to give the buffers to Adapter +status_t OMXCameraAdapter::useBuffers(CameraMode mode, CameraBuffer * bufArr, int num, size_t length, unsigned int queueable) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + switch(mode) + { + case CAMERA_PREVIEW: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_IMAGE_CAPTURE: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mMaxQueueable = queueable; + ret = UseBuffersCapture(bufArr, num); + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mNumBufs = num; + break; + + case CAMERA_VIDEO: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex].mMaxQueueable = queueable; + ret = UseBuffersRawCapture(bufArr, num); + break; + + case CAMERA_MEASUREMENT: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreviewData(bufArr, num); + break; + + case CAMERA_REPROCESS: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex].mMaxQueueable = queueable; + ret = UseBuffersReprocess(bufArr, num); + break; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::UseBuffersPreviewData(CameraBuffer * bufArr, int num) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * measurementData = NULL; + android::AutoMutex lock(mPreviewDataBufferLock); + + LOG_FUNCTION_NAME; + + if ( mComponentState != OMX_StateLoaded ) + { + CAMHAL_LOGEA("Calling UseBuffersPreviewData() when not in LOADED state"); + return BAD_VALUE; + } + + if ( NULL == bufArr ) + { + CAMHAL_LOGEA("NULL pointer passed for buffArr"); + return BAD_VALUE; + } + + if ( 0 != mUsePreviewDataSem.Count() ) + { + CAMHAL_LOGEB("Error mUsePreviewDataSem semaphore count %d", mUsePreviewDataSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + measurementData->mNumBufs = num ; + } + + if ( NO_ERROR == ret ) + { + ///Register for port enable event on measurement port + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + mUsePreviewDataSem); + + if ( ret == NO_ERROR ) + { + CAMHAL_LOGDB("Registering for event %d", ret); + } + else + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + } + + if ( NO_ERROR == ret ) + { + ///Enable MEASUREMENT Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + NULL); + + if ( eError == OMX_ErrorNone ) + { + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + } + else + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + goto EXIT; + } + } + + if ( NO_ERROR == ret ) + { + ret = mUsePreviewDataSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after measurement port enable Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Port enable event arrived on measurement port"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + NULL); + CAMHAL_LOGEA("Timeout expoired during port enable on measurement port"); + goto EXIT; + } + + CAMHAL_LOGDA("Port enable event arrived on measurement port"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::switchToExecuting() +{ + status_t ret = NO_ERROR; + Utils::Message msg; + + LOG_FUNCTION_NAME; + + mStateSwitchLock.lock(); + msg.command = CommandHandler::CAMERA_SWITCH_TO_EXECUTING; + msg.arg1 = mErrorNotifier; + ret = mCommandHandler->put(&msg); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doSwitchToExecuting() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + LOG_FUNCTION_NAME; + + if ( (mComponentState == OMX_StateExecuting) || (mComponentState == OMX_StateInvalid) ){ + CAMHAL_LOGDA("Already in OMX_Executing state or OMX_StateInvalid state"); + mStateSwitchLock.unlock(); + return NO_ERROR; + } + + if ( 0 != mSwitchToExecSem.Count() ){ + CAMHAL_LOGEB("Error mSwitchToExecSem semaphore count %d", mSwitchToExecSem.Count()); + goto EXIT; + } + + ///Register for Preview port DISABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + mSwitchToExecSem); + if ( NO_ERROR != ret ){ + CAMHAL_LOGEB("Error in registering Port Disable for event %d", ret); + goto EXIT; + } + ///Disable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + ret = mSwitchToExecSem.WaitTimeout(OMX_CMD_TIMEOUT); + if (ret != NO_ERROR){ + CAMHAL_LOGEB("Timeout PREVIEW PORT DISABLE %d", ret); + } + + CAMHAL_LOGVB("PREV PORT DISABLED %d", ret); + + ///Register for IDLE state switch event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + mSwitchToExecSem); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in IDLE STATE SWITCH %d", ret); + goto EXIT; + } + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp , + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + ret = mSwitchToExecSem.WaitTimeout(OMX_CMD_TIMEOUT); + if (ret != NO_ERROR){ + CAMHAL_LOGEB("Timeout IDLE STATE SWITCH %d", ret); + goto EXIT; + } + mComponentState = OMX_StateIdle; + CAMHAL_LOGVB("OMX_SendCommand(OMX_StateIdle) 0x%x", eError); + + ///Register for EXECUTING state switch event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateExecuting, + mSwitchToExecSem); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in EXECUTING STATE SWITCH %d", ret); + goto EXIT; + } + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp , + OMX_CommandStateSet, + OMX_StateExecuting, + NULL); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + ret = mSwitchToExecSem.WaitTimeout(OMX_CMD_TIMEOUT); + if (ret != NO_ERROR){ + CAMHAL_LOGEB("Timeout EXEC STATE SWITCH %d", ret); + goto EXIT; + } + mComponentState = OMX_StateExecuting; + CAMHAL_LOGVB("OMX_SendCommand(OMX_StateExecuting) 0x%x", eError); + + mStateSwitchLock.unlock(); + + LOG_FUNCTION_NAME_EXIT; + return ret; + + EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + mStateSwitchLock.unlock(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::switchToIdle() { + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mIdleStateSwitchLock); + + if ( mComponentState == OMX_StateIdle || mComponentState == OMX_StateLoaded || mComponentState == OMX_StateInvalid) { + CAMHAL_LOGDA("Already in OMX_StateIdle, OMX_Loaded state or OMX_StateInvalid state"); + return NO_ERROR; + } + + if ( 0 != mSwitchToLoadedSem.Count() ) + { + CAMHAL_LOGEB("Error mSwitchToLoadedSem semaphore count %d", mSwitchToLoadedSem.Count()); + goto EXIT; + } + + ///Register for EXECUTING state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + mSwitchToLoadedSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateIdle) - %x", eError); + } + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + ///Wait for the EXECUTING ->IDLE transition to arrive + + CAMHAL_LOGDA("EXECUTING->IDLE state changed"); + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after EXECUTING->IDLE Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("EXECUTING->IDLE state changed"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + CAMHAL_LOGEA("Timeout expired on EXECUTING->IDLE state change"); + goto EXIT; + } + + mComponentState = OMX_StateIdle; + + return NO_ERROR; + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + + + +status_t OMXCameraAdapter::prevPortEnable() { + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + ///Register for Preview port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mSwitchToLoadedSem); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Enable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandStateSet) 0x%x", eError); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + CAMHAL_LOGDA("Enabling Preview port"); + ///Wait for state to switch to idle + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after Enabling Preview port Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview port enabled!"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Preview enable timedout"); + + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::switchToLoaded(bool bPortEnableRequired) { + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mStateSwitchLock); + if ( mComponentState == OMX_StateLoaded || mComponentState == OMX_StateInvalid) { + CAMHAL_LOGDA("Already in OMX_Loaded state or OMX_StateInvalid state"); + return NO_ERROR; + } + + if ( mComponentState != OMX_StateIdle) { + ret = switchToIdle(); + if (ret != NO_ERROR) return ret; + } + + if ( 0 != mSwitchToLoadedSem.Count() ) { + CAMHAL_LOGEB("Error mSwitchToLoadedSem semaphore count %d", mSwitchToLoadedSem.Count()); + goto EXIT; + } + + ///Register for LOADED state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateLoaded, + mSwitchToLoadedSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateLoaded, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateLoaded) - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + if ( !bPortEnableRequired ) { + OMXCameraPortParameters *mCaptureData , *mPreviewData, *measurementData; + mCaptureData = mPreviewData = measurementData = NULL; + + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + mCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + + ///Free the OMX Buffers + for ( int i = 0 ; i < mPreviewData->mNumBufs ; i++ ) { + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mPrevPortIndex, + mPreviewData->mBufferHeader[i]); + + if(eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_FreeBuffer - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + if ( mMeasurementEnabled ) { + + for ( int i = 0 ; i < measurementData->mNumBufs ; i++ ) { + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mMeasurementPortIndex, + measurementData->mBufferHeader[i]); + if(eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_FreeBuffer - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + { + android::AutoMutex lock(mPreviewDataBufferLock); + mPreviewDataBuffersAvailable.clear(); + } + + } + } + + CAMHAL_LOGDA("Switching IDLE->LOADED state"); + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after IDLE->LOADED Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("IDLE->LOADED state changed"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateLoaded, + NULL); + CAMHAL_LOGEA("Timeout expired on IDLE->LOADED state change"); + goto EXIT; + } + + mComponentState = OMX_StateLoaded; + if (bPortEnableRequired == true) { + prevPortEnable(); + } + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + { + android::AutoMutex lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::UseBuffersPreview(CameraBuffer * bufArr, int num) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + int tmpHeight, tmpWidth; + + LOG_FUNCTION_NAME; + + if(!bufArr) + { + CAMHAL_LOGEA("NULL pointer passed for buffArr"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + OMXCameraPortParameters * mPreviewData = NULL; + OMXCameraPortParameters *measurementData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + mPreviewData->mNumBufs = num ; + + if ( 0 != mUsePreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mUsePreviewSem semaphore count %d", mUsePreviewSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if(mPreviewData->mNumBufs != num) + { + CAMHAL_LOGEA("Current number of buffers doesnt equal new num of buffers passed!"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + mStateSwitchLock.lock(); + + if ( mComponentState == OMX_StateLoaded ) { + + if (mPendingPreviewSettings & SetLDC) { + mPendingPreviewSettings &= ~SetLDC; + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setLDC() failed %d", ret); + } + } + + if (mPendingPreviewSettings & SetNSF) { + mPendingPreviewSettings &= ~SetNSF; + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setNSF() failed %d", ret); + } + } + + if (mPendingPreviewSettings & SetCapMode) { + mPendingPreviewSettings &= ~SetCapMode; + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + } + } + + if( (mCapMode == OMXCameraAdapter::VIDEO_MODE) || + (mCapMode == OMXCameraAdapter::VIDEO_MODE_HQ) ) { + + if (mPendingPreviewSettings & SetVNF) { + mPendingPreviewSettings &= ~SetVNF; + ret = enableVideoNoiseFilter(mVnfEnabled); + if ( NO_ERROR != ret){ + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + } + + if (mPendingPreviewSettings & SetVSTAB) { + mPendingPreviewSettings &= ~SetVSTAB; + ret = enableVideoStabilization(mVstabEnabled); + if ( NO_ERROR != ret) { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + } + } + + } + } + + ret = setSensorOrientation(mSensorOrientation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret); + mSensorOrientation = 0; + } + + if ( mComponentState == OMX_StateLoaded ) + { + ///Register for IDLE state switch event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + mUsePreviewSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Once we get the buffers, move component state to idle state and pass the buffers to OMX comp using UseBuffer + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp , + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandStateSet) 0x%x", eError); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + mComponentState = OMX_StateIdle; + } + else + { + ///Register for Preview port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mUsePreviewSem); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Enable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + } + + + ///Configure DOMX to use either gralloc handles or vptrs + OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles; + OMX_INIT_STRUCT_PTR (&domxUseGrallocHandles, OMX_TI_PARAMUSENATIVEBUFFER); + + domxUseGrallocHandles.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + domxUseGrallocHandles.bEnable = OMX_TRUE; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + OMX_BUFFERHEADERTYPE *pBufferHdr; + for(int index=0;indexmBufSize, + ptr); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_UseBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR)&bufArr[index]; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0 ; + pBufferHdr->nVersion.s.nStep = 0; + mPreviewData->mBufferHeader[index] = pBufferHdr; + } + + if ( mMeasurementEnabled ) + { + + for( int i = 0; i < num; i++ ) + { + OMX_BUFFERHEADERTYPE *pBufHdr; + OMX_U8 *ptr; + + ptr = (OMX_U8 *)camera_buffer_get_omx_ptr (&mPreviewDataBuffers[i]); + eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp, + &pBufHdr, + mCameraAdapterParameters.mMeasurementPortIndex, + 0, + measurementData->mBufSize, + ptr); + + if ( eError == OMX_ErrorNone ) + { + pBufHdr->pAppPrivate = (OMX_PTR *)&mPreviewDataBuffers[i]; + pBufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufHdr->nVersion.s.nVersionMajor = 1 ; + pBufHdr->nVersion.s.nVersionMinor = 1 ; + pBufHdr->nVersion.s.nRevision = 0 ; + pBufHdr->nVersion.s.nStep = 0; + measurementData->mBufferHeader[i] = pBufHdr; + } + else + { + CAMHAL_LOGEB("OMX_UseBuffer -0x%x", eError); + ret = BAD_VALUE; + break; + } + } + + } + + CAMHAL_LOGDA("Registering preview buffers"); + + ret = mUsePreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after Registering preview buffers Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview buffer registration successfull"); + } + else + { + if ( mComponentState == OMX_StateLoaded ) + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + } + CAMHAL_LOGEA("Timeout expired on preview buffer registration"); + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + + ///If there is any failure, we reach here. + ///Here, we do any resource freeing and convert from OMX error code to Camera Hal error code +EXIT: + mStateSwitchLock.unlock(); + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *mPreviewData = NULL; + OMXCameraPortParameters *measurementData = NULL; + + LOG_FUNCTION_NAME; + + if( 0 != mStartPreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mStartPreviewSem semaphore count %d", mStartPreviewSem.Count()); + ret = NO_INIT; + goto EXIT; + } + + // Enable all preview mode extra data. + if ( OMX_ErrorNone == eError) { + ret |= setExtraData(true, mCameraAdapterParameters.mPrevPortIndex, OMX_AncillaryData); +#ifdef OMAP_ENHANCEMENT_CPCAM + ret |= setExtraData(true, OMX_ALL, OMX_TI_VectShotInfo); +#endif +#ifdef CAMERAHAL_OMX_PROFILING + if ( UNLIKELY( mDebugProfile ) ) { + ret |= setExtraData(true, OMX_ALL, OMX_TI_ProfilerData); + } +#endif + } + + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + + if( OMX_StateIdle == mComponentState ) + { + ///Register for EXECUTING state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateExecuting, + mStartPreviewSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Switch to EXECUTING state + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateExecuting, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateExecuting)-0x%x", eError); + } + + CAMHAL_LOGDA("+Waiting for component to go into EXECUTING state"); + ret = mStartPreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after IDLE_EXECUTING Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("+Great. Component went into executing state!!"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateExecuting, + NULL); + CAMHAL_LOGDA("Timeout expired on executing state switch!"); + goto EXIT; + } + + mComponentState = OMX_StateExecuting; + + } + + mStateSwitchLock.unlock(); + + //Queue all the buffers on preview port + for(int index=0;index< mPreviewData->mMaxQueueable;index++) + { + CAMHAL_LOGDB("Queuing buffer on Preview port - 0x%x", (uint32_t)mPreviewData->mBufferHeader[index]->pBuffer); + mPreviewData->mStatus[index] = OMXCameraPortParameters::FILL; + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)mPreviewData->mBufferHeader[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError); + } + mFramesWithDucati++; +#ifdef CAMERAHAL_DEBUG + { + android::AutoMutex locker(mBuffersWithDucatiLock); + mBuffersWithDucati.add((int)mPreviewData->mBufferHeader[index]->pBuffer,1); + } +#endif + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + if ( mMeasurementEnabled ) + { + + for(int index=0;index< mPreviewData->mNumBufs;index++) + { + CAMHAL_LOGDB("Queuing buffer on Measurement port - 0x%x", (uint32_t) measurementData->mBufferHeader[index]->pBuffer); + measurementData->mStatus[index] = OMXCameraPortParameters::FILL; + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*) measurementData->mBufferHeader[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + } + + setFocusCallback(true); + + //reset frame rate estimates + mFPS = 0.0f; + mLastFPS = 0.0f; + // start frame count from 0. i.e first frame after + // startPreview will be the 0th reference frame + // this way we will wait for second frame until + // takePicture/autoFocus is allowed to run. we + // are seeing SetConfig/GetConfig fail after + // calling after the first frame and not failing + // after the second frame + mFrameCount = -1; + mLastFrameCount = 0; + mIter = 1; + mLastFPSTime = systemTime(); + mTunnelDestroyed = false; + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + mStateSwitchLock.unlock(); + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +} + +status_t OMXCameraAdapter::destroyTunnel() +{ + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + OMXCameraPortParameters *mCaptureData , *mPreviewData, *measurementData; + mCaptureData = mPreviewData = measurementData = NULL; + + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + mCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + + if (mAdapterState == LOADED_PREVIEW_STATE) { + // Something happened in CameraHal between UseBuffers and startPreview + // this means that state switch is still locked..so we need to unlock else + // deadlock will occur on the next start preview + mStateSwitchLock.unlock(); + return ALREADY_EXISTS; + } + + if ( mComponentState != OMX_StateExecuting ) + { + CAMHAL_LOGEA("Calling StopPreview() when not in EXECUTING state"); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + { + android::AutoMutex lock(mFrameCountMutex); + // we should wait for the first frame to come before trying to stopPreview...if not + // we might put OMXCamera in a bad state (IDLE->LOADED timeout). Seeing this a lot + // after a capture + if (mFrameCount < 1) { + // I want to wait for at least two frames.... + mFrameCount = -1; + + // first frame may time some time to come...so wait for an adequate amount of time + // which 2 * OMX_CAPTURE_TIMEOUT * 1000 will cover. + ret = mFirstFrameCondition.waitRelative(mFrameCountMutex, + (nsecs_t) 2 * OMX_CAPTURE_TIMEOUT * 1000); + } + // even if we timeout waiting for the first frame...go ahead with trying to stop preview + // signal anybody that might be waiting + mFrameCount = 0; + mFirstFrameCondition.broadcast(); + } + + { + android::AutoMutex lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + + OMX_CONFIG_FOCUSASSISTTYPE focusAssist; + OMX_INIT_STRUCT_PTR (&focusAssist, OMX_CONFIG_FOCUSASSISTTYPE); + focusAssist.nPortIndex = OMX_ALL; + focusAssist.bFocusAssist = OMX_FALSE; + CAMHAL_LOGDB("Configuring AF Assist mode 0x%x", focusAssist.bFocusAssist); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigFocusAssist, + &focusAssist); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring AF Assist mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera AF Assist mode configured successfully"); + } + + if ( 0 != mStopPreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mStopPreviewSem semaphore count %d", mStopPreviewSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + ret = disableImagePort(); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("disable image port failed 0x%x", ret); + goto EXIT; + } + + CAMHAL_LOGDB("Average framerate: %f", mFPS); + + //Avoid state switching of the OMX Component + ret = flushBuffers(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Flush Buffers failed 0x%x", ret); + goto EXIT; + } + + switchToIdle(); + + mTunnelDestroyed = true; + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + { + android::AutoMutex lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +} + +status_t OMXCameraAdapter::stopPreview() { + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + +#ifdef CAMERAHAL_OMX_PROFILING + ret |= setExtraData(false, OMX_ALL, OMX_TI_ProfilerData); +#endif + if (mTunnelDestroyed == false){ + ret = destroyTunnel(); + if (ret == ALREADY_EXISTS) { + // Special case to handle invalid stopping preview in LOADED_PREVIEW_STATE + return NO_ERROR; + } + if (ret != NO_ERROR) { + CAMHAL_LOGEB(" destroyTunnel returned error "); + return ret; + } + } + + mTunnelDestroyed = false; + + { + android::AutoMutex lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + + switchToLoaded(); + + mFirstTimeInit = true; + mPendingCaptureSettings = 0; + mPendingReprocessSettings = 0; + mFramesWithDucati = 0; + mFramesWithDisplay = 0; + mFramesWithEncoder = 0; + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::setSensorOverclock(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGDA("OMX component is not in loaded state"); + return ret; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + + if ( enable ) + { + bOMX.bEnabled = OMX_TRUE; + } + else + { + bOMX.bEnabled = OMX_FALSE; + } + + CAMHAL_LOGDB("Configuring Sensor overclock mode 0x%x", bOMX.bEnabled); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexParamSensorOverClockMode, &bOMX); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting Sensor overclock 0x%x", eError); + } + else + { + mSensorOverclock = enable; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::printComponentVersion(OMX_HANDLETYPE handle) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_VERSIONTYPE compVersion; + char compName[OMX_MAX_STRINGNAME_SIZE]; + char *currentUUID = NULL; + size_t offset = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == handle ) + { + CAMHAL_LOGEB("Invalid OMX Handle =0x%x", ( unsigned int ) handle); + ret = -EINVAL; + } + + mCompUUID[0] = 0; + + if ( NO_ERROR == ret ) + { + eError = OMX_GetComponentVersion(handle, + compName, + &compVersion, + &mCompRevision, + &mCompUUID + ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetComponentVersion returned 0x%x", eError); + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGVB("OMX Component name: [%s]", compName); + CAMHAL_LOGVB("OMX Component version: [%u]", ( unsigned int ) compVersion.nVersion); + CAMHAL_LOGVB("Spec version: [%u]", ( unsigned int ) mCompRevision.nVersion); + CAMHAL_LOGVB("Git Commit ID: [%s]", mCompUUID); + currentUUID = ( char * ) mCompUUID; + } + + if ( NULL != currentUUID ) + { + offset = strlen( ( const char * ) mCompUUID) + 1; + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Git Branch: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + offset = strlen( ( const char * ) currentUUID) + 1; + + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Build date and time: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + offset = strlen( ( const char * ) currentUUID) + 1; + + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Build description: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setS3DFrameLayout(OMX_U32 port) const +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_FRAMELAYOUTTYPE frameLayout; + const OMXCameraPortParameters *cap = + &mCameraAdapterParameters.mCameraPortParams[port]; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR (&frameLayout, OMX_TI_FRAMELAYOUTTYPE); + frameLayout.nPortIndex = port; + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexParamStereoFrmLayout, &frameLayout); + if (eError != OMX_ErrorNone) + { + CAMHAL_LOGEB("Error while getting S3D frame layout: 0x%x", eError); + return -EINVAL; + } + + if (cap->mFrameLayoutType == OMX_TI_StereoFrameLayoutTopBottomSubsample) + { + frameLayout.eFrameLayout = OMX_TI_StereoFrameLayoutTopBottom; + frameLayout.nSubsampleRatio = 2; + } + else if (cap->mFrameLayoutType == + OMX_TI_StereoFrameLayoutLeftRightSubsample) + { + frameLayout.eFrameLayout = OMX_TI_StereoFrameLayoutLeftRight; + frameLayout.nSubsampleRatio = 2; + } + else + { + frameLayout.eFrameLayout = cap->mFrameLayoutType; + frameLayout.nSubsampleRatio = 1; + } + frameLayout.nSubsampleRatio = frameLayout.nSubsampleRatio << 7; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexParamStereoFrmLayout, &frameLayout); + if (eError != OMX_ErrorNone) + { + CAMHAL_LOGEB("Error while setting S3D frame layout: 0x%x", eError); + return -EINVAL; + } + else + { + CAMHAL_LOGDB("S3D frame layout %d applied successfully on port %lu", + frameLayout.eFrameLayout, port); + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t OMXCameraAdapter::autoFocus() +{ + status_t ret = NO_ERROR; + Utils::Message msg; + + LOG_FUNCTION_NAME; + + { + android::AutoMutex lock(mFrameCountMutex); + if (mFrameCount < 1) { + // first frame may time some time to come...so wait for an adequate amount of time + // which 2 * OMX_CAPTURE_TIMEOUT * 1000 will cover. + ret = mFirstFrameCondition.waitRelative(mFrameCountMutex, + (nsecs_t) 2 * OMX_CAPTURE_TIMEOUT * 1000); + if ((NO_ERROR != ret) || (mFrameCount == 0)) { + goto EXIT; + } + } + } + + msg.command = CommandHandler::CAMERA_PERFORM_AUTOFOCUS; + msg.arg1 = mErrorNotifier; + ret = mCommandHandler->put(&msg); + + EXIT: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::takePicture() +{ + status_t ret = NO_ERROR; + Utils::Message msg; + + LOG_FUNCTION_NAME; + + if (mNextState != REPROCESS_STATE) { + android::AutoMutex lock(mFrameCountMutex); + if (mFrameCount < 1) { + // first frame may time some time to come...so wait for an adequate amount of time + // which 2 * OMX_CAPTURE_TIMEOUT * 1000 will cover. + ret = mFirstFrameCondition.waitRelative(mFrameCountMutex, + (nsecs_t) 2 * OMX_CAPTURE_TIMEOUT * 1000); + if ((NO_ERROR != ret) || (mFrameCount == 0)) { + goto EXIT; + } + } + } + + // TODO(XXX): re-using take picture to kick off reprocessing pipe + // Need to rethink this approach during reimplementation + if (mNextState == REPROCESS_STATE) { + msg.command = CommandHandler::CAMERA_START_REPROCESS; + } else { + msg.command = CommandHandler::CAMERA_START_IMAGE_CAPTURE; + } + + msg.arg1 = mErrorNotifier; + msg.arg2 = cacheCaptureParameters(); + ret = mCommandHandler->put(&msg); + + EXIT: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startVideoCapture() +{ + return BaseCameraAdapter::startVideoCapture(); +} + +status_t OMXCameraAdapter::stopVideoCapture() +{ + return BaseCameraAdapter::stopVideoCapture(); +} + +//API to get the frame size required to be allocated. This size is used to override the size passed +//by camera service when VSTAB/VNF is turned ON for example +status_t OMXCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_RECTTYPE tFrameDim; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR (&tFrameDim, OMX_CONFIG_RECTTYPE); + tFrameDim.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + if ( mOMXStateSwitch ) + { + ret = switchToLoaded(true); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("switchToLoaded() failed 0x%x", ret); + goto exit; + } + + mOMXStateSwitch = false; + } + + if ( OMX_StateLoaded == mComponentState ) + { + + if (mPendingPreviewSettings & SetLDC) { + mPendingPreviewSettings &= ~SetLDC; + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setLDC() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + } + + if (mPendingPreviewSettings & SetNSF) { + mPendingPreviewSettings &= ~SetNSF; + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setNSF() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + } + + if (mPendingPreviewSettings & SetCapMode) { + mPendingPreviewSettings &= ~SetCapMode; + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + } + } + + if((mCapMode == OMXCameraAdapter::VIDEO_MODE) || + (mCapMode == OMXCameraAdapter::VIDEO_MODE_HQ) ) { + + if (mPendingPreviewSettings & SetVNF) { + mPendingPreviewSettings &= ~SetVNF; + ret = enableVideoNoiseFilter(mVnfEnabled); + if ( NO_ERROR != ret){ + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + } + + if (mPendingPreviewSettings & SetVSTAB) { + mPendingPreviewSettings &= ~SetVSTAB; + ret = enableVideoStabilization(mVstabEnabled); + if ( NO_ERROR != ret) { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + } + } + + } + } + + ret = setSensorOrientation(mSensorOrientation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret); + mSensorOrientation = 0; + } + + if ( NO_ERROR == ret ) + { + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexParam2DBufferAllocDimension, &tFrameDim); + if ( OMX_ErrorNone == eError) + { + width = tFrameDim.nWidth; + height = tFrameDim.nHeight; + } + } + +exit: + + CAMHAL_LOGDB("Required frame size %dx%d", width, height); + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + status_t ret = NO_ERROR; + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("Calling getFrameDataSize() when not in LOADED state"); + dataFrameSize = 0; + ret = BAD_VALUE; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR(&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + portCheck.nPortIndex = mCameraAdapterParameters.mMeasurementPortIndex; + + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + dataFrameSize = 0; + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + portCheck.nBufferCountActual = bufferCount; + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_SetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + dataFrameSize = 0; + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + ret = BAD_VALUE; + } + else + { + mCameraAdapterParameters.mCameraPortParams[portCheck.nPortIndex].mBufSize = portCheck.nBufferSize; + dataFrameSize = portCheck.nBufferSize; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void OMXCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + + static const unsigned int DEGREES_TILT_IGNORE = 45; + + // if tilt angle is greater than DEGREES_TILT_IGNORE + // we are going to ignore the orientation returned from + // sensor. the orientation returned from sensor is not + // reliable. Value of DEGREES_TILT_IGNORE may need adjusting + if (tilt > DEGREES_TILT_IGNORE) { + return; + } + + int mountOrientation = 0; + bool isFront = false; + if (mCapabilities) { + const char * const mountOrientationString = + mCapabilities->get(CameraProperties::ORIENTATION_INDEX); + if (mountOrientationString) { + mountOrientation = atoi(mountOrientationString); + } + + const char * const facingString = mCapabilities->get(CameraProperties::FACING_INDEX); + if (facingString) { + isFront = strcmp(facingString, TICameraParameters::FACING_FRONT) == 0; + } + } + + // direction is a constant sign for facing, meaning the rotation direction relative to device + // +1 (clockwise) for back sensor and -1 (counter-clockwise) for front sensor + const int direction = isFront ? -1 : 1; + + int rotation = mountOrientation + direction*orientation; + + // crop the calculated value to [0..360) range + while ( rotation < 0 ) rotation += 360; + rotation %= 360; + + if (rotation != mDeviceOrientation) { + mDeviceOrientation = rotation; + + // restart face detection with new rotation + setFaceDetectionOrientation(mDeviceOrientation); + } + CAMHAL_LOGVB("orientation = %d tilt = %d device_orientation = %d", orientation, tilt, mDeviceOrientation); + + LOG_FUNCTION_NAME_EXIT; +} + +/* Application callback Functions */ +/*========================================================*/ +/* @ fn SampleTest_EventHandler :: Application callback */ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + LOG_FUNCTION_NAME; + + CAMHAL_LOGDB("Event %d", eEvent); + + OMX_ERRORTYPE ret = OMX_ErrorNone; + OMXCameraAdapter *oca = (OMXCameraAdapter*)pAppData; + ret = oca->OMXCameraAdapterEventHandler(hComponent, eEvent, nData1, nData2, pEventData); + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +/* Application callback Functions */ +/*========================================================*/ +/* @ fn SampleTest_EventHandler :: Application callback */ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + CAMHAL_LOGDB("+OMX_Event %x, %d %d", eEvent, (int)nData1, (int)nData2); + + switch (eEvent) { + case OMX_EventCmdComplete: + CAMHAL_LOGDB("+OMX_EventCmdComplete %d %d", (int)nData1, (int)nData2); + + if (OMX_CommandStateSet == nData1) { + mCameraAdapterParameters.mState = (OMX_STATETYPE) nData2; + + } else if (OMX_CommandFlush == nData1) { + CAMHAL_LOGDB("OMX_CommandFlush received for port %d", (int)nData2); + + } else if (OMX_CommandPortDisable == nData1) { + CAMHAL_LOGDB("OMX_CommandPortDisable received for port %d", (int)nData2); + + } else if (OMX_CommandPortEnable == nData1) { + CAMHAL_LOGDB("OMX_CommandPortEnable received for port %d", (int)nData2); + + } else if (OMX_CommandMarkBuffer == nData1) { + ///This is not used currently + } + + CAMHAL_LOGDA("-OMX_EventCmdComplete"); + break; + + case OMX_EventIndexSettingChanged: + CAMHAL_LOGDB("OMX_EventIndexSettingChanged event received data1 0x%x, data2 0x%x", + ( unsigned int ) nData1, ( unsigned int ) nData2); + break; + + case OMX_EventError: + CAMHAL_LOGDB("OMX interface failed to execute OMX command %d", (int)nData1); + CAMHAL_LOGDA("See OMX_INDEXTYPE for reference"); + if ( NULL != mErrorNotifier && ( ( OMX_U32 ) OMX_ErrorHardware == nData1 ) && mComponentState != OMX_StateInvalid) + { + CAMHAL_LOGEA("***Got Fatal Error Notification***\n"); + mComponentState = OMX_StateInvalid; + /* + Remove any unhandled events and + unblock any waiting semaphores + */ + if ( !mEventSignalQ.isEmpty() ) + { + for (unsigned int i = 0 ; i < mEventSignalQ.size(); i++ ) + { + CAMHAL_LOGEB("***Removing %d EVENTS***** \n", mEventSignalQ.size()); + //remove from queue and free msg + Utils::Message *msg = mEventSignalQ.itemAt(i); + if ( NULL != msg ) + { + Utils::Semaphore *sem = (Utils::Semaphore*) msg->arg3; + if ( sem ) + { + sem->Signal(); + } + free(msg); + } + } + mEventSignalQ.clear(); + } + ///Report Error to App + mErrorNotifier->errorNotify(CAMERA_ERROR_FATAL); + } + break; + + case OMX_EventMark: + break; + + case OMX_EventPortSettingsChanged: + break; + + case OMX_EventBufferFlag: + break; + + case OMX_EventResourcesAcquired: + break; + + case OMX_EventComponentResumed: + break; + + case OMX_EventDynamicResourcesAvailable: + break; + + case OMX_EventPortFormatDetected: + break; + + default: + break; + } + + ///Signal to the thread(s) waiting that the event has occured + SignalEvent(hComponent, eEvent, nData1, nData2, pEventData); + + LOG_FUNCTION_NAME_EXIT; + return eError; + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of eError=%x", __FUNCTION__, eError); + LOG_FUNCTION_NAME_EXIT; + return eError; +} + +OMX_ERRORTYPE OMXCameraAdapter::SignalEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + android::AutoMutex lock(mEventLock); + Utils::Message *msg; + bool eventSignalled = false; + + LOG_FUNCTION_NAME; + + if ( !mEventSignalQ.isEmpty() ) + { + CAMHAL_LOGDA("Event queue not empty"); + + for ( unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ ) + { + msg = mEventSignalQ.itemAt(i); + if ( NULL != msg ) + { + if( ( msg->command != 0 || msg->command == ( unsigned int ) ( eEvent ) ) + && ( !msg->arg1 || ( OMX_U32 ) msg->arg1 == nData1 ) + && ( !msg->arg2 || ( OMX_U32 ) msg->arg2 == nData2 ) + && msg->arg3) + { + Utils::Semaphore *sem = (Utils::Semaphore*) msg->arg3; + CAMHAL_LOGDA("Event matched, signalling sem"); + mEventSignalQ.removeAt(i); + //Signal the semaphore provided + sem->Signal(); + free(msg); + eventSignalled = true; + break; + } + } + } + } + else + { + CAMHAL_LOGDA("Event queue empty!!!"); + } + + // Special handling for any unregistered events + if (!eventSignalled) { + // Handling for focus callback + if ((nData2 == OMX_IndexConfigCommonFocusStatus) && + (eEvent == (OMX_EVENTTYPE) OMX_EventIndexSettingChanged)) { + Utils::Message msg; + msg.command = OMXCallbackHandler::CAMERA_FOCUS_STATUS; + msg.arg1 = NULL; + msg.arg2 = NULL; + mOMXCallbackHandler->put(&msg); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OMXCameraAdapter::RemoveEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + android::AutoMutex lock(mEventLock); + Utils::Message *msg; + LOG_FUNCTION_NAME; + + if ( !mEventSignalQ.isEmpty() ) + { + CAMHAL_LOGDA("Event queue not empty"); + + for ( unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ ) + { + msg = mEventSignalQ.itemAt(i); + if ( NULL != msg ) + { + if( ( msg->command != 0 || msg->command == ( unsigned int ) ( eEvent ) ) + && ( !msg->arg1 || ( OMX_U32 ) msg->arg1 == nData1 ) + && ( !msg->arg2 || ( OMX_U32 ) msg->arg2 == nData2 ) + && msg->arg3) + { + Utils::Semaphore *sem = (Utils::Semaphore*) msg->arg3; + CAMHAL_LOGDA("Event matched, signalling sem"); + mEventSignalQ.removeAt(i); + free(msg); + break; + } + } + } + } + else + { + CAMHAL_LOGEA("Event queue empty!!!"); + } + LOG_FUNCTION_NAME_EXIT; + + return OMX_ErrorNone; +} + + +status_t OMXCameraAdapter::RegisterForEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN Utils::Semaphore &semaphore) +{ + status_t ret = NO_ERROR; + ssize_t res; + android::AutoMutex lock(mEventLock); + + LOG_FUNCTION_NAME; + Utils::Message * msg = ( struct Utils::Message * ) malloc(sizeof(struct Utils::Message)); + if ( NULL != msg ) + { + msg->command = ( unsigned int ) eEvent; + msg->arg1 = ( void * ) nData1; + msg->arg2 = ( void * ) nData2; + msg->arg3 = ( void * ) &semaphore; + msg->arg4 = ( void * ) hComponent; + res = mEventSignalQ.add(msg); + if ( NO_MEMORY == res ) + { + CAMHAL_LOGEA("No ressources for inserting OMX events"); + free(msg); + ret = -ENOMEM; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/*========================================================*/ +/* @ fn SampleTest_EmptyBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + + OMXCameraAdapter *oca = (OMXCameraAdapter*)pAppData; + eError = oca->OMXCameraAdapterEmptyBufferDone(hComponent, pBuffHeader); + + LOG_FUNCTION_NAME_EXIT; + return eError; +} + + +/*========================================================*/ +/* @ fn SampleTest_EmptyBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + + LOG_FUNCTION_NAME; + status_t stat = NO_ERROR; + status_t res1, res2; + OMXCameraPortParameters *pPortParam; + CameraFrame::FrameType typeOfFrame = CameraFrame::ALL_FRAMES; + unsigned int refCount = 0; + unsigned int mask = 0xFFFF; + CameraFrame cameraFrame; + OMX_TI_PLATFORMPRIVATE *platformPrivate; + + res1 = res2 = NO_ERROR; + + if (!pBuffHeader || !pBuffHeader->pBuffer) { + CAMHAL_LOGE("NULL Buffer from OMX"); + return OMX_ErrorNone; + } + + pPortParam = &(mCameraAdapterParameters.mCameraPortParams[pBuffHeader->nInputPortIndex]); + platformPrivate = (OMX_TI_PLATFORMPRIVATE*) pBuffHeader->pPlatformPrivate; + + if (pBuffHeader->nInputPortIndex == OMX_CAMERA_PORT_VIDEO_IN_VIDEO) { + typeOfFrame = CameraFrame::REPROCESS_INPUT_FRAME; + mask = (unsigned int)CameraFrame::REPROCESS_INPUT_FRAME; + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + } + + LOG_FUNCTION_NAME_EXIT; + + return OMX_ErrorNone; +} + +static void debugShowFPS() +{ + static int mFrameCount = 0; + static int mLastFrameCount = 0; + static nsecs_t mLastFpsTime = 0; + static float mFps = 0; + mFrameCount++; + if (!(mFrameCount & 0x1F)) { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + CAMHAL_LOGI("Camera %d Frames, %f FPS", mFrameCount, mFps); + } + // XXX: mFPS has the value we want +} + +/*========================================================*/ +/* @ fn SampleTest_FillBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + Utils::Message msg; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + if (UNLIKELY(mDebugFps)) { + debugShowFPS(); + } + + OMXCameraAdapter *adapter = ( OMXCameraAdapter * ) pAppData; + if ( NULL != adapter ) + { + msg.command = OMXCameraAdapter::OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE; + msg.arg1 = ( void * ) hComponent; + msg.arg2 = ( void * ) pBuffHeader; + adapter->mOMXCallbackHandler->put(&msg); + } + + return eError; +} + +#ifdef CAMERAHAL_OMX_PROFILING + +status_t OMXCameraAdapter::storeProfilingData(OMX_BUFFERHEADERTYPE* pBuffHeader) { + OMX_TI_PLATFORMPRIVATE *platformPrivate = NULL; + OMX_OTHER_EXTRADATATYPE *extraData = NULL; + FILE *fd = NULL; + + LOG_FUNCTION_NAME + + if ( UNLIKELY( mDebugProfile ) ) { + + platformPrivate = static_cast (pBuffHeader->pPlatformPrivate); + extraData = getExtradata(platformPrivate, + static_cast (OMX_TI_ProfilerData)); + + if ( NULL != extraData ) { + if( extraData->eType == static_cast (OMX_TI_ProfilerData) ) { + + fd = fopen(DEFAULT_PROFILE_PATH, "ab"); + if ( NULL != fd ) { + fwrite(extraData->data, 1, extraData->nDataSize, fd); + fclose(fd); + } else { + return -errno; + } + + } else { + return NOT_ENOUGH_DATA; + } + } else { + return NOT_ENOUGH_DATA; + } + } + + LOG_FUNCTION_NAME_EXIT + + return NO_ERROR; +} + +#endif + +/*========================================================*/ +/* @ fn SampleTest_FillBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + + status_t stat = NO_ERROR; + status_t res1, res2; + OMXCameraPortParameters *pPortParam; + OMX_ERRORTYPE eError = OMX_ErrorNone; + CameraFrame::FrameType typeOfFrame = CameraFrame::ALL_FRAMES; + unsigned int refCount = 0; + BaseCameraAdapter::AdapterState state, nextState; + BaseCameraAdapter::getState(state); + BaseCameraAdapter::getNextState(nextState); + android::sp metadataResult = NULL; + unsigned int mask = 0xFFFF; + CameraFrame cameraFrame; + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_TI_ANCILLARYDATATYPE *ancillaryData = NULL; + bool snapshotFrame = false; + + if ( NULL == pBuffHeader ) { + return OMX_ErrorBadParameter; + } + +#ifdef CAMERAHAL_OMX_PROFILING + + storeProfilingData(pBuffHeader); + +#endif + + res1 = res2 = NO_ERROR; + + if ( !pBuffHeader || !pBuffHeader->pBuffer ) { + CAMHAL_LOGEA("NULL Buffer from OMX"); + return OMX_ErrorNone; + } + + pPortParam = &(mCameraAdapterParameters.mCameraPortParams[pBuffHeader->nOutputPortIndex]); + + // Find buffer and mark it as filled + for (int i = 0; i < pPortParam->mNumBufs; i++) { + if (pPortParam->mBufferHeader[i] == pBuffHeader) { + pPortParam->mStatus[i] = OMXCameraPortParameters::DONE; + } + } + + if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW) + { + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return OMX_ErrorNone; + } + + if ( mWaitingForSnapshot ) { + extraData = getExtradata(pBuffHeader->pPlatformPrivate, + (OMX_EXTRADATATYPE) OMX_AncillaryData); + + if ( NULL != extraData ) { + ancillaryData = (OMX_TI_ANCILLARYDATATYPE*) extraData->data; + if ((OMX_2D_Snap == ancillaryData->eCameraView) + || (OMX_3D_Left_Snap == ancillaryData->eCameraView) + || (OMX_3D_Right_Snap == ancillaryData->eCameraView)) { + snapshotFrame = OMX_TRUE; + } else { + snapshotFrame = OMX_FALSE; + } + mPending3Asettings |= SetFocus; + } + } + + ///Prepare the frames to be sent - initialize CameraFrame object and reference count + // TODO(XXX): ancillary data for snapshot frame is not being sent for video snapshot + // if we are waiting for a snapshot and in video mode...go ahead and send + // this frame as a snapshot + if( mWaitingForSnapshot && (mCapturedFrames > 0) && + (snapshotFrame || (mCapMode == VIDEO_MODE) || (mCapMode == VIDEO_MODE_HQ ) )) + { + typeOfFrame = CameraFrame::SNAPSHOT_FRAME; + mask = (unsigned int)CameraFrame::SNAPSHOT_FRAME; + + // video snapshot gets ancillary data and wb info from last snapshot frame + mCaptureAncillaryData = ancillaryData; + mWhiteBalanceData = NULL; + extraData = getExtradata(pBuffHeader->pPlatformPrivate, + (OMX_EXTRADATATYPE) OMX_WhiteBalance); + if ( NULL != extraData ) + { + mWhiteBalanceData = (OMX_TI_WHITEBALANCERESULTTYPE*) extraData->data; + } + } + else + { + typeOfFrame = CameraFrame::PREVIEW_FRAME_SYNC; + mask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC; + } + + if (mRecording) + { + mask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC; + mFramesWithEncoder++; + } + + //CAMHAL_LOGV("FBD pBuffer = 0x%x", pBuffHeader->pBuffer); + + if( mWaitingForSnapshot ) + { + if ( !mBracketingEnabled && + ((HIGH_SPEED == mCapMode) || + (VIDEO_MODE == mCapMode) || + (VIDEO_MODE_HQ == mCapMode)) ) + { + notifyShutterSubscribers(); + } + } + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + mFramesWithDisplay++; + + mFramesWithDucati--; + +#ifdef CAMERAHAL_DEBUG + { + android::AutoMutex locker(mBuffersWithDucatiLock); + if(mBuffersWithDucati.indexOfKey((uint32_t)pBuffHeader->pBuffer)<0) + { + CAMHAL_LOGE("Buffer was never with Ducati!! %p", pBuffHeader->pBuffer); + for(unsigned int i=0;ipBuffer); + } +#endif + + if(mDebugFcs) + CAMHAL_LOGEB("C[%d] D[%d] E[%d]", mFramesWithDucati, mFramesWithDisplay, mFramesWithEncoder); + + recalculateFPS(); + + createPreviewMetadata(pBuffHeader, metadataResult, pPortParam->mWidth, pPortParam->mHeight); + if ( NULL != metadataResult.get() ) { + notifyMetadataSubscribers(metadataResult); + metadataResult.clear(); + } + + { + android::AutoMutex lock(mFaceDetectionLock); + if ( mFDSwitchAlgoPriority ) { + + //Disable region priority and enable face priority for AF + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO , true); + + //Disable Region priority and enable Face priority + setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, false); + setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, true); + mFDSwitchAlgoPriority = false; + } + } + + sniffDccFileDataSave(pBuffHeader); + + stat |= advanceZoom(); + + // On the fly update to 3A settings not working + // Do not update 3A here if we are in the middle of a capture + // or in the middle of transitioning to it + if( mPending3Asettings && + ( (nextState & CAPTURE_ACTIVE) == 0 ) && + ( (state & CAPTURE_ACTIVE) == 0 ) ) { + apply3Asettings(mParameters3A); + } + + } + else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT ) + { + typeOfFrame = CameraFrame::FRAME_DATA_SYNC; + mask = (unsigned int)CameraFrame::FRAME_DATA_SYNC; + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + } + else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_IMAGE_OUT_IMAGE ) + { + OMX_COLOR_FORMATTYPE pixFormat; + const char *valstr = NULL; + + pixFormat = pPortParam->mColorFormat; + + if ( OMX_COLOR_FormatUnused == pixFormat ) + { + typeOfFrame = CameraFrame::IMAGE_FRAME; + mask = (unsigned int) CameraFrame::IMAGE_FRAME; + } else if ( pixFormat == OMX_COLOR_FormatCbYCrY && + ((mPictureFormatFromClient && + !strcmp(mPictureFormatFromClient, + android::CameraParameters::PIXEL_FORMAT_JPEG)) || + !mPictureFormatFromClient) ) { + // signals to callbacks that this needs to be coverted to jpeg + // before returning to framework + typeOfFrame = CameraFrame::IMAGE_FRAME; + mask = (unsigned int) CameraFrame::IMAGE_FRAME; + cameraFrame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG; + cameraFrame.mQuirks |= CameraFrame::FORMAT_YUV422I_UYVY; + + // populate exif data and pass to subscribers via quirk + // subscriber is in charge of freeing exif data + ExifElementsTable* exif = new ExifElementsTable(); + setupEXIF_libjpeg(exif, mCaptureAncillaryData, mWhiteBalanceData); + cameraFrame.mQuirks |= CameraFrame::HAS_EXIF_DATA; + cameraFrame.mCookie2 = (void*) exif; + } else { + typeOfFrame = CameraFrame::RAW_FRAME; + mask = (unsigned int) CameraFrame::RAW_FRAME; + } + + pPortParam->mImageType = typeOfFrame; + + if((mCapturedFrames>0) && !mCaptureSignalled) + { + mCaptureSignalled = true; + mCaptureSem.Signal(); + } + + if( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE ) + { + goto EXIT; + } + + { + android::AutoMutex lock(mBracketingLock); + if ( mBracketingEnabled ) + { + doBracketing(pBuffHeader, typeOfFrame); + return eError; + } + } + + if (mZoomBracketingEnabled) { + doZoom(mZoomBracketingValues[mCurrentZoomBracketing]); + CAMHAL_LOGDB("Current Zoom Bracketing: %d", mZoomBracketingValues[mCurrentZoomBracketing]); + mCurrentZoomBracketing++; + if (mCurrentZoomBracketing == ARRAY_SIZE(mZoomBracketingValues)) { + mZoomBracketingEnabled = false; + } + } + + if ( 1 > mCapturedFrames ) + { + goto EXIT; + } + +#ifdef OMAP_ENHANCEMENT_CPCAM + if ( NULL != mSharedAllocator ) { + cameraFrame.mMetaData = new CameraMetadataResult(getMetaData(pBuffHeader->pPlatformPrivate, mSharedAllocator)); + } +#endif + + CAMHAL_LOGDB("Captured Frames: %d", mCapturedFrames); + + mCapturedFrames--; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + if (mYuvCapture) { + struct timeval timeStampUsec; + gettimeofday(&timeStampUsec, NULL); + + time_t saveTime; + time(&saveTime); + const struct tm * const timeStamp = gmtime(&saveTime); + + char filename[256]; + snprintf(filename,256, "%s/yuv_%d_%d_%d_%lu.yuv", + kYuvImagesOutputDirPath, + timeStamp->tm_hour, + timeStamp->tm_min, + timeStamp->tm_sec, + timeStampUsec.tv_usec); + + const status_t saveBufferStatus = saveBufferToFile(((CameraBuffer*)pBuffHeader->pAppPrivate)->mapped, + pBuffHeader->nFilledLen, filename); + + if (saveBufferStatus != OK) { + CAMHAL_LOGE("ERROR: %d, while saving yuv!", saveBufferStatus); + } else { + CAMHAL_LOGD("yuv_%d_%d_%d_%lu.yuv successfully saved in %s", + timeStamp->tm_hour, + timeStamp->tm_min, + timeStamp->tm_sec, + timeStampUsec.tv_usec, + kYuvImagesOutputDirPath); + } + } +#endif + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); +#ifdef OMAP_ENHANCEMENT_CPCAM + if ( NULL != cameraFrame.mMetaData.get() ) { + cameraFrame.mMetaData.clear(); + } +#endif + + } + else if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_VIDEO) { + typeOfFrame = CameraFrame::RAW_FRAME; + pPortParam->mImageType = typeOfFrame; + { + android::AutoMutex lock(mLock); + if( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE ) { + goto EXIT; + } + } + + CAMHAL_LOGD("RAW buffer done on video port, length = %d", pBuffHeader->nFilledLen); + + mask = (unsigned int) CameraFrame::RAW_FRAME; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + if ( mRawCapture ) { + struct timeval timeStampUsec; + gettimeofday(&timeStampUsec, NULL); + + time_t saveTime; + time(&saveTime); + const struct tm * const timeStamp = gmtime(&saveTime); + + char filename[256]; + snprintf(filename,256, "%s/raw_%d_%d_%d_%lu.raw", + kRawImagesOutputDirPath, + timeStamp->tm_hour, + timeStamp->tm_min, + timeStamp->tm_sec, + timeStampUsec.tv_usec); + + const status_t saveBufferStatus = saveBufferToFile( ((CameraBuffer*)pBuffHeader->pAppPrivate)->mapped, + pBuffHeader->nFilledLen, filename); + + if (saveBufferStatus != OK) { + CAMHAL_LOGE("ERROR: %d , while saving raw!", saveBufferStatus); + } else { + CAMHAL_LOGD("raw_%d_%d_%d_%lu.raw successfully saved in %s", + timeStamp->tm_hour, + timeStamp->tm_min, + timeStamp->tm_sec, + timeStampUsec.tv_usec, + kRawImagesOutputDirPath); + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + } + } +#endif + } else { + CAMHAL_LOGEA("Frame received for non-(preview/capture/measure) port. This is yet to be supported"); + goto EXIT; + } + + if ( NO_ERROR != stat ) + { + CameraBuffer *camera_buffer; + + camera_buffer = (CameraBuffer *)pBuffHeader->pAppPrivate; + + CAMHAL_LOGDB("sendFrameToSubscribers error: %d", stat); + returnFrame(camera_buffer, typeOfFrame); + } + + return eError; + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, stat, eError); + + if ( NO_ERROR != stat ) + { + if ( NULL != mErrorNotifier ) + { + mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN); + } + } + + return eError; +} + +status_t OMXCameraAdapter::recalculateFPS() +{ + float currentFPS; + + { + android::AutoMutex lock(mFrameCountMutex); + mFrameCount++; + if (mFrameCount == 1) { + mFirstFrameCondition.broadcast(); + } + } + + if ( ( mFrameCount % FPS_PERIOD ) == 0 ) + { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFPSTime; + currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFPSTime = now; + mLastFrameCount = mFrameCount; + + if ( 1 == mIter ) + { + mFPS = currentFPS; + } + else + { + //cumulative moving average + mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; + } + + mLastFPS = mFPS; + mIter++; + } + + return NO_ERROR; +} + +status_t OMXCameraAdapter::sendCallBacks(CameraFrame frame, OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, unsigned int mask, OMXCameraPortParameters *port) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == port) + { + CAMHAL_LOGEA("Invalid portParam"); + return -EINVAL; + } + + if ( NULL == pBuffHeader ) + { + CAMHAL_LOGEA("Invalid Buffer header"); + return -EINVAL; + } + + android::AutoMutex lock(mSubscriberLock); + + //frame.mFrameType = typeOfFrame; + frame.mFrameMask = mask; + frame.mBuffer = (CameraBuffer *)pBuffHeader->pAppPrivate; + frame.mLength = pBuffHeader->nFilledLen; + frame.mAlignment = port->mStride; + frame.mOffset = pBuffHeader->nOffset; + frame.mWidth = port->mWidth; + frame.mHeight = port->mHeight; + frame.mYuv[0] = NULL; + frame.mYuv[1] = NULL; + + if ( onlyOnce && mRecording ) + { + mTimeSourceDelta = (pBuffHeader->nTimeStamp * 1000) - systemTime(SYSTEM_TIME_MONOTONIC); + onlyOnce = false; + } + + frame.mTimestamp = (pBuffHeader->nTimeStamp * 1000) - mTimeSourceDelta; + + ret = setInitFrameRefCount(frame.mBuffer, mask); + + if (ret != NO_ERROR) { + CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); + } else { + ret = sendFrameToSubscribers(&frame); + } + + CAMHAL_LOGVB("B 0x%x T %llu", frame.mBuffer, pBuffHeader->nTimeStamp); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool OMXCameraAdapter::CommandHandler::Handler() +{ + Utils::Message msg; + volatile int forever = 1; + status_t stat; + ErrorNotifier *errorNotify = NULL; + + LOG_FUNCTION_NAME; + + while ( forever ) + { + stat = NO_ERROR; + CAMHAL_LOGDA("Handler: waiting for messsage..."); + Utils::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + { + android::AutoMutex lock(mLock); + mCommandMsgQ.get(&msg); + } + CAMHAL_LOGDB("msg.command = %d", msg.command); + switch ( msg.command ) { + case CommandHandler::CAMERA_START_IMAGE_CAPTURE: + { + OMXCameraAdapter::CachedCaptureParameters* cap_params = + static_cast(msg.arg2); + stat = mCameraAdapter->startImageCapture(false, cap_params); + delete cap_params; + break; + } + case CommandHandler::CAMERA_PERFORM_AUTOFOCUS: + { + stat = mCameraAdapter->doAutoFocus(); + break; + } + case CommandHandler::COMMAND_EXIT: + { + CAMHAL_LOGDA("Exiting command handler"); + forever = 0; + break; + } + case CommandHandler::CAMERA_SWITCH_TO_EXECUTING: + { + stat = mCameraAdapter->doSwitchToExecuting(); + break; + } + case CommandHandler::CAMERA_START_REPROCESS: + { + OMXCameraAdapter::CachedCaptureParameters* cap_params = + static_cast(msg.arg2); + stat = mCameraAdapter->startReprocess(); + stat = mCameraAdapter->startImageCapture(false, cap_params); + delete cap_params; + break; + } + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return false; +} + +bool OMXCameraAdapter::OMXCallbackHandler::Handler() +{ + Utils::Message msg; + volatile int forever = 1; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + while(forever){ + Utils::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + { + android::AutoMutex lock(mLock); + mCommandMsgQ.get(&msg); + mIsProcessed = false; + } + + switch ( msg.command ) { + case OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE: + { + ret = mCameraAdapter->OMXCameraAdapterFillBufferDone(( OMX_HANDLETYPE ) msg.arg1, + ( OMX_BUFFERHEADERTYPE *) msg.arg2); + break; + } + case OMXCallbackHandler::CAMERA_FOCUS_STATUS: + { + mCameraAdapter->handleFocusCallback(); + break; + } + case CommandHandler::COMMAND_EXIT: + { + CAMHAL_LOGDA("Exiting OMX callback handler"); + forever = 0; + break; + } + } + + { + android::AutoMutex locker(mLock); + CAMHAL_UNUSED(locker); + + mIsProcessed = mCommandMsgQ.isEmpty(); + if ( mIsProcessed ) + mCondition.signal(); + } + } + + // force the condition to wake + { + android::AutoMutex locker(mLock); + CAMHAL_UNUSED(locker); + + mIsProcessed = true; + mCondition.signal(); + } + + LOG_FUNCTION_NAME_EXIT; + return false; +} + +void OMXCameraAdapter::OMXCallbackHandler::flush() +{ + LOG_FUNCTION_NAME; + + android::AutoMutex locker(mLock); + CAMHAL_UNUSED(locker); + + if ( mIsProcessed ) + return; + + mCondition.wait(mLock); +} + +status_t OMXCameraAdapter::setExtraData(bool enable, OMX_U32 nPortIndex, OMX_EXT_EXTRADATATYPE eType) { + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXTRADATATYPE extraDataControl; + + LOG_FUNCTION_NAME; + + if ( ( OMX_StateInvalid == mComponentState ) || + ( NULL == mCameraAdapterParameters.mHandleComp ) ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return -EINVAL; + } + + OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE); + + extraDataControl.nPortIndex = nPortIndex; + extraDataControl.eExtraDataType = eType; +#ifdef CAMERAHAL_TUNA + extraDataControl.eCameraView = OMX_2D; +#endif + + if (enable) { + extraDataControl.bEnable = OMX_TRUE; + } else { + extraDataControl.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigOtherExtraDataControl, + &extraDataControl); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +OMX_OTHER_EXTRADATATYPE *OMXCameraAdapter::getExtradata(const OMX_PTR ptrPrivate, OMX_EXTRADATATYPE type) const +{ + if ( NULL != ptrPrivate ) { + const OMX_TI_PLATFORMPRIVATE *platformPrivate = (const OMX_TI_PLATFORMPRIVATE *) ptrPrivate; + + CAMHAL_LOGVB("Size = %d, sizeof = %d, pAuxBuf = 0x%x, pAuxBufSize= %d, pMetaDataBufer = 0x%x, nMetaDataSize = %d", + platformPrivate->nSize, + sizeof(OMX_TI_PLATFORMPRIVATE), + platformPrivate->pAuxBuf1, + platformPrivate->pAuxBufSize1, + platformPrivate->pMetaDataBuffer, + platformPrivate->nMetaDataSize); + if ( sizeof(OMX_TI_PLATFORMPRIVATE) == platformPrivate->nSize ) { + if ( 0 < platformPrivate->nMetaDataSize ) { + OMX_U32 remainingSize = platformPrivate->nMetaDataSize; + OMX_OTHER_EXTRADATATYPE *extraData = (OMX_OTHER_EXTRADATATYPE *) platformPrivate->pMetaDataBuffer; + if ( NULL != extraData ) { + while ( extraData->eType && extraData->nDataSize && extraData->data && + (remainingSize >= extraData->nSize)) { + if ( type == extraData->eType ) { + return extraData; + } + remainingSize -= extraData->nSize; + extraData = (OMX_OTHER_EXTRADATATYPE*) ((char*)extraData + extraData->nSize); + } + } else { + CAMHAL_LOGEB("OMX_TI_PLATFORMPRIVATE pMetaDataBuffer is NULL"); + } + } else { + CAMHAL_LOGEB("OMX_TI_PLATFORMPRIVATE nMetaDataSize is size is %d", + ( unsigned int ) platformPrivate->nMetaDataSize); + } + } else { + CAMHAL_LOGEB("OMX_TI_PLATFORMPRIVATE size mismatch: expected = %d, received = %d", + ( unsigned int ) sizeof(OMX_TI_PLATFORMPRIVATE), + ( unsigned int ) platformPrivate->nSize); + } + } else { + CAMHAL_LOGEA("Invalid OMX_TI_PLATFORMPRIVATE"); + } + + // Required extradata type wasn't found + return NULL; +} + +OMXCameraAdapter::CachedCaptureParameters* OMXCameraAdapter::cacheCaptureParameters() { + CachedCaptureParameters* params = new CachedCaptureParameters(); + + params->mPendingCaptureSettings = mPendingCaptureSettings; + params->mPictureRotation = mPictureRotation; + memcpy(params->mExposureBracketingValues, + mExposureBracketingValues, + sizeof(mExposureBracketingValues)); + memcpy(params->mExposureGainBracketingValues, + mExposureGainBracketingValues, + sizeof(mExposureGainBracketingValues)); + memcpy(params->mExposureGainBracketingModes, + mExposureGainBracketingModes, + sizeof(mExposureGainBracketingModes)); + params->mExposureBracketingValidEntries = mExposureBracketingValidEntries; + params->mExposureBracketMode = mExposureBracketMode; + params->mBurstFrames = mBurstFrames; + params->mFlushShotConfigQueue = mFlushShotConfigQueue; + + return params; +} + +OMXCameraAdapter::OMXCameraAdapter(size_t sensor_index) +{ + LOG_FUNCTION_NAME; + + mOmxInitialized = false; + mComponentState = OMX_StateInvalid; + mSensorIndex = sensor_index; + mPictureRotation = 0; + // Initial values + mTimeSourceDelta = 0; + onlyOnce = true; + mDccData.pData = NULL; + + mInitSem.Create(0); + mFlushSem.Create(0); + mUsePreviewDataSem.Create(0); + mUsePreviewSem.Create(0); + mUseCaptureSem.Create(0); + mUseReprocessSem.Create(0); + mStartPreviewSem.Create(0); + mStopPreviewSem.Create(0); + mStartCaptureSem.Create(0); + mStopCaptureSem.Create(0); + mStopReprocSem.Create(0); + mSwitchToLoadedSem.Create(0); + mCaptureSem.Create(0); + + mSwitchToExecSem.Create(0); + + mCameraAdapterParameters.mHandleComp = 0; + + mUserSetExpLock = OMX_FALSE; + mUserSetWbLock = OMX_FALSE; + + mFramesWithDucati = 0; + mFramesWithDisplay = 0; + mFramesWithEncoder = 0; + +#ifdef CAMERAHAL_OMX_PROFILING + + mDebugProfile = 0; + +#endif + + mPreviewPortInitialized = false; + + LOG_FUNCTION_NAME_EXIT; +} + +OMXCameraAdapter::~OMXCameraAdapter() +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(gAdapterLock); + + // return to OMX Loaded state + switchToLoaded(); + + if ( mOmxInitialized ) { + saveDccFileDataSave(); + + closeDccFileDataSave(); + // deinit the OMX + if ( mComponentState == OMX_StateLoaded || mComponentState == OMX_StateInvalid ) { + // free the handle for the Camera component + if ( mCameraAdapterParameters.mHandleComp ) { + OMX_FreeHandle(mCameraAdapterParameters.mHandleComp); + mCameraAdapterParameters.mHandleComp = NULL; + } + } + + OMX_Deinit(); + mOmxInitialized = false; + } + + //Remove any unhandled events + if ( !mEventSignalQ.isEmpty() ) + { + for (unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ ) + { + Utils::Message *msg = mEventSignalQ.itemAt(i); + //remove from queue and free msg + if ( NULL != msg ) + { + Utils::Semaphore *sem = (Utils::Semaphore*) msg->arg3; + sem->Signal(); + free(msg); + + } + } + mEventSignalQ.clear(); + } + + //Exit and free ref to command handling thread + if ( NULL != mCommandHandler.get() ) + { + Utils::Message msg; + msg.command = CommandHandler::COMMAND_EXIT; + msg.arg1 = mErrorNotifier; + mCommandHandler->clearCommandQ(); + mCommandHandler->put(&msg); + mCommandHandler->requestExitAndWait(); + mCommandHandler.clear(); + } + + //Exit and free ref to callback handling thread + if ( NULL != mOMXCallbackHandler.get() ) + { + Utils::Message msg; + msg.command = OMXCallbackHandler::COMMAND_EXIT; + //Clear all messages pending first + mOMXCallbackHandler->clearCommandQ(); + mOMXCallbackHandler->put(&msg); + mOMXCallbackHandler->requestExitAndWait(); + mOMXCallbackHandler.clear(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +extern "C" CameraAdapter* OMXCameraAdapter_Factory(size_t sensor_index) +{ + CameraAdapter *adapter = NULL; + android::AutoMutex lock(gAdapterLock); + + LOG_FUNCTION_NAME; + + adapter = new OMXCameraAdapter(sensor_index); + if ( adapter ) { + CAMHAL_LOGDB("New OMX Camera adapter instance created for sensor %d",sensor_index); + } else { + CAMHAL_LOGEA("OMX Camera adapter create failed for sensor index = %d!",sensor_index); + } + + LOG_FUNCTION_NAME_EXIT; + + return adapter; +} + +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData, + const OMX_CALLBACKTYPE & callbacks) +{ + OMX_ERRORTYPE eError = OMX_ErrorUndefined; + + for ( int i = 0; i < 5; ++i ) { + if ( i > 0 ) { + // sleep for 100 ms before next attempt + usleep(100000); + } + + // setup key parameters to send to Ducati during init + OMX_CALLBACKTYPE oCallbacks = callbacks; + + // get handle + eError = OMX_GetHandle(handle, (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.CAMERA", pAppData, &oCallbacks); + if ( eError == OMX_ErrorNone ) { + return OMX_ErrorNone; + } + + CAMHAL_LOGEB("OMX_GetHandle() failed, error: 0x%x", eError); + } + + *handle = 0; + return eError; +} + + +class CapabilitiesHandler +{ +public: + CapabilitiesHandler() + { + mComponent = 0; + } + + const OMX_HANDLETYPE & component() const + { + return mComponent; + } + + OMX_HANDLETYPE & componentRef() + { + return mComponent; + } + + status_t fetchCapabiltiesForMode(OMX_CAMOPERATINGMODETYPE mode, + int sensorId, + CameraProperties::Properties * properties) + { + OMX_CONFIG_CAMOPERATINGMODETYPE camMode; + + OMX_INIT_STRUCT_PTR (&camMode, OMX_CONFIG_CAMOPERATINGMODETYPE); + camMode.eCamOperatingMode = mode; + + OMX_ERRORTYPE eError = OMX_SetParameter(component(), + ( OMX_INDEXTYPE ) OMX_IndexCameraOperatingMode, + &camMode); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGE("Error while configuring camera mode in CameraAdapter_Capabilities 0x%x", eError); + return BAD_VALUE; + } + + // get and fill capabilities + OMXCameraAdapter::getCaps(sensorId, properties, component()); + + return NO_ERROR; + } + + status_t fetchCapabilitiesForSensor(int sensorId, + CameraProperties::Properties * properties) + { + // sensor select + OMX_CONFIG_SENSORSELECTTYPE sensorSelect; + OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE); + sensorSelect.eSensor = (OMX_SENSORSELECT)sensorId; + + CAMHAL_LOGD("Selecting sensor %d...", sensorId); + const OMX_ERRORTYPE sensorSelectError = OMX_SetConfig(component(), + (OMX_INDEXTYPE)OMX_TI_IndexConfigSensorSelect, &sensorSelect); + CAMHAL_LOGD("Selecting sensor %d... DONE", sensorId); + + if ( sensorSelectError != OMX_ErrorNone ) { + CAMHAL_LOGD("Max supported sensor number reached: %d", sensorId); + return BAD_VALUE; + } + + status_t err = NO_ERROR; + if ( sensorId == 2 ) { + CAMHAL_LOGD("Camera mode: STEREO"); + properties->setMode(MODE_STEREO); + err = fetchCapabiltiesForMode(OMX_CaptureStereoImageCapture, + sensorId, + properties); + } else { + CAMHAL_LOGD("Camera MONO"); + + CAMHAL_LOGD("Camera mode: HQ "); + properties->setMode(MODE_HIGH_QUALITY); + err = fetchCapabiltiesForMode(OMX_CaptureImageProfileBase, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } + + CAMHAL_LOGD("Camera mode: VIDEO "); + properties->setMode(MODE_VIDEO); + err = fetchCapabiltiesForMode(OMX_CaptureVideo, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } + + CAMHAL_LOGD("Camera mode: ZSL "); + properties->setMode(MODE_ZEROSHUTTERLAG); + err = fetchCapabiltiesForMode(OMX_TI_CaptureImageProfileZeroShutterLag, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } + + CAMHAL_LOGD("Camera mode: HS "); + properties->setMode(MODE_HIGH_SPEED); + err = fetchCapabiltiesForMode(OMX_CaptureImageHighSpeedTemporalBracketing, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } + +#ifdef OMAP_ENHANCEMENT_CPCAM + CAMHAL_LOGD("Camera mode: CPCAM "); + properties->setMode(MODE_CPCAM); + err = fetchCapabiltiesForMode(OMX_TI_CPCam, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } +#endif + +#ifdef CAMERAHAL_OMAP5_CAPTURE_MODES + + CAMHAL_LOGD("Camera mode: VIDEO HQ "); + properties->setMode(MODE_VIDEO_HIGH_QUALITY); + err = fetchCapabiltiesForMode(OMX_CaptureHighQualityVideo, + sensorId, + properties); + if ( NO_ERROR != err ) { + return err; + } + +#endif + + } + + return err; + } + +private: + OMX_HANDLETYPE mComponent; + OMX_STATETYPE mState; +}; + +extern "C" status_t OMXCameraAdapter_Capabilities( + CameraProperties::Properties * const properties_array, + const int starting_camera, const int max_camera, int & supportedCameras) +{ + LOG_FUNCTION_NAME; + + supportedCameras = 0; + + int num_cameras_supported = 0; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + android::AutoMutex lock(gAdapterLock); + + if (!properties_array) { + CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("Error OMX_Init -0x%x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + CapabilitiesHandler handler; + OMX_CALLBACKTYPE callbacks; + callbacks.EventHandler = 0; + callbacks.EmptyBufferDone = 0; + callbacks.FillBufferDone = 0; + + eError = OMXCameraAdapter::OMXCameraGetHandle(&handler.componentRef(), &handler, callbacks); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError); + goto EXIT; + } + +#ifndef USES_LEGACY_DOMX_DCC + DCCHandler dcc_handler; + dcc_handler.loadDCC(handler.componentRef()); +#endif + + // Continue selecting sensor and then querying OMX Camera for it's capabilities + // When sensor select returns an error, we know to break and stop + while (eError == OMX_ErrorNone && + (starting_camera + num_cameras_supported) < max_camera) { + + const int sensorId = num_cameras_supported; + CameraProperties::Properties * properties = properties_array + starting_camera + sensorId; + const status_t err = handler.fetchCapabilitiesForSensor(sensorId, properties); + + if ( err != NO_ERROR ) + break; + + num_cameras_supported++; + CAMHAL_LOGEB("Number of OMX Cameras detected = %d \n",num_cameras_supported); + } + + // clean up + if(handler.component()) { + CAMHAL_LOGD("Freeing the component..."); + OMX_FreeHandle(handler.component()); + CAMHAL_LOGD("Freeing the component... DONE"); + handler.componentRef() = NULL; + } + + EXIT: + CAMHAL_LOGD("Deinit..."); + OMX_Deinit(); + CAMHAL_LOGD("Deinit... DONE"); + + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGE("Error: 0x%x", eError); + LOG_FUNCTION_NAME_EXIT; + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + supportedCameras = num_cameras_supported; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +} // namespace Camera +} // namespace Ti + + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ + diff --git a/camera/OMXCameraAdapter/OMXCapabilities.cpp b/camera/OMXCameraAdapter/OMXCapabilities.cpp new file mode 100644 index 0000000..72a2380 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapabilities.cpp @@ -0,0 +1,2513 @@ +/* + * 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. + */ + +/** +* @file OMXCap.cpp +* +* This file implements the OMX Capabilities feature. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" +#include "TICameraParameters.h" + +namespace Ti { +namespace Camera { + +/************************************ + * global constants and variables + *************************************/ + +#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) + +static const char PARAM_SEP[] = ","; +static const uint32_t VFR_OFFSET = 8; +static const char FPS_STR_MAX_LEN = 10; + +static const unsigned int MANUAL_EXPOSURE_STEP = 1; +static const unsigned int MANUAL_GAIN_ISO_MIN = 100; +static const unsigned int MANUAL_GAIN_ISO_STEP = 100; + +const int OMXCameraAdapter::SENSORID_IMX060 = 300; +const int OMXCameraAdapter::SENSORID_OV5650 = 301; +const int OMXCameraAdapter::SENSORID_OV5640 = 302; +const int OMXCameraAdapter::SENSORID_OV14825 = 304; +const int OMXCameraAdapter::SENSORID_S5K4E1GA = 305; +const int OMXCameraAdapter::SENSORID_S5K6A1GX03 = 306; +const int OMXCameraAdapter::SENSORID_OV8830 = 310; +const int OMXCameraAdapter::SENSORID_OV2722 = 311; +const int OMXCameraAdapter::SENSORID_OV9726 = 312; + + +const int OMXCameraAdapter::FPS_MIN = 5; +const int OMXCameraAdapter::FPS_MAX = 30; +const int OMXCameraAdapter::FPS_MAX_EXTENDED = 60; + +inline static int androidFromDucatiFrameRate(OMX_U32 frameRate) { + return (frameRate >> VFR_OFFSET) * CameraHal::VFR_SCALE; +} + +/**** look up tables to translate OMX Caps to Parameter ****/ + +const CapResolution OMXCameraAdapter::mImageCapRes [] = { + { 4416, 3312, "4416x3312" }, + { 4032, 3024, "4032x3024" }, + { 4000, 3000, "4000x3000" }, + { 3648, 2736, "3648x2736" }, + { 3264, 2448, "3264x2448" }, + { 2608, 1960, "2608x1960" }, + { 2592, 1944, "2592x1944" }, + { 2592, 1728, "2592x1728" }, + { 2592, 1458, "2592x1458" }, + { 2400, 1350, "2400x1350" }, + { 2304, 1296, "2304x1296" }, + { 2240, 1344, "2240x1344" }, + { 2160, 1440, "2160x1440" }, + { 2112, 1728, "2112x1728" }, + { 2112, 1188, "2112x1188" }, + { 2048, 1536, "2048x1536" }, + { 2016, 1512, "2016x1512" }, + { 2016, 1134, "2016x1134" }, + { 2000, 1600, "2000x1600" }, + { 1920, 1080, "1920x1080" }, + { 1600, 1200, "1600x1200" }, + { 1600, 900, "1600x900" }, + { 1536, 864, "1536x864" }, + { 1408, 792, "1408x792" }, + { 1344, 756, "1344x756" }, + { 1280, 1024, "1280x1024" }, + { 1280, 720, "1280x720" }, + { 1152, 864, "1152x864" }, + { 1280, 960, "1280x960" }, + { 1024, 768, "1024x768" }, + { 640, 480, "640x480" }, + { 320, 240, "320x240" }, +}; + +const CapResolution OMXCameraAdapter::mImageCapResSS [] = { + { 4032*2, 3024, "8064x3024" }, + { 3648*2, 2736, "7296x2736" }, + { 3264*2, 2448, "6528x2448" }, + { 2592*2, 1944, "5184x1944" }, + { 2048*2, 1536, "4096x1536" }, + { 1600*2, 1200, "3200x1200" }, + { 1280*2, 960, "2560x960" }, + { 1280*2, 720, "2560x720" }, + { 1024*2, 768, "2048x768" }, + { 640*2, 480, "1280x480" }, + { 320*2, 240, "640x240" }, +}; + +const CapResolution OMXCameraAdapter::mImageCapResTB [] = { + { 4032, 3024*2, "4032x6048" }, + { 3648, 2736*2, "3648x5472" }, + { 3264, 2448*2, "3264x4896" }, + { 2592, 1944*2, "2592x3888" }, + { 2048, 1536*2, "2048x3072" }, + { 1600, 1200*2, "1600x2400" }, + { 1280, 960*2, "1280x1920" }, + { 1280, 720*2, "1280x1440" }, + { 1024, 768*2, "1024x1536" }, + { 640, 480*2, "640x960" }, + { 320, 240*2, "320x480" }, +}; + +const CapResolution OMXCameraAdapter::mPreviewRes [] = { + { 1920, 1080, "1920x1080" }, + { 1280, 720, "1280x720" }, + { 960, 720, "960x720" }, + { 800, 480, "800x480" }, + { 720, 576, "720x576" }, + { 720, 480, "720x480" }, + { 768, 576, "768x576" }, + { 640, 480, "640x480" }, + { 320, 240, "320x240" }, + { 352, 288, "352x288" }, + { 240, 160, "240x160" }, + { 176, 144, "176x144" }, + { 160, 120, "160x120" }, + { 128, 96, "128x96" }, +}; + +const CapResolution OMXCameraAdapter::mPreviewPortraitRes [] = { + //Portrait resolutions + { 1088, 1920, "1088x1920" }, + { 720, 1280, "720x1280" }, + { 480, 800, "480x800" }, + { 576, 720, "576x720" }, + { 576, 768, "576x768" }, + { 480, 720, "480x720" }, + { 480, 640, "480x640" }, + { 288, 352, "288x352" }, + { 240, 320, "240x320" }, + { 160, 240, "160x240" }, + { 144, 176, "144x176" }, + { 120, 160, "120x160"}, + { 96, 128, "96x128" } +}; + +const CapResolution OMXCameraAdapter::mPreviewResSS [] = { + { 1920*2, 1080, "3840x1080" }, + { 1280*2, 720, "2560x720" }, + { 800*2, 480, "1600x480" }, + { 720*2, 576, "1440x576" }, + { 720*2, 480, "1440x480" }, + { 768*2, 576, "1536x576" }, + { 640*2, 480, "1280x480" }, + { 320*2, 240, "640x240" }, + { 352*2, 288, "704x288" }, + { 240*2, 160, "480x160" }, + { 176*2, 144, "352x144" }, + { 128*2, 96, "256x96" } +}; + +const CapResolution OMXCameraAdapter::mPreviewResTB [] = { + { 1920, 1080*2, "1920x2160" }, + { 1280, 720*2, "1280x1440" }, + { 800, 480*2, "800x960" }, + { 720, 576*2, "720x1152" }, + { 720, 480*2, "720x960" }, + { 768, 576*2, "768x1152" }, + { 640, 480*2, "640x960" }, + { 320, 240*2, "320x480" }, + { 352, 288*2, "352x576" }, + { 240, 160*2, "240x320" }, + { 176, 144*2, "176x288" }, + { 128, 96*2, "128x192" }, +}; + +const CapResolution OMXCameraAdapter::mThumbRes [] = { + { 640, 480, "640x480" }, + { 160, 120, "160x120" }, + { 200, 120, "200x120" }, + { 320, 240, "320x240" }, + { 512, 384, "512x384" }, + { 352, 144, "352x144" }, + { 176, 144, "176x144" }, + { 96, 96, "96x96" }, +}; + +const CapPixelformat OMXCameraAdapter::mPixelformats [] = { + { OMX_COLOR_FormatCbYCrY, android::CameraParameters::PIXEL_FORMAT_YUV422I }, + { OMX_COLOR_FormatYUV420SemiPlanar, android::CameraParameters::PIXEL_FORMAT_YUV420SP }, + { OMX_COLOR_Format16bitRGB565, android::CameraParameters::PIXEL_FORMAT_RGB565 }, + { OMX_COLOR_FormatYUV420SemiPlanar, android::CameraParameters::PIXEL_FORMAT_YUV420P }, + { OMX_COLOR_FormatUnused, TICameraParameters::PIXEL_FORMAT_UNUSED }, + { OMX_COLOR_FormatRawBayer10bit, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB }, +}; + +const userToOMX_LUT OMXCameraAdapter::mFrameLayout [] = { + { TICameraParameters::S3D_NONE, OMX_TI_StereoFrameLayout2D }, + { TICameraParameters::S3D_TB_FULL, OMX_TI_StereoFrameLayoutTopBottom }, + { TICameraParameters::S3D_SS_FULL, OMX_TI_StereoFrameLayoutLeftRight }, + { TICameraParameters::S3D_TB_SUBSAMPLED, OMX_TI_StereoFrameLayoutTopBottomSubsample }, + { TICameraParameters::S3D_SS_SUBSAMPLED, OMX_TI_StereoFrameLayoutLeftRightSubsample }, +}; + +const LUTtype OMXCameraAdapter::mLayoutLUT = { + ARRAY_SIZE(mFrameLayout), + mFrameLayout +}; + +const CapCodingFormat OMXCameraAdapter::mImageCodingFormat [] = { + { OMX_IMAGE_CodingJPEG, android::CameraParameters::PIXEL_FORMAT_JPEG }, + { (OMX_IMAGE_CODINGTYPE)OMX_TI_IMAGE_CodingJPS, TICameraParameters::PIXEL_FORMAT_JPS }, + { (OMX_IMAGE_CODINGTYPE)OMX_TI_IMAGE_CodingMPO, TICameraParameters::PIXEL_FORMAT_MPO }, +}; + +const CapFramerate OMXCameraAdapter::mFramerates [] = { + { 60, "60" }, + { 30, "30" }, + { 24, "24" }, + { 20, "20" }, + { 15, "15" }, + { 10, "10" }, +}; + +const CapZoom OMXCameraAdapter::mZoomStages [] = { + { 65536, "100" }, + { 68157, "104" }, + { 70124, "107" }, + { 72745, "111" }, + { 75366, "115" }, + { 77988, "119" }, + { 80609, "123" }, + { 83231, "127" }, + { 86508, "132" }, + { 89784, "137" }, + { 92406, "141" }, + { 95683, "146" }, + { 99615, "152" }, + { 102892, "157" }, + { 106168, "162" }, + { 110100, "168" }, + { 114033, "174" }, + { 117965, "180" }, + { 122552, "187" }, + { 126484, "193" }, + { 131072, "200" }, + { 135660, "207" }, + { 140247, "214" }, + { 145490, "222" }, + { 150733, "230" }, + { 155976, "238" }, + { 161219, "246" }, + { 167117, "255" }, + { 173015, "264" }, + { 178913, "273" }, + { 185467, "283" }, + { 192020, "293" }, + { 198574, "303" }, + { 205783, "314" }, + { 212992, "325" }, + { 220201, "336" }, + { 228065, "348" }, + { 236585, "361" }, + { 244449, "373" }, + { 252969, "386" }, + { 262144, "400" }, + { 271319, "414" }, + { 281149, "429" }, + { 290980, "444" }, + { 300810, "459" }, + { 311951, "476" }, + { 322437, "492" }, + { 334234, "510" }, + { 346030, "528" }, + { 357827, "546" }, + { 370934, "566" }, + { 384041, "586" }, + { 397148, "606" }, + { 411566, "628" }, + { 425984, "650" }, + { 441057, "673" }, + { 456131, "696" }, + { 472515, "721" }, + { 488899, "746" }, + { 506593, "773" }, + { 524288, "800" }, +}; + +const CapISO OMXCameraAdapter::mISOStages [] = { + { 0, "auto" }, + { 100, "100" }, + { 200, "200"}, + { 400, "400" }, + { 800, "800" }, + { 1000, "1000" }, + { 1200, "1200" }, + { 1600, "1600" }, +}; + +// mapped values have to match with new_sensor_MSP.h +const CapU32 OMXCameraAdapter::mSensorNames [] = { + { SENSORID_IMX060, "IMX060" }, + { SENSORID_OV5650, "OV5650" }, + { SENSORID_OV5640, "OV5640" }, + { SENSORID_OV14825, "OV14825"}, + { SENSORID_S5K4E1GA, "S5K4E1GA"}, + { SENSORID_S5K6A1GX03, "S5K6A1GX03" }, + { SENSORID_OV8830, "OV8830" }, + { SENSORID_OV2722, "OV2722" }, + { SENSORID_OV9726, "OV9726" } + // TODO(XXX): need to account for S3D camera later +}; + +const userToOMX_LUT OMXCameraAdapter::mAutoConvergence [] = { + { TICameraParameters::AUTOCONVERGENCE_MODE_DISABLE, OMX_TI_AutoConvergenceModeDisable }, + { TICameraParameters::AUTOCONVERGENCE_MODE_FRAME, OMX_TI_AutoConvergenceModeFrame }, + { TICameraParameters::AUTOCONVERGENCE_MODE_CENTER, OMX_TI_AutoConvergenceModeCenter }, + { TICameraParameters::AUTOCONVERGENCE_MODE_TOUCH, OMX_TI_AutoConvergenceModeFocusFaceTouch }, + { TICameraParameters::AUTOCONVERGENCE_MODE_MANUAL, OMX_TI_AutoConvergenceModeManual } +}; + +const LUTtype OMXCameraAdapter::mAutoConvergenceLUT = { + ARRAY_SIZE(mAutoConvergence), + mAutoConvergence +}; + +const userToOMX_LUT OMXCameraAdapter::mBracketingModes [] = { + { TICameraParameters::TEMP_BRACKETING , OMX_BracketTemporal }, + { TICameraParameters::EXPOSURE_BRACKETING , OMX_BracketExposureRelativeInEV } +}; + +const LUTtype OMXCameraAdapter::mBracketingModesLUT = { + ARRAY_SIZE(mBracketingModes), + mBracketingModes +}; + +// values for supported camera facing direction +const CapU32 OMXCameraAdapter::mFacing [] = { + { OMX_TI_SENFACING_BACK , TICameraParameters::FACING_BACK }, + { OMX_TI_SENFACING_FRONT, TICameraParameters::FACING_FRONT}, +}; + +/***************************************** + * internal static function declarations + *****************************************/ + +/**** Utility functions to help translate OMX Caps to Parameter ****/ + +status_t OMXCameraAdapter::encodeImageCodingFormatCap(OMX_IMAGE_CODINGTYPE format, + const CapCodingFormat *cap, + size_t capCount, + char * buffer) { + + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( ( NULL == buffer ) || ( NULL == cap ) ) { + CAMHAL_LOGEA("Invalid input arguments"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) { + for ( unsigned int i = 0 ; i < capCount ; i++ ) { + if ( format == cap[i].imageCodingFormat ) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, ((((int)MAX_PROP_VALUE_LENGTH - 1 - (int)strlen(buffer)) < 0) ? 0 : (MAX_PROP_VALUE_LENGTH - 1 - strlen(buffer)))); + } + strncat(buffer, cap[i].param, ((((int)MAX_PROP_VALUE_LENGTH - 1 - (int)strlen(buffer)) < 0) ? 0 : (MAX_PROP_VALUE_LENGTH - 1 - strlen(buffer)))); + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodePixelformatCap(OMX_COLOR_FORMATTYPE format, + const CapPixelformat *cap, + size_t capCount, + char * buffer, + size_t bufferSize) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( ( NULL == buffer ) || ( NULL == cap ) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + + for ( unsigned int i = 0 ; i < capCount ; i++ ) + { + if ( format == cap[i].pixelformat ) + { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize - 1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void OMXCameraAdapter::encodeFrameRates(const int minFrameRate, const int maxFrameRate, + const OMX_TI_CAPTYPE & caps, const CapFramerate * const fixedFrameRates, + const int frameRateCount, android::Vector & fpsRanges) { + LOG_FUNCTION_NAME; + + if ( minFrameRate == maxFrameRate ) { + // single fixed frame rate supported + fpsRanges.add(FpsRange(minFrameRate, maxFrameRate)); + return; + } + + // insert min and max frame rates + fpsRanges.add(FpsRange(minFrameRate, minFrameRate)); + fpsRanges.add(FpsRange(maxFrameRate, maxFrameRate)); + + // insert variable frame rates + for ( int i = 0; i < static_cast(caps.ulPrvVarFPSModesCount); ++i ) { + const FpsRange fpsRange = FpsRange( + max(androidFromDucatiFrameRate(caps.tPrvVarFPSModes[i].nVarFPSMin), minFrameRate), + min(androidFromDucatiFrameRate(caps.tPrvVarFPSModes[i].nVarFPSMax), maxFrameRate)); + + if ( fpsRange.isFixed() ) { + // this range is either min or max fixed frame rate, already added above + continue; + } + + fpsRanges.add(fpsRange); + } + + // insert fixed frame rates + for ( int i = 0; i < frameRateCount; ++i ) { + const int fixedFrameRate = fixedFrameRates[i].num * CameraHal::VFR_SCALE; + + if ( fixedFrameRate < minFrameRate || fixedFrameRate > maxFrameRate ) { + // not supported by hardware + continue; + } + + const FpsRange fpsRange = FpsRange(fixedFrameRate, fixedFrameRate); + fpsRanges.add(fpsRange); + } + + // sort first by max, then by min, according to Android API requirements + fpsRanges.sort(FpsRange::compare); + + // remove duplicated frame rates + for ( int i = 0; i < static_cast(fpsRanges.size()) - 1; ) { + const FpsRange & current = fpsRanges.itemAt(i); + const FpsRange & next = fpsRanges.itemAt(i + 1); + if ( current == next ) { + fpsRanges.removeAt(i + 1); + } else { + i++; + } + } +} + +size_t OMXCameraAdapter::encodeZoomCap(OMX_S32 maxZoom, + const CapZoom *cap, + size_t capCount, + char * buffer, + size_t bufferSize) +{ + status_t res = NO_ERROR; + size_t ret = 0; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( cap[i].num <= maxZoom ) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize - 1); + ret++; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeISOCap(OMX_U32 maxISO, + const CapISO *cap, + size_t capCount, + char * buffer, + size_t bufferSize) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( cap[i].num <= maxISO) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize - 1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeSizeCap(OMX_TI_CAPRESTYPE &res, + const CapResolution *cap, + size_t capCount, + char * buffer, + size_t bufferSize) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0 ; i < capCount ; i++ ) { + if ( (cap[i].width <= res.nWidthMax) && + (cap[i].height <= res.nHeightMax) && + (cap[i].width >= res.nWidthMin) && + (cap[i].height >= res.nHeightMin) ) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize -1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeSizeCap3D(OMX_TI_CAPRESTYPE &res, + const CapResolution *cap, + size_t capCount, + char * buffer, + size_t bufferSize) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0 ; i < capCount ; i++ ) { + if ( (cap[i].width <= res.nWidthMax) && + (cap[i].height <= res.nHeightMax) && + (cap[i].width >= res.nWidthMin) && + (cap[i].height >= res.nHeightMin) && + (cap[i].width * cap[i].height <= res.nMaxResInPixels)) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize -1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertImageSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + int s3d_detected = 0; + int s3d_ss_detected = 0; + int s3d_tb_detected = 0; + + LOG_FUNCTION_NAME; + + for ( unsigned int i = 0 ; i < caps.ulCapFrameLayoutCount; i++ ) { + if (caps.eCapFrameLayout[i] == OMX_TI_StereoFrameLayoutTopBottom) + { + s3d_tb_detected = 1; + } + else if (caps.eCapFrameLayout[i] == OMX_TI_StereoFrameLayoutLeftRight) + { + s3d_ss_detected = 1; + } + else if ( (caps.eCapFrameLayout[i] == OMX_TI_StereoFrameLayoutTopBottomSubsample) + || (caps.eCapFrameLayout[i] == OMX_TI_StereoFrameLayoutLeftRightSubsample) ) + { + s3d_detected = 1; + } + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + // Check if we are in 2d mode + if (!s3d_ss_detected && !s3d_tb_detected && !s3d_detected) + { + ret = encodeSizeCap(caps.tImageResRange, + mImageCapRes, + ARRAY_SIZE(mImageCapRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, supported); + } + params->set(CameraProperties::MAX_PICTURE_WIDTH, caps.tImageResRange.nWidthMax); + params->set(CameraProperties::MAX_PICTURE_HEIGHT, caps.tImageResRange.nHeightMax); + } + else // 3d mode + { + if (s3d_tb_detected) + { + ret = encodeSizeCap3D(caps.tImageResRange, + mImageCapResTB, + ARRAY_SIZE(mImageCapResTB), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES, supported); + } + } + else + { + params->set(CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES, supported); + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + if (s3d_ss_detected) + { + ret = encodeSizeCap3D(caps.tImageResRange, + mImageCapResSS, + ARRAY_SIZE(mImageCapResSS), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES, supported); + } + } + else + { + params->set(CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES, supported); + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + if (s3d_detected) + { + ret = encodeSizeCap3D(caps.tImageResRange, + mImageCapRes, + ARRAY_SIZE(mImageCapRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES, supported); + } + } else { + params->set(CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES, supported); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertPreviewSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + int s3d_detected = 0; + int s3d_ss_detected = 0; + int s3d_tb_detected = 0; + + LOG_FUNCTION_NAME; + + for ( unsigned int i = 0 ; i < caps.ulPrvFrameLayoutCount; i++ ) { + if (caps.ePrvFrameLayout[i] == OMX_TI_StereoFrameLayoutTopBottom) + { + s3d_tb_detected = 1; + } + else if (caps.ePrvFrameLayout[i] == OMX_TI_StereoFrameLayoutLeftRight) + { + s3d_ss_detected = 1; + } + else if ( (caps.ePrvFrameLayout[i] == OMX_TI_StereoFrameLayoutTopBottomSubsample) + || (caps.ePrvFrameLayout[i] == OMX_TI_StereoFrameLayoutLeftRightSubsample) ) + { + s3d_detected = 1; + } + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + // Check if we are in 2d mode + if (!s3d_ss_detected && !s3d_tb_detected && !s3d_detected) + { + ret = encodeSizeCap(caps.tPreviewResRange, + mPreviewRes, + ARRAY_SIZE(mPreviewRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported Landscape preview sizes 0x%x", ret); + return ret; + } + + /* Insert Portait Resolutions by verifying Potrait Capability Support */ + ret = encodeSizeCap(caps.tRotatedPreviewResRange, + mPreviewPortraitRes, + ARRAY_SIZE(mPreviewPortraitRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported Potrait preview sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, supported); + } + } + else // 3d mode + { + if (s3d_tb_detected) + { + ret = encodeSizeCap3D(caps.tPreviewResRange, + mPreviewResTB, + ARRAY_SIZE(mPreviewResTB), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported 3D TB preview sizes 0x%x", ret); + return ret; + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES, supported); + } + } + else + { + params->set(CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES, supported); + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + if (s3d_ss_detected) + { + ret = encodeSizeCap3D(caps.tPreviewResRange, + mPreviewResSS, + ARRAY_SIZE(mPreviewResSS), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported 3D SS preview sizes 0x%x", ret); + return ret; + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES, supported); + } + } + else + { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES, supported); + } + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + if (s3d_detected) + { + ret = encodeSizeCap3D(caps.tPreviewResRange, + mPreviewRes, + ARRAY_SIZE(mPreviewRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview sizes 0x%x", ret); + return ret; + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES, supported); + } + } + else + { + params->set(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES, supported); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertVideoSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeSizeCap(caps.tPreviewResRange, + mPreviewRes, + ARRAY_SIZE(mPreviewRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported video sizes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_VIDEO_SIZES, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertThumbSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeSizeCap(caps.tThumbResRange, + mThumbRes, + ARRAY_SIZE(mThumbRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported thumbnail sizes 0x%x", ret); + } else { + //CTS Requirement: 0x0 should always be supported + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, "0x0", MAX_PROP_NAME_LENGTH); + params->set(CameraProperties::SUPPORTED_THUMBNAIL_SIZES, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertZoomStages(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + size_t zoomStageCount = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + zoomStageCount = encodeZoomCap(caps.xMaxWidthZoom, + mZoomStages, + ARRAY_SIZE(mZoomStages), + supported, + MAX_PROP_VALUE_LENGTH); + + params->set(CameraProperties::SUPPORTED_ZOOM_RATIOS, supported); + params->set(CameraProperties::SUPPORTED_ZOOM_STAGES, zoomStageCount - 1); //As per CTS requirement + + if ( 0 == zoomStageCount ) { + params->set(CameraProperties::ZOOM_SUPPORTED, android::CameraParameters::FALSE); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, android::CameraParameters::FALSE); + } else { + params->set(CameraProperties::ZOOM_SUPPORTED, android::CameraParameters::TRUE); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, android::CameraParameters::TRUE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertImageFormats(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + for ( int i = 0 ; i < caps.ulImageFormatCount ; i++ ) { + ret = encodePixelformatCap(caps.eImageFormats[i], + mPixelformats, + ARRAY_SIZE(mPixelformats), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture formats 0x%x", ret); + break; + } + } + + for (int i = 0; i < caps.ulImageCodingFormatCount ; i++) { + ret = encodeImageCodingFormatCap(caps.eImageCodingFormat[i], + mImageCodingFormat, + ARRAY_SIZE(mImageCodingFormat), + supported); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture formats 0x%x", ret); + break; + } + } + + if ( NO_ERROR == ret ) { + params->set(CameraProperties::SUPPORTED_PICTURE_FORMATS, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertPreviewFormats(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( int i = 0 ; i < caps.ulPreviewFormatCount; i++ ) { + ret = encodePixelformatCap(caps.ePreviewFormats[i], + mPixelformats, + ARRAY_SIZE(mPixelformats), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview formats 0x%x", ret); + break; + } + } + + if ( NO_ERROR == ret ) { + // need to advertise we support YV12 format + // We will program preview port with NV21 when we see application set YV12 + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, android::CameraParameters::PIXEL_FORMAT_YUV420P, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PREVIEW_FORMATS, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFramerates(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + // collect supported normal frame rates + { + android::Vector fpsRanges; + + // HASH: Fix JEM Amazon Ducati xFramerates which are [1 .. 30] vs [256 .. 7680] + int minFrameRate = -1; + if (caps.xFramerateMin >= 50) + minFrameRate = max(FPS_MIN * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMin)); + else + minFrameRate = max(FPS_MIN * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMin << 8)); + int maxFrameRate = -1; + if (caps.xFramerateMax >= 50) + maxFrameRate = min(FPS_MAX * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMax)); + else + maxFrameRate = min(FPS_MAX * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMax << 8)); + + if ( minFrameRate > maxFrameRate ) { + CAMHAL_LOGE("Invalid frame rate range: [%d .. %d]", caps.xFramerateMin, caps.xFramerateMax); + return BAD_VALUE; + } + + encodeFrameRates(minFrameRate, maxFrameRate, caps, mFramerates, ARRAY_SIZE(mFramerates), fpsRanges); + + // populate variable frame rates + char supported[MAX_PROP_VALUE_LENGTH]; + char defaultRange[MAX_PROP_VALUE_LENGTH]; + + memset(supported, 0, sizeof(supported)); + memset(defaultRange, 0, sizeof(defaultRange)); + + for ( int i = 0; i < static_cast(fpsRanges.size()); ++i ) { + const FpsRange & fpsRange = fpsRanges.itemAt(i); + if ( supported[0] ) strncat(supported, PARAM_SEP, 1); + char tmp[MAX_PROP_VALUE_LENGTH]; + snprintf(tmp, sizeof(tmp) - 1, "(%d,%d)", fpsRange.min(), fpsRange.max()); + strcat(supported, tmp); + } + + const FpsRange & defaultFpsRange = fpsRanges.itemAt(fpsRanges.size() - 1); + snprintf(defaultRange, sizeof(defaultRange) - 1, "%d,%d", defaultFpsRange.min(), defaultFpsRange.max()); + + CAMHAL_LOGD("Supported framerate ranges: %s", supported); + CAMHAL_LOGD("Default framerate range: [%s]", defaultRange); + + params->set(CameraProperties::FRAMERATE_RANGE_SUPPORTED, supported); + params->set(CameraProperties::FRAMERATE_RANGE, defaultRange); + + // populate fixed frame rates + memset(supported, 0, sizeof(supported)); + memset(defaultRange, 0, sizeof(defaultRange)); + + for ( int i = 0; i < static_cast(fpsRanges.size()); ++i ) { + const FpsRange & fpsRange = fpsRanges.itemAt(i); + if ( fpsRange.isFixed() && (fpsRange.min()%CameraHal::VFR_SCALE) == 0 ) { + if ( supported[0] ) strncat(supported, PARAM_SEP, 1); + char tmp[MAX_PROP_VALUE_LENGTH]; + snprintf(tmp, sizeof(tmp) - 1, "%d", fpsRange.min()/CameraHal::VFR_SCALE); + strcat(supported, tmp); + } + } + + CAMHAL_LOGD("Supported preview framerates: %s", supported); + params->set(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES, supported); + + // insert default frame rate only if it is fixed + if ( defaultFpsRange.isFixed() && (defaultFpsRange.min()%CameraHal::VFR_SCALE) == 0 ) { + snprintf(defaultRange, sizeof(defaultRange) - 1, "%d", defaultFpsRange.min()/CameraHal::VFR_SCALE); + params->set(CameraProperties::PREVIEW_FRAME_RATE, defaultRange); + } + } + + // collect supported extended frame rates + { + android::Vector fpsRanges; + + // HASH: Fix JEM Amazon Ducati xFramerates which are [1 .. 30] vs [256 .. 7680] + int minFrameRate = -1; + if (caps.xFramerateMin >= 50) + minFrameRate = max(FPS_MIN * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMin)); + else + minFrameRate = max(FPS_MIN * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMin << 8)); + int maxFrameRate = -1; + if (caps.xFramerateMax >= 50) + maxFrameRate = min(FPS_MAX_EXTENDED * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMax)); + else + maxFrameRate = min(FPS_MAX_EXTENDED * CameraHal::VFR_SCALE, androidFromDucatiFrameRate(caps.xFramerateMax << 8)); + + encodeFrameRates(minFrameRate, maxFrameRate, caps, mFramerates, ARRAY_SIZE(mFramerates), fpsRanges); + + // populate variable frame rates + char supported[MAX_PROP_VALUE_LENGTH]; + memset(supported, 0, sizeof(supported) - 1); + + for ( int i = 0; i < static_cast(fpsRanges.size()); ++i ) { + const FpsRange & fpsRange = fpsRanges.itemAt(i); + if ( supported[0] ) strncat(supported, PARAM_SEP, 1); + char tmp[MAX_PROP_VALUE_LENGTH]; + snprintf(tmp, sizeof(tmp) - 1, "(%d,%d)", fpsRange.min(), fpsRange.max()); + strcat(supported, tmp); + } + + CAMHAL_LOGD("Supported framerate ranges extended: %s", supported); + params->set(CameraProperties::FRAMERATE_RANGE_EXT_SUPPORTED, supported); + + // populate fixed frame rates + memset(supported, 0, sizeof(supported) - 1); + + for ( int i = 0; i < static_cast(fpsRanges.size()); ++i ) { + const FpsRange & fpsRange = fpsRanges.itemAt(i); + if ( fpsRange.isFixed() && (fpsRange.min()%CameraHal::VFR_SCALE) == 0 ) { + if ( supported[0] ) strncat(supported, PARAM_SEP, 1); + char tmp[MAX_PROP_VALUE_LENGTH]; + snprintf(tmp, sizeof(tmp) - 1, "%d", fpsRange.min()/CameraHal::VFR_SCALE); + strcat(supported, tmp); + } + } + + CAMHAL_LOGD("Supported extended preview framerates: %s", supported); + params->set(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES_EXT, supported); + } + + return OK; +} + +status_t OMXCameraAdapter::insertEVs(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.xEVCompensationMin * 10 )); + params->set(CameraProperties::SUPPORTED_EV_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.xEVCompensationMax * 10 )); + params->set(CameraProperties::SUPPORTED_EV_MAX, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertISOModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeISOCap(caps.nSensitivityMax, + mISOStages, + ARRAY_SIZE(mISOStages), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported ISO modes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_ISO_VALUES, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertIPPModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + //Off is always supported + strncat(supported, TICameraParameters::IPP_NONE, MAX_PROP_NAME_LENGTH); + + if ( caps.bLensDistortionCorrectionSupported ) { + strncat(supported, PARAM_SEP, 1); + strncat(supported, TICameraParameters::IPP_LDC, MAX_PROP_NAME_LENGTH); + } + + if ( caps.bISONoiseFilterSupported ) { + strncat(supported, PARAM_SEP, 1); + strncat(supported, TICameraParameters::IPP_NSF, MAX_PROP_NAME_LENGTH); + } + + if ( caps.bISONoiseFilterSupported && caps.bLensDistortionCorrectionSupported ) { + strncat(supported, PARAM_SEP, 1); + strncat(supported, TICameraParameters::IPP_LDCNSF, MAX_PROP_NAME_LENGTH); + } + + params->set(CameraProperties::SUPPORTED_IPP_MODES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertWBModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulWhiteBalanceCount ; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eWhiteBalanceModes[i], WBalLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + params->set(CameraProperties::SUPPORTED_WHITE_BALANCE, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertEffects(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulColorEffectCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eColorEffects[i], EffLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + params->set(CameraProperties::SUPPORTED_EFFECTS, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertExpModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulExposureModeCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eExposureModes[i], ExpLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + params->set(CameraProperties::SUPPORTED_EXPOSURE_MODES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertManualExpRanges(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + if (caps.nManualExpMin > caps.nManualExpMax) { + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MAX, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_STEP, supported); + } else { + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) caps.nManualExpMin); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) caps.nManualExpMax); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_MAX, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) MANUAL_EXPOSURE_STEP); + params->set(CameraProperties::SUPPORTED_MANUAL_EXPOSURE_STEP, supported); + } + + if (MANUAL_GAIN_ISO_MIN > caps.nSensitivityMax) { + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MAX, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) 0); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_STEP, supported); } + else { + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) MANUAL_GAIN_ISO_MIN); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) caps.nSensitivityMax); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_MAX, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", (int) MANUAL_GAIN_ISO_STEP); + params->set(CameraProperties::SUPPORTED_MANUAL_GAIN_ISO_STEP, supported); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFlashModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFlashCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFlashModes[i], FlashLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + if ( strlen(supported) == 0 ) { + strncpy(supported, DEFAULT_FLASH_MODE, MAX_PROP_NAME_LENGTH); + } + + params->set(CameraProperties::SUPPORTED_FLASH_MODES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertSceneModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulSceneCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eSceneModes[i], SceneLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + params->set(CameraProperties::SUPPORTED_SCENE_MODES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFocusModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFocusModeCount; i++ ) { + getMultipleLUTvalue_OMXtoHAL(caps.eFocusModes[i], FocusLUT, supported); + } + + // Check if focus is supported by camera + if (caps.ulFocusModeCount == 1 && + caps.eFocusModes[0] == OMX_IMAGE_FocusControlOff) { + // Focus is not supported by camera + // Advertise this to app as infinitiy focus mode + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, android::CameraParameters::FOCUS_MODE_INFINITY, MAX_PROP_NAME_LENGTH); + } + + params->set(CameraProperties::SUPPORTED_FOCUS_MODES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFlickerModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFlickerCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFlicker[i], FlickerLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + + params->set(CameraProperties::SUPPORTED_ANTIBANDING, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertAreas(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + sprintf(supported, "%d", caps.ulAlgoAreasFocusCount); + params->set(CameraProperties::MAX_FOCUS_AREAS, supported); + CAMHAL_LOGDB("Maximum supported focus areas %s", supported); + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + sprintf(supported, "%d", caps.ulAlgoAreasExposureCount); + params->set(CameraProperties::MAX_NUM_METERING_AREAS, supported); + CAMHAL_LOGDB("Maximum supported exposure areas %s", supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertVNFSupported(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( OMX_TRUE == caps.bVideoNoiseFilterSupported ) { + params->set(CameraProperties::VNF_SUPPORTED, android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::VNF_SUPPORTED, android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertVSTABSupported(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( OMX_TRUE == caps.bVideoStabilizationSupported ) { + params->set(CameraProperties::VSTAB_SUPPORTED, android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::VSTAB_SUPPORTED, android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertLocks(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME + + if ( caps.bAELockSupported ) { + params->set(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED, android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED, android::CameraParameters::FALSE); + } + + if ( caps.bAWBLockSupported ) { + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED, android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED, android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +status_t OMXCameraAdapter::insertSenMount(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + unsigned int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + // 1) Look up and assign sensor name + for (i = 0; i < ARRAY_SIZE(mSensorNames); i++) { + if(mSensorNames[i].num == caps.tSenMounting.nSenId) { + // sensor found + break; + } + } + if ( i == ARRAY_SIZE(mSensorNames) ) { + p = "UNKNOWN_SENSOR"; + } else { + p = mSensorNames[i].param; + } + strncat(supported, p, REMAINING_BYTES(supported)); + params->set(CameraProperties::CAMERA_NAME, supported); + params->set(CameraProperties::CAMERA_SENSOR_ID, caps.tSenMounting.nSenId); + + // 2) Assign mounting rotation + params->set(CameraProperties::ORIENTATION_INDEX, caps.tSenMounting.nRotation); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertRaw(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + unsigned int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + sprintf(supported,"%d",int(caps.uSenNativeResWidth)); + params->set(CameraProperties::RAW_WIDTH, supported); + + memset(supported, '\0', sizeof(supported)); + if (caps.bMechanicalMisalignmentSupported) { + sprintf(supported,"%d",int(caps.uSenNativeResHeight) * 2); + } else { + sprintf(supported,"%d",int(caps.uSenNativeResHeight)); + } + params->set(CameraProperties::RAW_HEIGHT, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFacing(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + unsigned int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + for (i = 0; i < ARRAY_SIZE(mFacing); i++) { + if((OMX_TI_SENFACING_TYPE)mFacing[i].num == caps.tSenMounting.eFacing) { + break; + } + } + if ( i == ARRAY_SIZE(mFacing) ) { + p = "UNKNOWN_FACING"; + } else { + p = mFacing[i].param; + } + strncat(supported, p, REMAINING_BYTES(supported)); + params->set(CameraProperties::FACING_INDEX, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertFocalLength(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + sprintf(supported, "%d", caps.nFocalLength / 100); + strncat(supported, ".", REMAINING_BYTES(supported)); + sprintf(supported+(strlen(supported)*sizeof(char)), "%d", caps.nFocalLength % 100); + + params->set(CameraProperties::FOCAL_LENGTH, supported); + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +status_t OMXCameraAdapter::insertAutoConvergenceModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + unsigned int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + for ( unsigned int i = 0 ; i < caps.ulAutoConvModesCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eAutoConvModes[i], mAutoConvergenceLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + } + strncat(supported, p, REMAINING_BYTES(supported)); + } + } + params->set(CameraProperties::AUTOCONVERGENCE_MODE_VALUES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertManualConvergenceRange(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.nManualConvMin )); + params->set(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.nManualConvMax )); + params->set(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_MAX, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.nManualConvMax != caps.nManualConvMin )); + params->set(CameraProperties::SUPPORTED_MANUAL_CONVERGENCE_STEP, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertMechanicalMisalignmentCorrection(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + LOG_FUNCTION_NAME; + + params->set(CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED, + caps.bMechanicalMisalignmentSupported == OMX_TRUE ? + android::CameraParameters::TRUE : android::CameraParameters::FALSE); + + return OK; +} + +status_t OMXCameraAdapter::insertCaptureModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', sizeof(supported)); + + // 3D mode detect: Misalignment is present only in 3d mode + if (caps.bMechanicalMisalignmentSupported) + { + strncat(supported, TICameraParameters::HIGH_QUALITY_MODE, REMAINING_BYTES(supported)); + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::VIDEO_MODE, REMAINING_BYTES(supported)); + } + else // 2D mode detect: Misalignment is present only in 3d mode + { + strncat(supported, TICameraParameters::HIGH_QUALITY_MODE, REMAINING_BYTES(supported)); + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::VIDEO_MODE, REMAINING_BYTES(supported)); + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::HIGH_PERFORMANCE_MODE, REMAINING_BYTES(supported)); + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::HIGH_QUALITY_ZSL_MODE, REMAINING_BYTES(supported)); +#ifdef OMAP_ENHANCEMENT_CPCAM + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::CP_CAM_MODE, REMAINING_BYTES(supported)); +#endif +#ifdef CAMERAHAL_OMAP5_CAPTURE_MODES + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::VIDEO_MODE_HQ, REMAINING_BYTES(supported)); +#endif + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + strncat(supported, TICameraParameters::ZOOM_BRACKETING, REMAINING_BYTES(supported)); + } + + for ( unsigned int i = 0 ; i < caps.ulBracketingModesCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eBracketingModes[i], mBracketingModesLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, REMAINING_BYTES(supported)); + } + strncat(supported, p, REMAINING_BYTES(supported)); + } + } + + params->set(CameraProperties::CAP_MODE_VALUES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertLayout(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + unsigned int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for ( unsigned int i = 0 ; i < caps.ulPrvFrameLayoutCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.ePrvFrameLayout[i], mLayoutLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + params->set(CameraProperties::S3D_PRV_FRAME_LAYOUT_VALUES, supported); + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for ( unsigned int i = 0 ; i < caps.ulCapFrameLayoutCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eCapFrameLayout[i], mLayoutLUT); + if ( NULL != p ) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + } + } + params->set(CameraProperties::S3D_CAP_FRAME_LAYOUT_VALUES, supported); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertVideoSnapshotSupported(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if (caps.bStillCapDuringVideoSupported) + { + params->set(CameraProperties::VIDEO_SNAPSHOT_SUPPORTED, android::CameraParameters::TRUE); + } + else + { + params->set(CameraProperties::VIDEO_SNAPSHOT_SUPPORTED, android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertGBCESupported(CameraProperties::Properties* params, + const OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if (caps.bGbceSupported) { + params->set(CameraProperties::SUPPORTED_GBCE, + android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::SUPPORTED_GBCE, + android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertGLBCESupported(CameraProperties::Properties* params, + const OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if (caps.bGlbceSupported) { + params->set(CameraProperties::SUPPORTED_GLBCE, + android::CameraParameters::TRUE); + } else { + params->set(CameraProperties::SUPPORTED_GLBCE, + android::CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertDefaults(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char *pos, *str, *def; + char temp[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + /* If default is supported - set it, else - set first supported */ + if (strstr(params->get(CameraProperties::S3D_PRV_FRAME_LAYOUT_VALUES), DEFAULT_S3D_PREVIEW_LAYOUT)) { + strncpy(temp, DEFAULT_S3D_PREVIEW_LAYOUT, MAX_PROP_VALUE_LENGTH - 1); + } else { + strncpy(temp, params->get(CameraProperties::S3D_PRV_FRAME_LAYOUT_VALUES), + MAX_PROP_VALUE_LENGTH - 1); + if ((pos = strstr(temp, PARAM_SEP))) { + *pos = '\0'; + } + } + params->set(CameraProperties::S3D_PRV_FRAME_LAYOUT, temp); + + if (!strcmp(TICameraParameters::S3D_TB_FULL, temp)) { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, params->get(CameraProperties::SUPPORTED_PREVIEW_TOPBOTTOM_SIZES)); + } else if (!strcmp(TICameraParameters::S3D_SS_FULL, temp)) { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, params->get(CameraProperties::SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES)); + } else if ((!strcmp(TICameraParameters::S3D_TB_SUBSAMPLED, temp)) + || (!strcmp(TICameraParameters::S3D_SS_SUBSAMPLED, temp))) { + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, params->get(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES)); + } + + /* If default is supported - set it, else - set first supported */ + if (strstr(params->get(CameraProperties::S3D_CAP_FRAME_LAYOUT_VALUES), DEFAULT_S3D_PICTURE_LAYOUT)) { + strncpy(temp, DEFAULT_S3D_PICTURE_LAYOUT, MAX_PROP_VALUE_LENGTH - 1); + } else { + strncpy(temp, params->get(CameraProperties::S3D_CAP_FRAME_LAYOUT_VALUES), + MAX_PROP_VALUE_LENGTH - 1); + if ((pos = strstr(temp, PARAM_SEP))) { + *pos = '\0'; + } + } + params->set(CameraProperties::S3D_CAP_FRAME_LAYOUT, temp); + + if (!strcmp(TICameraParameters::S3D_TB_FULL, temp)) { + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, params->get(CameraProperties::SUPPORTED_PICTURE_TOPBOTTOM_SIZES)); + } else if (!strcmp(TICameraParameters::S3D_SS_FULL, temp)) { + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, params->get(CameraProperties::SUPPORTED_PICTURE_SIDEBYSIDE_SIZES)); + } else if ((!strcmp(TICameraParameters::S3D_TB_SUBSAMPLED, temp)) + || (!strcmp(TICameraParameters::S3D_SS_SUBSAMPLED, temp))) { + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, params->get(CameraProperties::SUPPORTED_PICTURE_SUBSAMPLED_SIZES)); + } + + params->set(CameraProperties::ANTIBANDING, DEFAULT_ANTIBANDING); + params->set(CameraProperties::BRIGHTNESS, DEFAULT_BRIGHTNESS); + params->set(CameraProperties::CONTRAST, DEFAULT_CONTRAST); + params->set(CameraProperties::EFFECT, DEFAULT_EFFECT); + params->set(CameraProperties::EV_COMPENSATION, DEFAULT_EV_COMPENSATION); + params->set(CameraProperties::SUPPORTED_EV_STEP, DEFAULT_EV_STEP); + params->set(CameraProperties::EXPOSURE_MODE, DEFAULT_EXPOSURE_MODE); + params->set(CameraProperties::FLASH_MODE, DEFAULT_FLASH_MODE); + pos = strstr(params->get(CameraProperties::SUPPORTED_FOCUS_MODES), DEFAULT_FOCUS_MODE_PREFERRED); + if ( NULL != pos ) + { + params->set(CameraProperties::FOCUS_MODE, DEFAULT_FOCUS_MODE_PREFERRED); + } + else + { + params->set(CameraProperties::FOCUS_MODE, DEFAULT_FOCUS_MODE); + } + params->set(CameraProperties::IPP, DEFAULT_IPP); + params->set(CameraProperties::GBCE, android::CameraParameters::FALSE); + params->set(CameraProperties::GLBCE, android::CameraParameters::FALSE); + params->set(CameraProperties::ISO_MODE, DEFAULT_ISO_MODE); + params->set(CameraProperties::JPEG_QUALITY, DEFAULT_JPEG_QUALITY); + params->set(CameraProperties::JPEG_THUMBNAIL_QUALITY, DEFAULT_THUMBNAIL_QUALITY); + params->set(CameraProperties::JPEG_THUMBNAIL_SIZE, DEFAULT_THUMBNAIL_SIZE); + params->set(CameraProperties::PICTURE_FORMAT, DEFAULT_PICTURE_FORMAT); + + if (!strcmp(params->get(CameraProperties::S3D_CAP_FRAME_LAYOUT), + TICameraParameters::S3D_TB_FULL)) { + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_TB_SIZE); + } else if (!strcmp(params->get(CameraProperties::S3D_CAP_FRAME_LAYOUT), + TICameraParameters::S3D_SS_FULL)) { + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_SS_SIZE); + } else { + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_SIZE); + } + + if (!strcmp(params->get(CameraProperties::S3D_PRV_FRAME_LAYOUT), + TICameraParameters::S3D_TB_FULL)) { + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_TB_SIZE); + } else if (!strcmp(params->get(CameraProperties::S3D_PRV_FRAME_LAYOUT), + TICameraParameters::S3D_SS_FULL)) { + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_SS_SIZE); + } else { + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_SIZE); + } + + params->set(CameraProperties::PREVIEW_FORMAT, DEFAULT_PREVIEW_FORMAT); + + /* Set default value if supported, otherwise set max supported value */ + strncpy(temp, params->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES), + MAX_PROP_VALUE_LENGTH - 1); + def = str = temp; + while (1) { + if ((pos = strstr(str, PARAM_SEP))) { + *pos = '\0'; + } + if (!strcmp(str, DEFAULT_FRAMERATE)) { + def = str; + break; + } + if (atoi(str) > atoi(def)) { + def = str; + } + if (pos == NULL) { + break; + } + str = pos + strlen(PARAM_SEP); + } + params->set(CameraProperties::PREVIEW_FRAME_RATE, def); + + params->set(CameraProperties::REQUIRED_PREVIEW_BUFS, DEFAULT_NUM_PREV_BUFS); + params->set(CameraProperties::REQUIRED_IMAGE_BUFS, DEFAULT_NUM_PIC_BUFS); + params->set(CameraProperties::SATURATION, DEFAULT_SATURATION); + params->set(CameraProperties::SCENE_MODE, DEFAULT_SCENE_MODE); + params->set(CameraProperties::SHARPNESS, DEFAULT_SHARPNESS); + params->set(CameraProperties::VSTAB, DEFAULT_VSTAB); + params->set(CameraProperties::VNF, DEFAULT_VNF); + params->set(CameraProperties::WHITEBALANCE, DEFAULT_WB); + params->set(CameraProperties::ZOOM, DEFAULT_ZOOM); + params->set(CameraProperties::MAX_FD_HW_FACES, DEFAULT_MAX_FD_HW_FACES); + params->set(CameraProperties::MAX_FD_SW_FACES, DEFAULT_MAX_FD_SW_FACES); + params->set(CameraProperties::AUTO_EXPOSURE_LOCK, DEFAULT_AE_LOCK); + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK, DEFAULT_AWB_LOCK); + params->set(CameraProperties::HOR_ANGLE, DEFAULT_HOR_ANGLE); + params->set(CameraProperties::VER_ANGLE, DEFAULT_VER_ANGLE); + params->set(CameraProperties::VIDEO_SIZE, DEFAULT_VIDEO_SIZE); + params->set(CameraProperties::SENSOR_ORIENTATION, DEFAULT_SENSOR_ORIENTATION); + params->set(CameraProperties::AUTOCONVERGENCE_MODE, DEFAULT_AUTOCONVERGENCE_MODE); + params->set(CameraProperties::MANUAL_CONVERGENCE, DEFAULT_MANUAL_CONVERGENCE); + params->set(CameraProperties::MECHANICAL_MISALIGNMENT_CORRECTION, DEFAULT_MECHANICAL_MISALIGNMENT_CORRECTION_MODE); + + char property[PROPERTY_VALUE_MAX]; + property_get("ro.product.manufacturer", + property, + DEFAULT_EXIF_MAKE); + property[0] = toupper(property[0]); + params->set(CameraProperties::EXIF_MAKE, property); + property_get("ro.product.model", + property, + DEFAULT_EXIF_MODEL); + property[0] = toupper(property[0]); + params->set(CameraProperties::EXIF_MODEL, property); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertCapabilities(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) { + ret = insertImageSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertPreviewSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertThumbSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertZoomStages(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertImageFormats(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertPreviewFormats(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFramerates(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertEVs(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertISOModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertIPPModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertWBModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertEffects(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertExpModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertManualExpRanges(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFlashModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertSceneModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFocusModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFlickerModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertSenMount(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertLocks(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertAreas(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertFacing(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertFocalLength(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertAutoConvergenceModes(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertManualConvergenceRange(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertMechanicalMisalignmentCorrection(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertRaw(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertCaptureModes(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertLayout(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertVideoSnapshotSupported(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertVSTABSupported(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertVNFSupported(params, caps); + } + + //NOTE: Ensure that we always call insertDefaults after inserting the supported capabilities + //as there are checks inside insertDefaults to make sure a certain default is supported + // or not + if ( NO_ERROR == ret ) { + ret = insertVideoSizes(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertGBCESupported(params, caps); + } + + if ( NO_ERROR == ret) { + ret = insertGLBCESupported(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertDefaults(params, caps); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +bool OMXCameraAdapter::_checkOmxTiCap(const OMX_TI_CAPTYPE & caps) +{ +#define CAMHAL_CHECK_OMX_TI_CAP(countVar, arrayVar) \ + do { \ + const int count = static_cast(caps.countVar); \ + const int maxSize = CAMHAL_SIZE_OF_ARRAY(caps.arrayVar); \ + if ( count < 0 || count > maxSize ) \ + { \ + CAMHAL_LOGE("OMX_TI_CAPTYPE verification failed"); \ + CAMHAL_LOGE(" variable: OMX_TI_CAPTYPE::" #countVar \ + ", value: %d, max allowed: %d", \ + count, maxSize); \ + return false; \ + } \ + } while (0) + + CAMHAL_CHECK_OMX_TI_CAP(ulPreviewFormatCount, ePreviewFormats); + CAMHAL_CHECK_OMX_TI_CAP(ulImageFormatCount, eImageFormats); + CAMHAL_CHECK_OMX_TI_CAP(ulWhiteBalanceCount, eWhiteBalanceModes); + CAMHAL_CHECK_OMX_TI_CAP(ulColorEffectCount, eColorEffects); + CAMHAL_CHECK_OMX_TI_CAP(ulFlickerCount, eFlicker); + CAMHAL_CHECK_OMX_TI_CAP(ulExposureModeCount, eExposureModes); + CAMHAL_CHECK_OMX_TI_CAP(ulFocusModeCount, eFocusModes); + CAMHAL_CHECK_OMX_TI_CAP(ulSceneCount, eSceneModes); + CAMHAL_CHECK_OMX_TI_CAP(ulFlashCount, eFlashModes); + CAMHAL_CHECK_OMX_TI_CAP(ulPrvVarFPSModesCount, tPrvVarFPSModes); + CAMHAL_CHECK_OMX_TI_CAP(ulCapVarFPSModesCount, tCapVarFPSModes); + CAMHAL_CHECK_OMX_TI_CAP(ulAutoConvModesCount, eAutoConvModes); + CAMHAL_CHECK_OMX_TI_CAP(ulBracketingModesCount, eBracketingModes); + CAMHAL_CHECK_OMX_TI_CAP(ulImageCodingFormatCount, eImageCodingFormat); + CAMHAL_CHECK_OMX_TI_CAP(ulPrvFrameLayoutCount, ePrvFrameLayout); + CAMHAL_CHECK_OMX_TI_CAP(ulCapFrameLayoutCount, eCapFrameLayout); + +#undef CAMHAL_CHECK_OMX_TI_CAP + + return true; +} + + +bool OMXCameraAdapter::_dumpOmxTiCap(const int sensorId, const OMX_TI_CAPTYPE & caps) +{ + if ( !_checkOmxTiCap(caps) ) + { + CAMHAL_LOGE("OMX_TI_CAPTYPE structure is invalid"); + return false; + } + + CAMHAL_LOGD("==================================================="); + CAMHAL_LOGD("---- Dumping OMX capabilities for sensor id: %d ----", sensorId); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulPreviewFormatCount = %d", int(caps.ulPreviewFormatCount)); + for ( int i = 0; i < int(caps.ulPreviewFormatCount); ++i ) + CAMHAL_LOGD(" ePreviewFormats[%2d] = %d", i, int(caps.ePreviewFormats[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulImageFormatCount = %d", int(caps.ulImageFormatCount)); + for ( int i = 0; i < int(caps.ulImageFormatCount); ++i ) + CAMHAL_LOGD(" eImageFormats[%2d] = %d", i, int(caps.eImageFormats[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("tPreviewResRange.nWidthMin = %d", int(caps.tPreviewResRange.nWidthMin)); + CAMHAL_LOGD("tPreviewResRange.nHeightMin = %d", int(caps.tPreviewResRange.nHeightMin)); + CAMHAL_LOGD("tPreviewResRange.nWidthMax = %d", int(caps.tPreviewResRange.nWidthMax)); + CAMHAL_LOGD("tPreviewResRange.nHeightMax = %d", int(caps.tPreviewResRange.nHeightMax)); + CAMHAL_LOGD("tPreviewResRange.nMaxResInPixels = %d", int(caps.tPreviewResRange.nMaxResInPixels)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("tRotatedPreviewResRange.nWidthMin = %d", int(caps.tRotatedPreviewResRange.nWidthMin)); + CAMHAL_LOGD("tRotatedPreviewResRange.nHeightMin = %d", int(caps.tRotatedPreviewResRange.nHeightMin)); + CAMHAL_LOGD("tRotatedPreviewResRange.nWidthMax = %d", int(caps.tRotatedPreviewResRange.nWidthMax)); + CAMHAL_LOGD("tRotatedPreviewResRange.nHeightMax = %d", int(caps.tRotatedPreviewResRange.nHeightMax)); + CAMHAL_LOGD("tRotatedPreviewResRange.nMaxResInPixels = %d", int(caps.tRotatedPreviewResRange.nMaxResInPixels)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("tImageResRange.nWidthMin = %d", int(caps.tImageResRange.nWidthMin)); + CAMHAL_LOGD("tImageResRange.nHeightMin = %d", int(caps.tImageResRange.nHeightMin)); + CAMHAL_LOGD("tImageResRange.nWidthMax = %d", int(caps.tImageResRange.nWidthMax)); + CAMHAL_LOGD("tImageResRange.nHeightMax = %d", int(caps.tImageResRange.nHeightMax)); + CAMHAL_LOGD("tImageResRange.nMaxResInPixels = %d", int(caps.tImageResRange.nMaxResInPixels)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("tThumbResRange.nWidthMin = %d", int(caps.tThumbResRange.nWidthMin)); + CAMHAL_LOGD("tThumbResRange.nHeightMin = %d", int(caps.tThumbResRange.nHeightMin)); + CAMHAL_LOGD("tThumbResRange.nWidthMax = %d", int(caps.tThumbResRange.nWidthMax)); + CAMHAL_LOGD("tThumbResRange.nHeightMax = %d", int(caps.tThumbResRange.nHeightMax)); + CAMHAL_LOGD("tThumbResRange.nMaxResInPixels = %d", int(caps.tThumbResRange.nMaxResInPixels)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulWhiteBalanceCount = %d", int(caps.ulWhiteBalanceCount)); + for ( int i = 0; i < int(caps.ulWhiteBalanceCount); ++i ) + CAMHAL_LOGD(" eWhiteBalanceModes[%2d] = 0x%08x", i, int(caps.eWhiteBalanceModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulColorEffectCount = %d", int(caps.ulColorEffectCount)); + for ( int i = 0; i < int(caps.ulColorEffectCount); ++i ) + CAMHAL_LOGD(" eColorEffects[%2d] = 0x%08x", i, int(caps.eColorEffects[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("xMaxWidthZoom = %d", int(caps.xMaxWidthZoom)); + CAMHAL_LOGD("xMaxHeightZoom = %d", int(caps.xMaxHeightZoom)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulFlickerCount = %d", int(caps.ulFlickerCount)); + for ( int i = 0; i < int(caps.ulFlickerCount); ++i ) + CAMHAL_LOGD(" eFlicker[%2d] = %d", i, int(caps.eFlicker[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulExposureModeCount = %d", int(caps.ulExposureModeCount)); + for ( int i = 0; i < int(caps.ulExposureModeCount); ++i ) + CAMHAL_LOGD(" eExposureModes[%2d] = 0x%08x", i, int(caps.eExposureModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("bLensDistortionCorrectionSupported = %d", int(caps.bLensDistortionCorrectionSupported)); + CAMHAL_LOGD("bISONoiseFilterSupported = %d", int(caps.bISONoiseFilterSupported)); + CAMHAL_LOGD("xEVCompensationMin = %d", int(caps.xEVCompensationMin)); + CAMHAL_LOGD("xEVCompensationMax = %d", int(caps.xEVCompensationMax)); + CAMHAL_LOGD("nSensitivityMax = %d", int(caps.nSensitivityMax)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulFocusModeCount = %d", int(caps.ulFocusModeCount)); + for ( int i = 0; i < int(caps.ulFocusModeCount); ++i ) + CAMHAL_LOGD(" eFocusModes[%2d] = 0x%08x", i, int(caps.eFocusModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulSceneCount = %d", int(caps.ulSceneCount)); + for ( int i = 0; i < int(caps.ulSceneCount); ++i ) + CAMHAL_LOGD(" eSceneModes[%2d] = %d", i, int(caps.eSceneModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulFlashCount = %d", int(caps.ulFlashCount)); + for ( int i = 0; i < int(caps.ulFlashCount); ++i ) + CAMHAL_LOGD(" eFlashModes[%2d] = %d", i, int(caps.eFlashModes[i])); + + CAMHAL_LOGD("xFramerateMin = %d", int(caps.xFramerateMin)); + CAMHAL_LOGD("xFramerateMax = %d", int(caps.xFramerateMax)); + CAMHAL_LOGD("bContrastSupported = %d", int(caps.bContrastSupported)); + CAMHAL_LOGD("bSaturationSupported = %d", int(caps.bSaturationSupported)); + CAMHAL_LOGD("bBrightnessSupported = %d", int(caps.bBrightnessSupported)); + CAMHAL_LOGD("bProcessingLevelSupported = %d", int(caps.bProcessingLevelSupported)); + CAMHAL_LOGD("bQFactorSupported = %d", int(caps.bQFactorSupported)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulPrvVarFPSModesCount = %d", int(caps.ulPrvVarFPSModesCount)); + for ( int i = 0; i < int(caps.ulPrvVarFPSModesCount); ++i ) + { + CAMHAL_LOGD(" tPrvVarFPSModes[%d].nVarFPSMin = %d", i, int(caps.tPrvVarFPSModes[i].nVarFPSMin)); + CAMHAL_LOGD(" tPrvVarFPSModes[%d].nVarFPSMax = %d", i, int(caps.tPrvVarFPSModes[i].nVarFPSMax)); + } + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulCapVarFPSModesCount = %d", int(caps.ulCapVarFPSModesCount)); + for ( int i = 0; i < int(caps.ulCapVarFPSModesCount); ++i ) + { + CAMHAL_LOGD(" tCapVarFPSModes[%d].nVarFPSMin = %d", i, int(caps.tCapVarFPSModes[i].nVarFPSMin)); + CAMHAL_LOGD(" tCapVarFPSModes[%d].nVarFPSMax = %d", i, int(caps.tCapVarFPSModes[i].nVarFPSMax)); + } + + CAMHAL_LOGD(""); + CAMHAL_LOGD("tSenMounting.nSenId = %d", int(caps.tSenMounting.nSenId)); + CAMHAL_LOGD("tSenMounting.nRotation = %d", int(caps.tSenMounting.nRotation)); + CAMHAL_LOGD("tSenMounting.bMirror = %d", int(caps.tSenMounting.bMirror)); + CAMHAL_LOGD("tSenMounting.bFlip = %d", int(caps.tSenMounting.bFlip)); + CAMHAL_LOGD("tSenMounting.eFacing = %d", int(caps.tSenMounting.eFacing)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulAutoConvModesCount = %d", int(caps.ulAutoConvModesCount)); + for ( int i = 0; i < int(caps.ulAutoConvModesCount); ++i ) + CAMHAL_LOGD(" eAutoConvModes[%2d] = %d", i, int(caps.eAutoConvModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulBracketingModesCount = %d", int(caps.ulBracketingModesCount)); + for ( int i = 0; i < int(caps.ulBracketingModesCount); ++i ) + CAMHAL_LOGD(" eBracketingModes[%2d] = %d", i, int(caps.eBracketingModes[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("bGbceSupported = %d", int(caps.bGbceSupported)); + CAMHAL_LOGD("bRawJpegSupported = %d", int(caps.bRawJpegSupported)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulImageCodingFormatCount = %d", int(caps.ulImageCodingFormatCount)); + for ( int i = 0; i < int(caps.ulImageCodingFormatCount); ++i ) + CAMHAL_LOGD(" eImageCodingFormat[%2d] = %d", i, int(caps.eImageCodingFormat[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("uSenNativeResWidth = %d", int(caps.uSenNativeResWidth)); + CAMHAL_LOGD("uSenNativeResHeight = %d", int(caps.uSenNativeResHeight)); + CAMHAL_LOGD("ulAlgoAreasFocusCount = %d", int(caps.ulAlgoAreasFocusCount)); + CAMHAL_LOGD("ulAlgoAreasExposureCount = %d", int(caps.ulAlgoAreasExposureCount)); + CAMHAL_LOGD("bAELockSupported = %d", int(caps.bAELockSupported)); + CAMHAL_LOGD("bAWBLockSupported = %d", int(caps.bAWBLockSupported)); + CAMHAL_LOGD("bAFLockSupported = %d", int(caps.bAFLockSupported)); + CAMHAL_LOGD("nFocalLength = %d", int(caps.nFocalLength)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulPrvFrameLayoutCount = %d", int(caps.ulPrvFrameLayoutCount)); + for ( int i = 0; i < int(caps.ulPrvFrameLayoutCount); ++i ) + CAMHAL_LOGD(" ePrvFrameLayout[%2d] = %d", i, int(caps.ePrvFrameLayout[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("ulCapFrameLayoutCount = %d", int(caps.ulCapFrameLayoutCount)); + for ( int i = 0; i < int(caps.ulCapFrameLayoutCount); ++i ) + CAMHAL_LOGD(" eCapFrameLayout[%2d] = %d", i, int(caps.eCapFrameLayout[i])); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("bVideoNoiseFilterSupported = %d", int(caps.bVideoNoiseFilterSupported )); + CAMHAL_LOGD("bVideoStabilizationSupported = %d", int(caps.bVideoStabilizationSupported )); + CAMHAL_LOGD("bStillCapDuringVideoSupported = %d", int(caps.bStillCapDuringVideoSupported )); + CAMHAL_LOGD("bMechanicalMisalignmentSupported = %d", int(caps.bMechanicalMisalignmentSupported)); + CAMHAL_LOGD("bFacePrioritySupported = %d", int(caps.bFacePrioritySupported )); + CAMHAL_LOGD("bRegionPrioritySupported = %d", int(caps.bRegionPrioritySupported )); + CAMHAL_LOGD("bGlbceSupported = %d", int(caps.bGlbceSupported)); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("nManualConvMin = %d", int(caps.nManualConvMin )); + CAMHAL_LOGD("nManualConvMax = %d", int(caps.nManualConvMax )); + CAMHAL_LOGD("nManualExpMin = %d", int(caps.nManualExpMin )); + CAMHAL_LOGD("nManualExpMax = %d", int(caps.nManualExpMax )); + CAMHAL_LOGD("nBrightnessMin = %d", int(caps.nBrightnessMin )); + CAMHAL_LOGD("nBrightnessMax = %d", int(caps.nBrightnessMax )); + CAMHAL_LOGD("nContrastMin = %d", int(caps.nContrastMin )); + CAMHAL_LOGD("nContrastMax = %d", int(caps.nContrastMax )); + CAMHAL_LOGD("nSharpnessMin = %d", int(caps.nSharpnessMin )); + CAMHAL_LOGD("nSharpnessMax = %d", int(caps.nSharpnessMax )); + CAMHAL_LOGD("nSaturationMin = %d", int(caps.nSaturationMin )); + CAMHAL_LOGD("nSaturationMax = %d", int(caps.nSaturationMax )); + + CAMHAL_LOGD(""); + CAMHAL_LOGD("------------------- end of dump -------------------"); + CAMHAL_LOGD("==================================================="); + + return true; +} + +/***************************************** + * public exposed function declarations + *****************************************/ + +status_t OMXCameraAdapter::getCaps(const int sensorId, CameraProperties::Properties* params, OMX_HANDLETYPE handle) +{ + status_t ret = NO_ERROR; + int caps_size = 0; + OMX_ERRORTYPE eError = OMX_ErrorNone; + CameraBuffer *bufferlist; + OMX_TI_CAPTYPE* caps; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + MemoryManager memMgr; + + LOG_FUNCTION_NAME; + + ret = memMgr.initialize(); + if ( ret != OK ) { + CAMHAL_LOGE("MemoryManager initialization failed, error: %d", ret); + return ret; + } + + // allocate tiler (or ion) buffer for caps (size is always a multiple of 4K) + caps_size = ((sizeof(OMX_TI_CAPTYPE)+4095)/4096)*4096; + bufferlist = memMgr.allocateBufferList(0, 0, NULL, caps_size, 1); + caps = (OMX_TI_CAPTYPE*) bufferlist[0].opaque; + + if (!caps) { + CAMHAL_LOGEB("Error allocating buffer for caps %d", eError); + ret = -ENOMEM; + goto EXIT; + } + + // initialize structures to be passed to OMX Camera + OMX_INIT_STRUCT_PTR (caps, OMX_TI_CAPTYPE); + caps->nPortIndex = OMX_ALL; + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = caps_size; + sharedBuffer.pSharedBuff = (OMX_U8 *) camera_buffer_get_omx_ptr (&bufferlist[0]); + + // Get capabilities from OMX Camera + eError = OMX_GetConfig(handle, (OMX_INDEXTYPE) OMX_TI_IndexConfigCamCapabilities, &sharedBuffer); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error during capabilities query 0x%x", eError); + ret = UNKNOWN_ERROR; + goto EXIT; + } else { + CAMHAL_LOGDA("OMX capability query success"); + } + +#ifdef CAMERAHAL_PIRANHA + char hwrotation[PROPERTY_VALUE_MAX]; + if (property_get("ro.sf.hwrotation", hwrotation, 0) > 0) { + if (caps->tSenMounting.nSenId == 306) { // front camera + caps->tSenMounting.nRotation = atoi(hwrotation); + } else { // back camera + caps->tSenMounting.nRotation = 360 - atoi(hwrotation); + } + } + // missing camera caps + if (caps->tSenMounting.nSenId == 306) { + caps->tPreviewResRange.nWidthMax = 640; + caps->tPreviewResRange.nHeightMax = 480; + caps->nFocalLength = 130; + } else { + caps->nFocalLength = 279; + } +#endif + +#ifdef CAMERAHAL_DEBUG + _dumpOmxTiCap(sensorId, *caps); +#endif + + // Translate and insert Ducati capabilities to CameraProperties + if ( NO_ERROR == ret ) { + ret = insertCapabilities(params, *caps); + } + + CAMHAL_LOGDB("sen mount id=%u", (unsigned int)caps->tSenMounting.nSenId); + CAMHAL_LOGDB("facing id=%u", (unsigned int)caps->tSenMounting.eFacing); + + EXIT: + if (bufferlist) { + memMgr.freeBufferList(bufferlist); + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXCapture.cpp b/camera/OMXCameraAdapter/OMXCapture.cpp new file mode 100644 index 0000000..afc335e --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapture.cpp @@ -0,0 +1,2098 @@ +/* + * 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. + */ + +/** +* @file OMXCapture.cpp +* +* This file contains functionality for handling image capture. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + + +namespace Ti { +namespace Camera { + +status_t OMXCameraAdapter::setParametersCapture(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + int w, h; + OMX_COLOR_FORMATTYPE pixFormat; + CodingMode codingMode = mCodingMode; + const char *valstr = NULL; + int varint = 0; + OMX_TI_STEREOFRAMELAYOUTTYPE capFrmLayout; + bool inCaptureState = false; + + LOG_FUNCTION_NAME; + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + capFrmLayout = cap->mFrameLayoutType; + setParamS3D(mCameraAdapterParameters.mImagePortIndex, + params.get(TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT)); + if (capFrmLayout != cap->mFrameLayoutType) { + mPendingCaptureSettings |= SetFormat; + } + + params.getPictureSize(&w, &h); + + if ( ( w != ( int ) cap->mWidth ) || + ( h != ( int ) cap->mHeight ) ) + { + mPendingCaptureSettings |= SetFormat; + } + + cap->mWidth = w; + cap->mHeight = h; + //TODO: Support more pixelformats + //cap->mStride = 2; + + CAMHAL_LOGVB("Image: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Image: cap.mHeight = %d", (int)cap->mHeight); + + if ((valstr = params.getPictureFormat()) != NULL) { + if (strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + mPictureFormatFromClient = android::CameraParameters::PIXEL_FORMAT_YUV422I; + } else if(strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + mPictureFormatFromClient = android::CameraParameters::PIXEL_FORMAT_YUV420SP; + } else if(strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + mPictureFormatFromClient = android::CameraParameters::PIXEL_FORMAT_RGB565; + } else if (strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_JPEG) == 0) { + CAMHAL_LOGDA("JPEG format selected"); + pixFormat = OMX_COLOR_FormatUnused; + codingMode = CodingJPEG; + mPictureFormatFromClient = android::CameraParameters::PIXEL_FORMAT_JPEG; + } else if (strcmp(valstr, TICameraParameters::PIXEL_FORMAT_JPS) == 0) { + CAMHAL_LOGDA("JPS format selected"); + pixFormat = OMX_COLOR_FormatUnused; + codingMode = CodingJPS; + mPictureFormatFromClient = TICameraParameters::PIXEL_FORMAT_JPS; + } else if (strcmp(valstr, TICameraParameters::PIXEL_FORMAT_MPO) == 0) { + CAMHAL_LOGDA("MPO format selected"); + pixFormat = OMX_COLOR_FormatUnused; + codingMode = CodingMPO; + mPictureFormatFromClient = TICameraParameters::PIXEL_FORMAT_MPO; + } else if (strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) { + CAMHAL_LOGDA("RAW Picture format selected"); + pixFormat = OMX_COLOR_FormatRawBayer10bit; + mPictureFormatFromClient = android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB; + } else { + CAMHAL_LOGEA("Invalid format, JPEG format selected as default"); + pixFormat = OMX_COLOR_FormatUnused; + codingMode = CodingJPEG; + mPictureFormatFromClient = NULL; + } + } else { + CAMHAL_LOGEA("Picture format is NULL, defaulting to JPEG"); + pixFormat = OMX_COLOR_FormatUnused; + codingMode = CodingJPEG; + mPictureFormatFromClient = NULL; + } + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + mRawCapture = false; + mYuvCapture = false; + + valstr = params.get(TICameraParameters::KEY_CAP_MODE); + if ( (!valstr || strcmp(valstr, TICameraParameters::HIGH_QUALITY_MODE) == 0) && + access(kRawImagesOutputDirPath, F_OK) != -1 ) { + mRawCapture = true; + } + + if (mRawCapture && (access(kYuvImagesOutputDirPath, F_OK) != -1)) { + pixFormat = OMX_COLOR_FormatCbYCrY; + mYuvCapture = true; + } +#endif + // JPEG capture is not supported in video mode by OMX Camera + // Set capture format to yuv422i...jpeg encode will + // be done on A9 + valstr = params.get(TICameraParameters::KEY_CAP_MODE); + if ( (valstr && ( strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) == 0 || + strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE_HQ) == 0 ) ) && + (pixFormat == OMX_COLOR_FormatUnused) ) { + CAMHAL_LOGDA("Capturing in video mode...selecting yuv422i"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + if (pixFormat != cap->mColorFormat || codingMode != mCodingMode) { + mPendingCaptureSettings |= SetFormat; + cap->mColorFormat = pixFormat; + mCodingMode = codingMode; + } + +#ifdef OMAP_ENHANCEMENT + str = params.get(TICameraParameters::KEY_TEMP_BRACKETING); + if ( ( str != NULL ) && + ( strcmp(str, android::CameraParameters::TRUE) == 0 ) ) { + + if ( !mBracketingSet ) { + mPendingCaptureSettings |= SetBurstExpBracket; + } + + mBracketingSet = true; + } else { + + if ( mBracketingSet ) { + mPendingCaptureSettings |= SetBurstExpBracket; + } + + mBracketingSet = false; + } + + if ( (str = params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE)) != NULL ) { + parseExpRange(str, mExposureBracketingValues, NULL, + mExposureGainBracketingModes, + EXP_BRACKET_RANGE, mExposureBracketingValidEntries); + if (mCapMode == OMXCameraAdapter::CP_CAM) { + mExposureBracketMode = OMX_BracketVectorShot; + } else { + mExposureBracketMode = OMX_BracketExposureRelativeInEV; + } + mPendingCaptureSettings |= SetBurstExpBracket; + } else if ( (str = params.get(TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE)) != NULL) { + parseExpRange(str, mExposureBracketingValues, mExposureGainBracketingValues, + mExposureGainBracketingModes, + EXP_BRACKET_RANGE, mExposureBracketingValidEntries); + if (mCapMode == OMXCameraAdapter::CP_CAM) { + mExposureBracketMode = OMX_BracketVectorShot; + } else { + mExposureBracketMode = OMX_BracketExposureGainAbsolute; + } + mPendingCaptureSettings |= SetBurstExpBracket; + } else { + // always set queued shot config in CPCAM mode + if (mCapMode == OMXCameraAdapter::CP_CAM) { + mExposureBracketMode = OMX_BracketVectorShot; + mPendingCaptureSettings |= SetBurstExpBracket; + } + // if bracketing was previously set...we set again before capturing to clear + if (mExposureBracketingValidEntries) { + mPendingCaptureSettings |= SetBurstExpBracket; + mExposureBracketingValidEntries = 0; + } + } + + str = params.get(TICameraParameters::KEY_ZOOM_BRACKETING_RANGE); + if ( NULL != str ) { + parseExpRange(str, mZoomBracketingValues, NULL, NULL, + ZOOM_BRACKET_RANGE, mZoomBracketingValidEntries); + mCurrentZoomBracketing = 0; + mZoomBracketingEnabled = true; + } else { + if (mZoomBracketingValidEntries) { + mZoomBracketingValidEntries = 0; + } + mZoomBracketingEnabled = false; + } +#endif + + // Flush config queue + // If TRUE: Flush queue and abort processing before enqueing + valstr = params.get(TICameraParameters::KEY_FLUSH_SHOT_CONFIG_QUEUE); + if ( NULL != valstr ) { + if ( 0 == strcmp(valstr, android::CameraParameters::TRUE) ) { + mFlushShotConfigQueue = true; + } else if ( 0 == strcmp(valstr, android::CameraParameters::FALSE) ) { + mFlushShotConfigQueue = false; + } else { + CAMHAL_LOGE("Missing flush shot config parameter. Will use current (%s)", + mFlushShotConfigQueue ? "true" : "false"); + } + } + + if ( params.getInt(android::CameraParameters::KEY_ROTATION) != -1 ) + { + if (params.getInt(android::CameraParameters::KEY_ROTATION) != (int) mPictureRotation) { + mPendingCaptureSettings |= SetRotation; + } + if (cap->mFrameLayoutType == OMX_TI_StereoFrameLayout2D) { + mPictureRotation = params.getInt(android::CameraParameters::KEY_ROTATION); + } else { + mPictureRotation = 0; + } + } + else + { + if (mPictureRotation) mPendingCaptureSettings |= SetRotation; + mPictureRotation = 0; + } + + CAMHAL_LOGVB("Picture Rotation set %d", mPictureRotation); + +#ifdef OMAP_ENHANCEMENT + // Read Sensor Orientation and set it based on perating mode + varint = params.getInt(TICameraParameters::KEY_SENSOR_ORIENTATION); + if ( varint != -1 ) + { + mSensorOrientation = varint; + if (mSensorOrientation == 270 ||mSensorOrientation==90) + { + CAMHAL_LOGEA(" Orientation is 270/90. So setting counter rotation to Ducati"); + mSensorOrientation +=180; + mSensorOrientation%=360; + } + } + else + { + mSensorOrientation = 0; + } + + CAMHAL_LOGVB("Sensor Orientation set : %d", mSensorOrientation); +#endif + +#ifdef OMAP_ENHANCEMENT_BURST_CAPTURE + varint = params.getInt(TICameraParameters::KEY_BURST); + if ( varint >= 1 ) + { + if (varint != (int) mBurstFrames) { + mPendingCaptureSettings |= SetBurstExpBracket; + } + mBurstFrames = varint; + } + else + { + if (mBurstFrames != 1) mPendingCaptureSettings |= SetBurstExpBracket; + mBurstFrames = 1; + } + + CAMHAL_LOGVB("Burst Frames set %d", mBurstFrames); +#endif + + varint = params.getInt(android::CameraParameters::KEY_JPEG_QUALITY); + if ( varint >= MIN_JPEG_QUALITY && varint <= MAX_JPEG_QUALITY ) { + if (varint != mPictureQuality) { + mPendingCaptureSettings |= SetQuality; + mPictureQuality = varint; + } + } else { + if (mPictureQuality != MAX_JPEG_QUALITY) { + mPendingCaptureSettings |= SetQuality; + mPictureQuality = MAX_JPEG_QUALITY; + } + } + + CAMHAL_LOGVB("Picture Quality set %d", mPictureQuality); + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + if ( varint >= 0 ) { + if (varint != mThumbWidth) { + mPendingCaptureSettings |= SetThumb; + mThumbWidth = varint; + } + } else { + if (mThumbWidth != DEFAULT_THUMB_WIDTH) { + mPendingCaptureSettings |= SetThumb; + mThumbWidth = DEFAULT_THUMB_WIDTH; + } + } + + CAMHAL_LOGVB("Picture Thumb width set %d", mThumbWidth); + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + if ( varint >= 0 ) { + if (varint != mThumbHeight) { + mPendingCaptureSettings |= SetThumb; + mThumbHeight = varint; + } + } else { + if (mThumbHeight != DEFAULT_THUMB_HEIGHT) { + mPendingCaptureSettings |= SetThumb; + mThumbHeight = DEFAULT_THUMB_HEIGHT; + } + } + + CAMHAL_LOGVB("Picture Thumb height set %d", mThumbHeight); + + varint = params.getInt(android::CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + if ( varint >= MIN_JPEG_QUALITY && varint <= MAX_JPEG_QUALITY ) { + if (varint != mThumbQuality) { + mPendingCaptureSettings |= SetThumb; + mThumbQuality = varint; + } + } else { + if (mThumbQuality != MAX_JPEG_QUALITY) { + mPendingCaptureSettings |= SetThumb; + mThumbQuality = MAX_JPEG_QUALITY; + } + } + + CAMHAL_LOGDB("Thumbnail Quality set %d", mThumbQuality); + + if (mFirstTimeInit) { + mPendingCaptureSettings = ECapturesettingsAll; + } + + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex]; + cap->mWidth = params.getInt(TICameraParameters::RAW_WIDTH); + cap->mHeight = params.getInt(TICameraParameters::RAW_HEIGHT); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters *imgCaptureData = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + + // If any settings have changed that need to be set with SetParam, + // we will need to disable the port to set them + if ((mPendingCaptureSettings & ECaptureParamSettings)) { + disableImagePort(); + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + } + + if (mPendingCaptureSettings & SetFormat) { + ret = setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *imgCaptureData); + } + + if ( ret == NO_ERROR ) + { + frame.mLength = imgCaptureData->mBufSize; + frame.mWidth = imgCaptureData->mWidth; + frame.mHeight = imgCaptureData->mHeight; + frame.mAlignment = imgCaptureData->mStride; + CAMHAL_LOGDB("getPictureBufferSize: width:%u height:%u alignment:%u length:%u", + frame.mWidth, frame.mHeight, frame.mAlignment, frame.mLength); + } + else + { + CAMHAL_LOGEB("setFormat() failed 0x%x", ret); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int OMXCameraAdapter::getBracketingValueMode(const char *a, const char *b) const +{ + BracketingValueMode bvm = BracketingValueAbsolute; + + if ( (NULL != b) && + (NULL != a) && + (a < b) && + ( (NULL != memchr(a, '+', b - a)) || + (NULL != memchr(a, '-', b - a)) ) ) { + bvm = BracketingValueRelative; + } + return bvm; +} + +status_t OMXCameraAdapter::parseExpRange(const char *rangeStr, + int *expRange, + int *gainRange, + int *expGainModes, + size_t count, + size_t &validEntries) +{ + status_t ret = NO_ERROR; + char *end = NULL; + const char *startPtr = NULL; + size_t i = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == rangeStr ){ + return -EINVAL; + } + + if ( NULL == expRange ){ + return -EINVAL; + } + + if ( NO_ERROR == ret ) { + startPtr = rangeStr; + do { + // Relative Exposure example: "-30,-10, 0, 10, 30" + // Absolute Gain ex. (exposure,gain) pairs: "(100,300),(200,300),(400,300),(800,300),(1600,300)" + // Relative Gain ex. (exposure,gain) pairs: "(-30,+0),(-10, +0),(+0,+0),(+10,+0),(+30,+0)" + // Forced relative Exposure example: "-30F,-10F, 0F, 10F, 30F" + // Forced absolute Gain ex. (exposure,gain) pairs: "(100,300)F,(200,300)F,(400,300)F,(800,300)F,(1600,300)F" + // Forced relative Gain ex. (exposure,gain) pairs: "(-30,+0)F,(-10, +0)F,(+0,+0)F,(+10,+0)F,(+30,+0)F" + + // skip '(' and ',' + while ((*startPtr == '(') || (*startPtr == ',')) startPtr++; + + expRange[i] = (int)strtol(startPtr, &end, 10); + + if (expGainModes) { + // if gainRange is given rangeStr should be (exposure, gain) pair + if (gainRange) { + int bvm_exp = getBracketingValueMode(startPtr, end); + startPtr = end + 1; // for the ',' + gainRange[i] = (int)strtol(startPtr, &end, 10); + + if (BracketingValueAbsolute == bvm_exp) { + expGainModes[i] = getBracketingValueMode(startPtr, end); + } else { + expGainModes[i] = bvm_exp; + } + } else { + expGainModes[i] = BracketingValueCompensation; + } + } + startPtr = end; + + // skip ')' + while (*startPtr == ')') startPtr++; + + // Check for "forced" key + if (expGainModes) { + while ((*startPtr == 'F') || (*startPtr == 'f')) { + if ( BracketingValueAbsolute == expGainModes[i] ) { + expGainModes[i] = BracketingValueAbsoluteForced; + } else if ( BracketingValueRelative == expGainModes[i] ) { + expGainModes[i] = BracketingValueRelativeForced; + } else if ( BracketingValueCompensation == expGainModes[i] ) { + expGainModes[i] = BracketingValueCompensationForced; + } else { + CAMHAL_LOGE("Unexpected old mode 0x%x", expGainModes[i]); + } + startPtr++; + } + } + + i++; + + } while ((startPtr[0] != '\0') && (i < count)); + validEntries = i; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doExposureBracketing(int *evValues, + int *evValues2, + int *evModes2, + size_t evCount, + size_t frameCount, + bool flush, + OMX_BRACKETMODETYPE bracketMode) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NULL == evValues ) { + CAMHAL_LOGEA("Exposure compensation values pointer is invalid"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) { + if (bracketMode == OMX_BracketVectorShot) { + ret = setVectorShot(evValues, evValues2, evModes2, evCount, frameCount, flush, bracketMode); + } else { + ret = setExposureBracketing(evValues, evValues2, evCount, frameCount, bracketMode); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setVectorStop(bool toPreview) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_VECTSHOTSTOPMETHODTYPE vecShotStop; + + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR(&vecShotStop, OMX_TI_CONFIG_VECTSHOTSTOPMETHODTYPE); + + vecShotStop.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + if (toPreview) { + vecShotStop.eStopMethod = OMX_TI_VECTSHOTSTOPMETHOD_GOTO_PREVIEW; + } else { + vecShotStop.eStopMethod = OMX_TI_VECTSHOTSTOPMETHOD_WAIT_IN_CAPTURE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigVectShotStopMethod, + &vecShotStop); + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while configuring bracket shot 0x%x", eError); + } else { + CAMHAL_LOGDA("Bracket shot configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::initVectorShot() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAPTUREMODETYPE expCapMode; + OMX_CONFIG_EXTCAPTUREMODETYPE extExpCapMode; + + LOG_FUNCTION_NAME; + + if (NO_ERROR == ret) { + OMX_INIT_STRUCT_PTR (&expCapMode, OMX_CONFIG_CAPTUREMODETYPE); + expCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + expCapMode.bFrameLimited = OMX_FALSE; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCaptureMode, + &expCapMode); + if (OMX_ErrorNone != eError) { + CAMHAL_LOGEB("Error while configuring capture mode 0x%x", eError); + goto exit; + } else { + CAMHAL_LOGDA("Camera capture mode configured successfully"); + } + } + + if (NO_ERROR == ret) { + OMX_INIT_STRUCT_PTR (&extExpCapMode, OMX_CONFIG_EXTCAPTUREMODETYPE); + extExpCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + extExpCapMode.bEnableBracketing = OMX_TRUE; + extExpCapMode.tBracketConfigType.eBracketMode = OMX_BracketVectorShot; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigExtCaptureMode, + &extExpCapMode); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring extended capture mode 0x%x", eError); + goto exit; + } else { + CAMHAL_LOGDA("Extended camera capture mode configured successfully"); + } + } + + + if (NO_ERROR == ret) { + // set vector stop method to stop in capture + ret = setVectorStop(false); + } + + exit: + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::setVectorShot(int *evValues, + int *evValues2, + int *evModes2, + size_t evCount, + size_t frameCount, + bool flush, + OMX_BRACKETMODETYPE bracketMode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_ENQUEUESHOTCONFIGS enqueueShotConfigs; + OMX_TI_CONFIG_QUERYAVAILABLESHOTS queryAvailableShots; + bool doFlush = flush; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR(&enqueueShotConfigs, OMX_TI_CONFIG_ENQUEUESHOTCONFIGS); + OMX_INIT_STRUCT_PTR(&queryAvailableShots, OMX_TI_CONFIG_QUERYAVAILABLESHOTS); + + queryAvailableShots.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigQueryAvailableShots, + &queryAvailableShots); + if (OMX_ErrorNone != eError) { + CAMHAL_LOGE("Error getting available shots 0x%x", eError); + goto exit; + } else { + CAMHAL_LOGD("AVAILABLE SHOTS: %d", queryAvailableShots.nAvailableShots); + if (queryAvailableShots.nAvailableShots < evCount) { + // TODO(XXX): Need to implement some logic to handle this error + CAMHAL_LOGE("Not enough available shots to fulfill this queue request"); + ret = -ENOSPC; + goto exit; + } + } + + for ( unsigned int confID = 0; confID < evCount; ) { + unsigned int i; + for ( i = 0 ; (i < ARRAY_SIZE(enqueueShotConfigs.nShotConfig)) && (confID < evCount); i++, confID++ ) { + CAMHAL_LOGD("%2u: (%7d,%4d) mode: %d", confID, evValues[confID], evValues2[confID], evModes2[confID]); + enqueueShotConfigs.nShotConfig[i].nConfigId = confID; + enqueueShotConfigs.nShotConfig[i].nFrames = 1; + if ( (BracketingValueCompensation == evModes2[confID]) || + (BracketingValueCompensationForced == evModes2[confID]) ) { + // EV compensation + enqueueShotConfigs.nShotConfig[i].nEC = evValues[confID]; + enqueueShotConfigs.nShotConfig[i].nExp = 0; + enqueueShotConfigs.nShotConfig[i].nGain = 0; + } else { + // exposure,gain pair + enqueueShotConfigs.nShotConfig[i].nEC = 0; + enqueueShotConfigs.nShotConfig[i].nExp = evValues[confID]; + enqueueShotConfigs.nShotConfig[i].nGain = evValues2[confID]; + } + enqueueShotConfigs.nShotConfig[i].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_ABSOLUTE; + switch (evModes2[confID]) { + case BracketingValueAbsolute: // (exp,gain) pairs directly program sensor values + default : + enqueueShotConfigs.nShotConfig[i].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_ABSOLUTE; + break; + case BracketingValueRelative: // (exp,gain) pairs relative to AE settings and constraints + case BracketingValueCompensation: // EV compensation relative to AE settings and constraints + enqueueShotConfigs.nShotConfig[i].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_RELATIVE; + break; + case BracketingValueAbsoluteForced: // (exp,gain) pairs directly program sensor values + // are forced over constraints due to flicker, etc. + enqueueShotConfigs.nShotConfig[i].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_FORCE_ABSOLUTE; + break; + case BracketingValueRelativeForced: // (exp, gain) pairs relative to AE settings AND settings + case BracketingValueCompensationForced: // EV compensation relative to AE settings and constraints + // are forced over constraints due to flicker, etc. + enqueueShotConfigs.nShotConfig[i].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_FORCE_RELATIVE; + break; + } + enqueueShotConfigs.nShotConfig[i].bNoSnapshot = OMX_FALSE; // TODO: Make this configurable + } + + // Repeat last exposure and again + if ((confID == evCount) && (evCount > 0) && (frameCount > evCount) && (0 != i)) { + enqueueShotConfigs.nShotConfig[i-1].nFrames = frameCount - evCount; + } + + enqueueShotConfigs.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + enqueueShotConfigs.bFlushQueue = doFlush ? OMX_TRUE : OMX_FALSE; + enqueueShotConfigs.nNumConfigs = i; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigEnqueueShotConfigs, + &enqueueShotConfigs); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring enqueue shot 0x%x", eError); + goto exit; + } else { + CAMHAL_LOGDA("Enqueue shot configured successfully"); + } + // Flush only first time + doFlush = false; + } + + // Handle burst capture (no any bracketing) case + if (0 == evCount) { + CAMHAL_LOGE("Handle burst capture (no any bracketing) case"); + enqueueShotConfigs.nShotConfig[0].nConfigId = 0; + enqueueShotConfigs.nShotConfig[0].nFrames = frameCount; + enqueueShotConfigs.nShotConfig[0].nEC = 0; + enqueueShotConfigs.nShotConfig[0].nExp = 0; + enqueueShotConfigs.nShotConfig[0].nGain = 0; + enqueueShotConfigs.nShotConfig[0].eExpGainApplyMethod = OMX_TI_EXPGAINAPPLYMETHOD_RELATIVE; + enqueueShotConfigs.nShotConfig[0].bNoSnapshot = OMX_FALSE; // TODO: Make this configurable + enqueueShotConfigs.nNumConfigs = 1; + enqueueShotConfigs.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + enqueueShotConfigs.bFlushQueue = doFlush ? OMX_TRUE : OMX_FALSE; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigEnqueueShotConfigs, + &enqueueShotConfigs); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring enqueue shot 0x%x", eError); + goto exit; + } else { + CAMHAL_LOGDA("Enqueue shot configured successfully"); + } + } + + exit: + LOG_FUNCTION_NAME_EXIT; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::setExposureBracketing(int *evValues, + int *evValues2, + size_t evCount, + size_t frameCount, + OMX_BRACKETMODETYPE bracketMode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAPTUREMODETYPE expCapMode; + OMX_CONFIG_EXTCAPTUREMODETYPE extExpCapMode; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&expCapMode, OMX_CONFIG_CAPTUREMODETYPE); + expCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + /// If frameCount>0 but evCount<=0, then this is the case of HQ burst. + //Otherwise, it is normal HQ capture + ///If frameCount>0 and evCount>0 then this is the cause of HQ Exposure bracketing. + if ( 0 == evCount && 0 == frameCount ) + { + expCapMode.bFrameLimited = OMX_FALSE; + } + else + { + expCapMode.bFrameLimited = OMX_TRUE; + expCapMode.nFrameLimit = frameCount; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCaptureMode, + &expCapMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring capture mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera capture mode configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&extExpCapMode, OMX_CONFIG_EXTCAPTUREMODETYPE); + extExpCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + if ( 0 == evCount ) + { + extExpCapMode.bEnableBracketing = OMX_FALSE; + } + else + { + extExpCapMode.bEnableBracketing = OMX_TRUE; + extExpCapMode.tBracketConfigType.eBracketMode = bracketMode; + extExpCapMode.tBracketConfigType.nNbrBracketingValues = evCount - 1; + } + + for ( unsigned int i = 0 ; i < evCount ; i++ ) + { + if (bracketMode == OMX_BracketExposureGainAbsolute) { + extExpCapMode.tBracketConfigType.nBracketValues[i] = evValues[i]; + extExpCapMode.tBracketConfigType.nBracketValues2[i] = evValues2[i]; + } else { + // assuming OMX_BracketExposureRelativeInEV + extExpCapMode.tBracketConfigType.nBracketValues[i] = ( evValues[i] * ( 1 << Q16_OFFSET ) ) / 10; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigExtCaptureMode, + &extExpCapMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring extended capture mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Extended camera capture mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setShutterCallback(bool enabled) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CALLBACKREQUESTTYPE shutterRequstCallback; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&shutterRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); + shutterRequstCallback.nPortIndex = OMX_ALL; + + if ( enabled ) + { + shutterRequstCallback.bEnable = OMX_TRUE; + shutterRequstCallback.nIndex = ( OMX_INDEXTYPE ) OMX_TI_IndexConfigShutterCallback; + CAMHAL_LOGDA("Enabling shutter callback"); + } + else + { + shutterRequstCallback.bEnable = OMX_FALSE; + shutterRequstCallback.nIndex = ( OMX_INDEXTYPE ) OMX_TI_IndexConfigShutterCallback; + CAMHAL_LOGDA("Disabling shutter callback"); + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCallbackRequest, + &shutterRequstCallback); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error registering shutter callback 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("Shutter callback for index 0x%x registered successfully", + OMX_TI_IndexConfigShutterCallback); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doBracketing(OMX_BUFFERHEADERTYPE *pBuffHeader, + CameraFrame::FrameType typeOfFrame) +{ + status_t ret = NO_ERROR; + int currentBufferIdx, nextBufferIdx; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + CameraBuffer *buffer = (CameraBuffer *)pBuffHeader->pAppPrivate; + currentBufferIdx = buffer->index; + + if ( currentBufferIdx >= imgCaptureData->mNumBufs) + { + CAMHAL_LOGEB("Invalid bracketing buffer index 0x%x", currentBufferIdx); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) + { + mBracketingBuffersQueued[currentBufferIdx] = false; + mBracketingBuffersQueuedCount--; + + if ( 0 >= mBracketingBuffersQueuedCount ) + { + nextBufferIdx = ( currentBufferIdx + 1 ) % imgCaptureData->mNumBufs; + mBracketingBuffersQueued[nextBufferIdx] = true; + mBracketingBuffersQueuedCount++; + mLastBracetingBufferIdx = nextBufferIdx; + setFrameRefCountByType((CameraBuffer *)imgCaptureData->mBufferHeader[nextBufferIdx]->pAppPrivate, typeOfFrame, 1); + returnFrame((CameraBuffer *)imgCaptureData->mBufferHeader[nextBufferIdx]->pAppPrivate, typeOfFrame); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::sendBracketFrames(size_t &framesSent) +{ + status_t ret = NO_ERROR; + int currentBufferIdx; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + framesSent = 0; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + + currentBufferIdx = mLastBracetingBufferIdx; + do + { + currentBufferIdx++; + currentBufferIdx %= imgCaptureData->mNumBufs; + if (!mBracketingBuffersQueued[currentBufferIdx] ) + { + CameraFrame cameraFrame; + sendCallBacks(cameraFrame, + imgCaptureData->mBufferHeader[currentBufferIdx], + imgCaptureData->mImageType, + imgCaptureData); + framesSent++; + } + } while ( currentBufferIdx != mLastBracetingBufferIdx ); + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startBracketing(int range) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + { + android::AutoMutex lock(mBracketingLock); + + if ( mBracketingEnabled ) + { + return ret; + } + } + + if ( 0 == imgCaptureData->mNumBufs ) + { + CAMHAL_LOGEB("Image capture buffers set to %d", imgCaptureData->mNumBufs); + ret = -EINVAL; + } + + if ( mPending3Asettings ) + apply3Asettings(mParameters3A); + + if ( NO_ERROR == ret ) + { + android::AutoMutex lock(mBracketingLock); + + mBracketingRange = range; + mBracketingBuffersQueued = new bool[imgCaptureData->mNumBufs]; + if ( NULL == mBracketingBuffersQueued ) + { + CAMHAL_LOGEA("Unable to allocate bracketing management structures"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + mBracketingBuffersQueuedCount = imgCaptureData->mNumBufs; + mBurstFramesAccum = imgCaptureData->mNumBufs; + mLastBracetingBufferIdx = mBracketingBuffersQueuedCount - 1; + + for ( int i = 0 ; i < imgCaptureData->mNumBufs ; i++ ) + { + mBracketingBuffersQueued[i] = true; + } + + } + } + + if ( NO_ERROR == ret ) + { + CachedCaptureParameters* cap_params = cacheCaptureParameters(); + ret = startImageCapture(true, cap_params); + delete cap_params; + { + android::AutoMutex lock(mBracketingLock); + + if ( NO_ERROR == ret ) + { + mBracketingEnabled = true; + } + else + { + mBracketingEnabled = false; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + ret = stopImageCapture(); + + android::AutoMutex lock(mBracketingLock); + + if ( NULL != mBracketingBuffersQueued ) + { + delete [] mBracketingBuffersQueued; + } + + mBracketingBuffersQueued = NULL; + mBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mLastBracetingBufferIdx = 0; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startImageCapture(bool bracketing, CachedCaptureParameters* capParams) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * capData = NULL; + OMX_CONFIG_BOOLEANTYPE bOMX; + size_t bracketingSent = 0; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mImageCaptureLock); + + if(!mCaptureConfigured) + { + ///Image capture was cancelled before we could start + return NO_ERROR; + } + + if ( 0 != mStartCaptureSem.Count() ) + { + CAMHAL_LOGEB("Error mStartCaptureSem semaphore count %d", mStartCaptureSem.Count()); + return NO_INIT; + } + + if ( !bracketing ) { + if ((getNextState() & (CAPTURE_ACTIVE|BRACKETING_ACTIVE)) == 0) { + CAMHAL_LOGDA("trying starting capture when already canceled"); + return NO_ERROR; + } + } + + if (!capParams) { + CAMHAL_LOGE("Invalid cached parameters sent!"); + return BAD_VALUE; + } + + // Camera framework doesn't expect face callbacks once capture is triggered + pauseFaceDetection(true); + + //During bracketing image capture is already active + { + android::AutoMutex lock(mBracketingLock); + if ( mBracketingEnabled ) + { + //Stop bracketing, activate normal burst for the remaining images + mBracketingEnabled = false; + ret = sendBracketFrames(bracketingSent); + + // Check if we accumulated enough buffers + if ( bracketingSent < ( mBracketingRange - 1 ) ) + { + mCapturedFrames = mBracketingRange + ( ( mBracketingRange - 1 ) - bracketingSent ); + } + else + { + mCapturedFrames = mBracketingRange; + } + mBurstFramesQueued = 0; + mBurstFramesAccum = mCapturedFrames; + + if(ret != NO_ERROR) + goto EXIT; + else + return ret; + } + } + + if ( NO_ERROR == ret ) { + if (capParams->mPendingCaptureSettings & SetRotation) { + mPendingCaptureSettings &= ~SetRotation; + ret = setPictureRotation(mPictureRotation); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error configuring image rotation %x", ret); + } + } + + if (capParams->mPendingCaptureSettings & SetBurstExpBracket) { + mPendingCaptureSettings &= ~SetBurstExpBracket; + if ( mBracketingSet ) { + ret = doExposureBracketing(capParams->mExposureBracketingValues, + capParams->mExposureGainBracketingValues, + capParams->mExposureGainBracketingModes, + 0, + 0, + capParams->mFlushShotConfigQueue, + capParams->mExposureBracketMode); + } else { + ret = doExposureBracketing(capParams->mExposureBracketingValues, + capParams->mExposureGainBracketingValues, + capParams->mExposureGainBracketingModes, + capParams->mExposureBracketingValidEntries, + capParams->mBurstFrames, + capParams->mFlushShotConfigQueue, + capParams->mExposureBracketMode); + } + + if ( ret != NO_ERROR ) { + CAMHAL_LOGEB("setExposureBracketing() failed %d", ret); + goto EXIT; + } + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + CameraHal::PPM("startImageCapture bracketing configs done: ", &mStartCapture); +#endif + + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + //OMX shutter callback events are only available in hq mode + if ( (HIGH_QUALITY == mCapMode) || (HIGH_QUALITY_ZSL== mCapMode)) { + if ( NO_ERROR == ret ) + { + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + mStartCaptureSem); + } + + if ( NO_ERROR == ret ) + { + ret = setShutterCallback(true); + } + + } + + if (mPending3Asettings) { + apply3Asettings(mParameters3A); + } + + if (ret == NO_ERROR) { + int index = 0; + int queued = 0; + android::AutoMutex lock(mBurstLock); + + if (capParams->mFlushShotConfigQueue) { + // reset shot queue + mCapturedFrames = mBurstFrames; + mBurstFramesAccum = mBurstFrames; + mBurstFramesQueued = 0; + for ( int index = 0 ; index < capData->mNumBufs ; index++ ) { + if (OMXCameraPortParameters::FILL == capData->mStatus[index]) { + mBurstFramesQueued++; + } + } + } else { + mCapturedFrames += mBurstFrames; + mBurstFramesAccum += mBurstFrames; + } + CAMHAL_LOGD("mBurstFramesQueued = %d mBurstFramesAccum = %d index = %d " + "capData->mNumBufs = %d queued = %d capData->mMaxQueueable = %d", + mBurstFramesQueued,mBurstFramesAccum,index, + capData->mNumBufs,queued,capData->mMaxQueueable); + CAMHAL_LOGD("%d", (mBurstFramesQueued < mBurstFramesAccum) + && (index < capData->mNumBufs) + && (queued < capData->mMaxQueueable)); + while ((mBurstFramesQueued < mBurstFramesAccum) && + (index < capData->mNumBufs) && + (queued < capData->mMaxQueueable)) { + if (capData->mStatus[index] == OMXCameraPortParameters::IDLE) { + CAMHAL_LOGDB("Queuing buffer on Capture port - %p", + capData->mBufferHeader[index]->pBuffer); + capData->mStatus[index] = OMXCameraPortParameters::FILL; + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)capData->mBufferHeader[index]); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + mBurstFramesQueued++; + queued++; + } else if (OMXCameraPortParameters::FILL == capData->mStatus[index]) { + CAMHAL_LOGE("Not queueing index = %d", index); + queued++; + } + index++; + } + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + if (mRawCapture) { + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex]; + + ///Queue all the buffers on capture port + for ( int index = 0 ; index < capData->mNumBufs ; index++ ) { + CAMHAL_LOGDB("Queuing buffer on Video port (for RAW capture) - 0x%x", ( unsigned int ) capData->mBufferHeader[index]->pBuffer); + capData->mStatus[index] = OMXCameraPortParameters::FILL; + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)capData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } +#endif + + mWaitingForSnapshot = true; + mCaptureSignalled = false; + + // Capturing command is not needed when capturing in video mode + // Only need to queue buffers on image ports + if ( ( mCapMode != VIDEO_MODE ) && ( mCapMode != VIDEO_MODE_HQ ) ) { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + bOMX.bEnabled = OMX_TRUE; + + /// sending Capturing Command to the component + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCapturing, + &bOMX); + + CAMHAL_LOGDB("Capture set - 0x%x", eError); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + CameraHal::PPM("startImageCapture image buffers queued and capture enabled: ", &mStartCapture); +#endif + + //OMX shutter callback events are only available in hq mode + + if ( (HIGH_QUALITY == mCapMode) || (HIGH_QUALITY_ZSL== mCapMode)) + { + if ( NO_ERROR == ret ) + { + ret = mStartCaptureSem.WaitTimeout(OMX_CAPTURE_TIMEOUT); + } + + //If something bad happened while we wait + if (mComponentState != OMX_StateExecuting) + { + CAMHAL_LOGEA("Invalid State after Image Capture Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Shutter callback received"); + notifyShutterSubscribers(); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + NULL); + CAMHAL_LOGEA("Timeout expired on shutter callback"); + goto EXIT; + } + + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + CameraHal::PPM("startImageCapture shutter event received: ", &mStartCapture); +#endif + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + mWaitingForSnapshot = false; + mCaptureSignalled = false; + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::stopImageCapture() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE bOMX; + OMXCameraPortParameters *imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mImageCaptureLock); + + if (!mCaptureConfigured) { + //Capture is not ongoing, return from here + return NO_ERROR; + } + + if ( 0 != mStopCaptureSem.Count() ) { + CAMHAL_LOGEB("Error mStopCaptureSem semaphore count %d", mStopCaptureSem.Count()); + goto EXIT; + } + + // TODO(XXX): Reprocessing is currently piggy-backing capture commands + if (mAdapterState == REPROCESS_STATE) { + ret = stopReprocess(); + } + + //Disable the callback first + mWaitingForSnapshot = false; + + // OMX shutter callback events are only available in hq mode + if ((HIGH_QUALITY == mCapMode) || (HIGH_QUALITY_ZSL== mCapMode)) { + //Disable the callback first + ret = setShutterCallback(false); + + // if anybody is waiting on the shutter callback + // signal them and then recreate the semaphore + if ( 0 != mStartCaptureSem.Count() ) { + + for (int i = mStartCaptureSem.Count(); i < 0; i++) { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + NULL ); + } + mStartCaptureSem.Create(0); + } + } else if (CP_CAM == mCapMode) { + // Reset shot config queue + OMX_TI_CONFIG_ENQUEUESHOTCONFIGS resetShotConfigs; + OMX_INIT_STRUCT_PTR(&resetShotConfigs, OMX_TI_CONFIG_ENQUEUESHOTCONFIGS); + + resetShotConfigs.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + resetShotConfigs.bFlushQueue = OMX_TRUE; + resetShotConfigs.nNumConfigs = 0; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigEnqueueShotConfigs, + &resetShotConfigs); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while reset shot config 0x%x", eError); + goto EXIT; + } else { + CAMHAL_LOGDA("Shot config reset successfully"); + } + } + + //Wait here for the capture to be done, in worst case timeout and proceed with cleanup + mCaptureSem.WaitTimeout(OMX_CAPTURE_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State Image Capture Stop Exitting!!!"); + goto EXIT; + } + + // Disable image capture + // Capturing command is not needed when capturing in video mode + if ( ( mCapMode != VIDEO_MODE ) && ( mCapMode != VIDEO_MODE_HQ ) ) { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + bOMX.bEnabled = OMX_FALSE; + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCapturing, + &bOMX); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGDB("Error during SetConfig- 0x%x", eError); + ret = -1; + goto EXIT; + } + } + + CAMHAL_LOGDB("Capture set - 0x%x", eError); + + mCaptureSignalled = true; //set this to true if we exited because of timeout + + { + android::AutoMutex lock(mFrameCountMutex); + mFrameCount = 0; + mFirstFrameCondition.broadcast(); + } + + // Stop is always signalled externally in CPCAM mode + // We need to make sure we really stop + if ((mCapMode == CP_CAM)) { + disableReprocess(); + disableImagePort(); + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + } + + // Moving code for below commit here as an optimization for continuous capture, + // so focus settings don't have to reapplied after each capture + // c78fa2a CameraHAL: Always reset focus mode after capture + // Workaround when doing many consecutive shots, CAF wasn't getting restarted. + mPending3Asettings |= SetFocus; + + mCapturedFrames = 0; + mBurstFramesAccum = 0; + mBurstFramesQueued = 0; + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + //Release image buffers + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + + { + android::AutoMutex lock(mFrameCountMutex); + mFrameCount = 0; + mFirstFrameCondition.broadcast(); + } + + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::disableImagePort(){ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *imgCaptureData = NULL; + OMXCameraPortParameters *imgRawCaptureData = NULL; + + if (!mCaptureConfigured) { + return NO_ERROR; + } + + mCaptureConfigured = false; + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + imgRawCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex]; // for RAW capture + + ///Register for Image port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + mStopCaptureSem); + ///Disable Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + + ///Free all the buffers on capture port + if (imgCaptureData) { + CAMHAL_LOGDB("Freeing buffer on Capture port - %d", imgCaptureData->mNumBufs); + for ( int index = 0 ; index < imgCaptureData->mNumBufs ; index++) { + CAMHAL_LOGDB("Freeing buffer on Capture port - 0x%x", + ( unsigned int ) imgCaptureData->mBufferHeader[index]->pBuffer); + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mImagePortIndex, + (OMX_BUFFERHEADERTYPE*)imgCaptureData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + CAMHAL_LOGDA("Waiting for port disable"); + //Wait for the image port enable event + ret = mStopCaptureSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after Disable Image Port Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("Port disabled"); + } else { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port disable"); + goto EXIT; + } + + deinitInternalBuffers(mCameraAdapterParameters.mImagePortIndex); + + // since port settings are not persistent after port is disabled... + mPendingCaptureSettings |= SetFormat; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + + if (mRawCapture) { + ///Register for Video port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoPortIndex, + mStopCaptureSem); + ///Disable RawCapture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoPortIndex, + NULL); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + ///Free all the buffers on RawCapture port + if (imgRawCaptureData) { + CAMHAL_LOGDB("Freeing buffer on Capture port - %d", imgRawCaptureData->mNumBufs); + for ( int index = 0 ; index < imgRawCaptureData->mNumBufs ; index++) { + CAMHAL_LOGDB("Freeing buffer on Capture port - 0x%x", ( unsigned int ) imgRawCaptureData->mBufferHeader[index]->pBuffer); + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mVideoPortIndex, + (OMX_BUFFERHEADERTYPE*)imgRawCaptureData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + CAMHAL_LOGDA("Waiting for Video port disable"); + //Wait for the image port enable event + mStopCaptureSem.WaitTimeout(OMX_CMD_TIMEOUT); + CAMHAL_LOGDA("Video Port disabled"); + } +#endif + +EXIT: + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::initInternalBuffers(OMX_U32 portIndex) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + int index = 0; + OMX_TI_PARAM_USEBUFFERDESCRIPTOR bufferdesc; + + /* Indicate to Ducati that we're planning to use dynamically-mapped buffers */ + OMX_INIT_STRUCT_PTR (&bufferdesc, OMX_TI_PARAM_USEBUFFERDESCRIPTOR); + bufferdesc.nPortIndex = portIndex; + bufferdesc.bEnabled = OMX_FALSE; + bufferdesc.eBufferType = OMX_TI_BufferTypePhysicalPageList; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexUseBufferDescriptor, + &bufferdesc); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + return -EINVAL; + } + + CAMHAL_LOGDA("Initializing internal buffers"); + do { + OMX_TI_PARAM_COMPONENTBUFALLOCTYPE bufferalloc; + OMX_TI_PARAM_COMPONENTBUFALLOCTYPE bufferallocset; + OMX_INIT_STRUCT_PTR (&bufferalloc, OMX_TI_PARAM_COMPONENTBUFALLOCTYPE); + bufferalloc.nPortIndex = portIndex; + bufferalloc.nIndex = index; + + eError = OMX_GetParameter (mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexParamComponentBufferAllocation, + &bufferalloc); + if (eError == OMX_ErrorNoMore) { + return NO_ERROR; + } + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("GetParameter failed error = 0x%x", eError); + break; + } + + CAMHAL_LOGDB("Requesting buftype %d of size %dx%d", + (int)bufferalloc.eBufType, (int)bufferalloc.nAllocWidth, + (int)bufferalloc.nAllocLines); + + bufferalloc.eBufType = OMX_TI_BufferTypeHardwareReserved1D; + + OMX_INIT_STRUCT_PTR (&bufferallocset, OMX_TI_PARAM_COMPONENTBUFALLOCTYPE); + bufferallocset.nPortIndex = portIndex; + bufferallocset.nIndex = index; + bufferallocset.eBufType = OMX_TI_BufferTypeHardwareReserved1D; + bufferallocset.nAllocWidth = bufferalloc.nAllocWidth; + bufferallocset.nAllocLines = bufferalloc.nAllocLines; + + eError = OMX_SetParameter (mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexParamComponentBufferAllocation, + &bufferallocset); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("SetParameter failed, error=%08x", eError); + if (eError == OMX_ErrorNoMore) return NO_ERROR; + break; + } + + index++; + + /* 1 is an arbitrary limit */ + } while (index < 1); + + CAMHAL_LOGV("Ducati requested too many (>1) internal buffers"); + + return -EINVAL; +} + +status_t OMXCameraAdapter::deinitInternalBuffers(OMX_U32 portIndex) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_PARAM_USEBUFFERDESCRIPTOR bufferdesc; + + OMX_INIT_STRUCT_PTR (&bufferdesc, OMX_TI_PARAM_USEBUFFERDESCRIPTOR); + bufferdesc.nPortIndex = portIndex; + bufferdesc.bEnabled = OMX_FALSE; + bufferdesc.eBufferType = OMX_TI_BufferTypeDefault; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexUseBufferDescriptor, + &bufferdesc); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + return -EINVAL; + } + + OMX_TI_PARAM_COMPONENTBUFALLOCTYPE bufferalloc; + OMX_INIT_STRUCT_PTR (&bufferalloc, OMX_TI_PARAM_COMPONENTBUFALLOCTYPE); + bufferalloc.nPortIndex = portIndex; + bufferalloc.eBufType = OMX_TI_BufferTypeDefault; + bufferalloc.nAllocWidth = 1; + bufferalloc.nAllocLines = 1; + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexParamComponentBufferAllocation, + &bufferalloc); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + return -EINVAL; + } + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::UseBuffersCapture(CameraBuffer * bufArr, int num) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * imgCaptureData = NULL; + OMXCameraPortParameters cap; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( 0 != mUseCaptureSem.Count() ) + { + CAMHAL_LOGEB("Error mUseCaptureSem semaphore count %d", mUseCaptureSem.Count()); + return BAD_VALUE; + } + + CAMHAL_ASSERT(num > 0); + + // if some setting that requires a SetParameter (including + // changing buffer types) then we need to disable the port + // before being allowed to apply the settings + if ((mPendingCaptureSettings & ECaptureParamSettings) || + bufArr[0].type != imgCaptureData->mBufferType || + imgCaptureData->mNumBufs != num) { + if (mCaptureConfigured) { + disableImagePort(); + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + } + + imgCaptureData->mBufferType = bufArr[0].type; + imgCaptureData->mNumBufs = num; + + CAMHAL_LOGDB("Params Width = %d", (int)imgCaptureData->mWidth); + CAMHAL_LOGDB("Params Height = %d", (int)imgCaptureData->mHeight); + + if (mPendingCaptureSettings & SetFormat) { + mPendingCaptureSettings &= ~SetFormat; + ret = setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *imgCaptureData); + if ( ret != NO_ERROR ) { + CAMHAL_LOGEB("setFormat() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + } + + if (mPendingCaptureSettings & SetThumb) { + mPendingCaptureSettings &= ~SetThumb; + ret = setThumbnailParams(mThumbWidth, mThumbHeight, mThumbQuality); + if ( NO_ERROR != ret) { + CAMHAL_LOGEB("Error configuring thumbnail size %x", ret); + return ret; + } + } + + if (mPendingCaptureSettings & SetQuality) { + mPendingCaptureSettings &= ~SetQuality; + ret = setImageQuality(mPictureQuality); + if ( NO_ERROR != ret) { + CAMHAL_LOGEB("Error configuring image quality %x", ret); + goto EXIT; + } + } + + // Configure DOMX to use either gralloc handles or vptrs + { + OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles; + OMX_INIT_STRUCT_PTR (&domxUseGrallocHandles, OMX_TI_PARAMUSENATIVEBUFFER); + + domxUseGrallocHandles.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + if (bufArr[0].type == CAMERA_BUFFER_ANW) { + CAMHAL_LOGD ("Using ANW Buffers"); + initInternalBuffers(mCameraAdapterParameters.mImagePortIndex); + domxUseGrallocHandles.bEnable = OMX_TRUE; + } else { + CAMHAL_LOGD ("Using ION Buffers"); + domxUseGrallocHandles.bEnable = OMX_FALSE; + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture image port configuration: ", &bufArr->ppmStamp); + +#endif + + // Register for Image port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + mUseCaptureSem); + + // Enable Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + + CAMHAL_LOGDB("OMX_UseBuffer = 0x%x", eError); + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + for (int index = 0 ; index < imgCaptureData->mNumBufs ; index++) { + OMX_BUFFERHEADERTYPE *pBufferHdr; + CAMHAL_LOGDB("OMX_UseBuffer Capture address: 0x%x, size = %d", + (unsigned int)bufArr[index].opaque, + (int)imgCaptureData->mBufSize); + + eError = OMX_UseBuffer(mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mImagePortIndex, + 0, + imgCaptureData->mBufSize, + (OMX_U8*)camera_buffer_get_omx_ptr(&bufArr[index])); + + CAMHAL_LOGDB("OMX_UseBuffer = 0x%x", eError); + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR) &bufArr[index]; + bufArr[index].index = index; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0; + pBufferHdr->nVersion.s.nStep = 0; + imgCaptureData->mBufferHeader[index] = pBufferHdr; + imgCaptureData->mStatus[index] = OMXCameraPortParameters::IDLE; + } + + // Wait for the image port enable event + CAMHAL_LOGDA("Waiting for port enable"); + ret = mUseCaptureSem.WaitTimeout(OMX_CMD_TIMEOUT); + + // If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) { + CAMHAL_LOGEA("Invalid State after Enable Image Port Exitting!!!"); + goto EXIT; + } + + if (ret != NO_ERROR) { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port enable"); + goto EXIT; + } + CAMHAL_LOGDA("Port enabled"); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture image port enabled and buffers registered: ", &bufArr->ppmStamp); + +#endif + + if (mNextState != LOADED_REPROCESS_CAPTURE_STATE) { + // Enable WB and vector shot extra data for metadata + setExtraData(true, mCameraAdapterParameters.mImagePortIndex, OMX_WhiteBalance); + setExtraData(true, mCameraAdapterParameters.mImagePortIndex, OMX_TI_LSCTable); + } + + // CPCam mode only supports vector shot + // Regular capture is not supported + if ( (mCapMode == CP_CAM) && (mNextState != LOADED_REPROCESS_CAPTURE_STATE) ) { + initVectorShot(); + } + + mCaptureBuffersAvailable.clear(); + for (unsigned int i = 0; i < imgCaptureData->mMaxQueueable; i++ ) { + mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 0); + } + + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for (unsigned int i = imgCaptureData->mMaxQueueable; i < imgCaptureData->mNumBufs; i++ ) { + mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 1); + } + } + + if ( NO_ERROR == ret ) + { + ret = setupEXIF(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring EXIF Buffer %x", ret); + } + } + + // Choose proper single preview mode for cp capture (reproc or hs) + if (( NO_ERROR == ret) && (OMXCameraAdapter::CP_CAM == mCapMode)) { + OMX_TI_CONFIG_SINGLEPREVIEWMODETYPE singlePrevMode; + OMX_INIT_STRUCT_PTR (&singlePrevMode, OMX_TI_CONFIG_SINGLEPREVIEWMODETYPE); + if (mNextState == LOADED_CAPTURE_STATE) { + singlePrevMode.eMode = OMX_TI_SinglePreviewMode_ImageCaptureHighSpeed; + } else if (mNextState == LOADED_REPROCESS_CAPTURE_STATE) { + singlePrevMode.eMode = OMX_TI_SinglePreviewMode_Reprocess; + } else { + CAMHAL_LOGE("Wrong state trying to start a capture in CPCAM mode?"); + singlePrevMode.eMode = OMX_TI_SinglePreviewMode_ImageCaptureHighSpeed; + } + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigSinglePreviewMode, + &singlePrevMode); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while configuring single preview mode 0x%x", eError); + ret = Utils::ErrorUtils::omxToAndroidError(eError); + } else { + CAMHAL_LOGDA("single preview mode configured successfully"); + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Takepicture extra configs on image port done: ", &bufArr->ppmStamp); + +#endif + + mCaptureConfigured = true; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + if (mRawCapture) { + mCaptureConfigured = false; + } +#endif + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + setExtraData(false, mCameraAdapterParameters.mImagePortIndex, OMX_WhiteBalance); + // TODO: WA: if domx client disables VectShotInfo metadata on the image port, this causes + // VectShotInfo to be disabled internally on preview port also. Remove setting in OMXCapture + // setExtraData(false, mCameraAdapterParameters.mImagePortIndex, OMX_TI_VectShotInfo); + setExtraData(false, mCameraAdapterParameters.mImagePortIndex, OMX_TI_LSCTable); + //Release image buffers + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +} +status_t OMXCameraAdapter::UseBuffersRawCapture(CameraBuffer *bufArr, int num) +{ + LOG_FUNCTION_NAME + status_t ret; + OMX_ERRORTYPE eError; + OMXCameraPortParameters * imgRawCaptureData = NULL; + Utils::Semaphore camSem; + OMXCameraPortParameters cap; + + imgRawCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoPortIndex]; + + if (mCaptureConfigured) { + return NO_ERROR; + } + + camSem.Create(); + + // mWaitingForSnapshot is true only when we're in the process of capturing + if (mWaitingForSnapshot) { + ///Register for Video port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoPortIndex, + camSem); + + ///Disable Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoPortIndex, + NULL); + + CAMHAL_LOGDA("Waiting for port disable"); + //Wait for the image port enable event + camSem.Wait(); + CAMHAL_LOGDA("Port disabled"); + } + + imgRawCaptureData->mNumBufs = num; + + CAMHAL_LOGDB("RAW Max sensor width = %d", (int)imgRawCaptureData->mWidth); + CAMHAL_LOGDB("RAW Max sensor height = %d", (int)imgRawCaptureData->mHeight); + + ret = setFormat(OMX_CAMERA_PORT_VIDEO_OUT_VIDEO, *imgRawCaptureData); + + if (ret != NO_ERROR) { + CAMHAL_LOGEB("setFormat() failed %d", ret); + LOG_FUNCTION_NAME_EXIT + return ret; + } + + ///Register for Video port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoPortIndex, + camSem); + + ///Enable Video Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoPortIndex, + NULL); + + mCaptureBuffersLength = (int)imgRawCaptureData->mBufSize; + for ( int index = 0 ; index < imgRawCaptureData->mNumBufs ; index++ ) { + OMX_BUFFERHEADERTYPE *pBufferHdr; + CAMHAL_LOGDB("OMX_UseBuffer rawCapture address: 0x%x, size = %d ", + (unsigned int)bufArr[index].opaque, + (int)imgRawCaptureData->mBufSize ); + + eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mVideoPortIndex, + 0, + mCaptureBuffersLength, + (OMX_U8*)camera_buffer_get_omx_ptr(&bufArr[index])); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_UseBuffer = 0x%x", eError); + } + + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR) &bufArr[index]; + bufArr[index].index = index; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0; + pBufferHdr->nVersion.s.nStep = 0; + imgRawCaptureData->mBufferHeader[index] = pBufferHdr; + + } + + //Wait for the image port enable event + CAMHAL_LOGDA("Waiting for port enable"); + camSem.Wait(); + CAMHAL_LOGDA("Port enabled"); + + if (NO_ERROR == ret) { + ret = setupEXIF(); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error configuring EXIF Buffer %x", ret); + } + } + + mCapturedFrames = mBurstFrames; + mBurstFramesQueued = 0; + mCaptureConfigured = true; + + EXIT: + + if (eError != OMX_ErrorNone) { + if ( NULL != mErrorNotifier ) + { + mErrorNotifier->errorNotify(eError); + } + } + + LOG_FUNCTION_NAME_EXIT + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXDCC.cpp b/camera/OMXCameraAdapter/OMXDCC.cpp new file mode 100644 index 0000000..cbaf2ab --- /dev/null +++ b/camera/OMXCameraAdapter/OMXDCC.cpp @@ -0,0 +1,227 @@ +/* + * 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. + */ + +/** +* @file OMXDCC.cpp +* +* This file contains functionality for loading the DCC binaries. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" +#include "OMXDCC.h" +#include +#include + +namespace Ti { +namespace Camera { + +#ifndef MOTOROLA_CAMERA +android::String8 DCCHandler::DCCPath("/data/misc/camera/"); +#else +android::String8 DCCHandler::DCCPath("/system/etc/omapcam/"); +#endif +bool DCCHandler::mDCCLoaded = false; + +status_t DCCHandler::loadDCC(OMX_HANDLETYPE hComponent) +{ + OMX_ERRORTYPE dccError = OMX_ErrorNone; + + if (!mDCCLoaded) { + dccError = initDCC(hComponent); + if (dccError != OMX_ErrorNone) { + CAMHAL_LOGE(" Error in DCC Init"); + } + + mDCCLoaded = true; + } + + return Utils::ErrorUtils::omxToAndroidError(dccError); +} + +OMX_ERRORTYPE DCCHandler::initDCC(OMX_HANDLETYPE hComponent) +{ + OMX_TI_PARAM_DCCURIINFO param; + OMX_PTR ptempbuf; + OMX_U16 nIndex = 0; + OMX_ERRORTYPE eError = OMX_ErrorNone; + int ret; + OMX_S32 status = 0; + android::Vector dccDirs; + OMX_U16 i; + MemoryManager memMgr; + CameraBuffer *dccBuffer = NULL; + int dccbuf_size = 0; + OMX_INIT_STRUCT_PTR(¶m, OMX_TI_PARAM_DCCURIINFO); + + // Read the the DCC URI info + for (nIndex = 0; eError != OMX_ErrorNoMore; nIndex++) { + param.nIndex = nIndex; + eError = OMX_GetParameter(hComponent, + ( OMX_INDEXTYPE )OMX_TI_IndexParamDccUriInfo, + ¶m); + + if (eError == OMX_ErrorNone) { + CAMHAL_LOGD("DCC URI's %s ", param.sDCCURI); + android::String8 *dccDir = new android::String8(); + if ( NULL != dccDir ) { + dccDir->clear(); + dccDir->append(DCCPath); + dccDir->append((const char *) param.sDCCURI); + dccDir->append("/"); + dccDirs.add(dccDir); + } else { + CAMHAL_LOGE("DCC URI not allocated"); + eError = OMX_ErrorInsufficientResources; + goto EXIT; + } + } + } + + // setting back errortype OMX_ErrorNone + if (eError == OMX_ErrorNoMore) { + eError = OMX_ErrorNone; + } + + dccbuf_size = readDCCdir(NULL, dccDirs); + if(dccbuf_size <= 0) { + CAMHAL_LOGE("No DCC files found, switching back to default DCC"); + eError = OMX_ErrorInsufficientResources; + goto EXIT; + } + dccbuf_size = ((dccbuf_size + 4095 )/4096)*4096; + + if ( memMgr.initialize() != NO_ERROR ) { + CAMHAL_LOGE("DCC memory manager initialization failed!!!"); + eError = OMX_ErrorInsufficientResources; + goto EXIT; + } + + dccBuffer = memMgr.allocateBufferList(0, 0, NULL, dccbuf_size, 1); + if ( NULL == dccBuffer ) { + CAMHAL_LOGE("DCC buffer allocation failed!!!"); + eError = OMX_ErrorInsufficientResources; + goto EXIT; + } + + dccbuf_size = readDCCdir(dccBuffer[0].mapped, dccDirs); + CAMHAL_ASSERT_X(dccbuf_size > 0,"ERROR in copy DCC files into buffer"); + + eError = sendDCCBufPtr(hComponent, dccBuffer); + +EXIT: + + for (i = 0; i < dccDirs.size(); i++) { + android::String8 *dccDir = dccDirs.itemAt(0); + dccDirs.removeAt(0); + delete dccDir; + } + + if ( NULL != dccBuffer ) { + memMgr.freeBufferList(dccBuffer); + } + + return eError; +} + +OMX_ERRORTYPE DCCHandler::sendDCCBufPtr(OMX_HANDLETYPE hComponent, + CameraBuffer *dccBuffer) +{ + OMX_TI_CONFIG_SHAREDBUFFER uribufparam; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_INIT_STRUCT_PTR(&uribufparam, OMX_TI_CONFIG_SHAREDBUFFER); + + CAMHAL_ASSERT_X(dccBuffer != NULL,"ERROR invalid DCC buffer"); + + uribufparam.nPortIndex = OMX_ALL; + uribufparam.nSharedBuffSize = dccBuffer->size; + uribufparam.pSharedBuff = (OMX_U8 *) camera_buffer_get_omx_ptr(dccBuffer); + + eError = OMX_SetParameter(hComponent, + ( OMX_INDEXTYPE )OMX_TI_IndexParamDccUriBuffer, + &uribufparam); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB(" Error in SetParam for DCC Uri Buffer 0x%x", eError); + } + + return eError; +} + +size_t DCCHandler::readDCCdir(OMX_PTR buffer, + const android::Vector &dirPaths) +{ + FILE *pFile; + OMX_S32 lSize; + OMX_S32 dcc_buf_size = 0; + size_t result; + OMX_STRING filename; + android::String8 temp; + const char *dotdot = ".."; + DIR *d; + struct dirent *dir; + OMX_U16 i = 0; + status_t stat = NO_ERROR; + size_t ret = 0; + + for (i = 0; i < dirPaths.size(); i++) { + d = opendir(dirPaths.itemAt(i)->string()); + if (d) { + // read each filename + while ((dir = readdir(d)) != NULL) { + filename = dir->d_name; + temp.clear(); + temp.append(dirPaths.itemAt(i)->string()); + temp.append(filename); + if ((*filename != *dotdot)) { + pFile = fopen(temp.string(), "rb"); + if (pFile == NULL) { + stat = -errno; + } else { + fseek(pFile, 0, SEEK_END); + lSize = ftell(pFile); + rewind(pFile); + // buffer is not NULL then copy all the DCC profiles into buffer + // else return the size of the DCC directory. + if (buffer) { + // copy file into the buffer: + result = fread(buffer, 1, lSize, pFile); + if (result != (size_t) lSize) { + stat = INVALID_OPERATION; + } + buffer = buffer + lSize; + } + // getting the size of the total dcc files available in FS */ + dcc_buf_size = dcc_buf_size + lSize; + // terminate + fclose(pFile); + } + } + } + closedir(d); + } + } + + if (stat == NO_ERROR) { + ret = dcc_buf_size; + } + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXDccDataSave.cpp b/camera/OMXCameraAdapter/OMXDccDataSave.cpp new file mode 100644 index 0000000..7547743 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXDccDataSave.cpp @@ -0,0 +1,361 @@ +/* + * 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. + */ + +/** +* @file OMXDccDataSave.cpp +* +* This file contains functionality for handling DCC data save +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + + +namespace Ti { +namespace Camera { + +status_t OMXCameraAdapter::initDccFileDataSave(OMX_HANDLETYPE* omxHandle, int portIndex) +{ + OMX_CONFIG_EXTRADATATYPE extraDataControl; + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE); + extraDataControl.nPortIndex = portIndex; + extraDataControl.eExtraDataType = OMX_TI_DccData; + extraDataControl.bEnable = OMX_TRUE; + + eError = OMX_SetConfig(*omxHandle, + ( OMX_INDEXTYPE ) OMX_IndexConfigOtherExtraDataControl, + &extraDataControl); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring dcc data overwrite extra data 0x%x", + eError); + + ret = NO_INIT; + } + + if (mDccData.pData) { + free(mDccData.pData); + mDccData.pData = NULL; + } + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::sniffDccFileDataSave(OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_TI_DCCDATATYPE* dccData; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mDccDataLock); + + if ( NULL == pBuffHeader ) { + CAMHAL_LOGEA("Invalid Buffer header"); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + extraData = getExtradata(pBuffHeader->pPlatformPrivate, + (OMX_EXTRADATATYPE)OMX_TI_DccData); + + if ( NULL != extraData ) { + CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x", + extraData->nSize, + sizeof(OMX_OTHER_EXTRADATATYPE), + extraData->eType, + extraData->nDataSize, + extraData->nPortIndex, + extraData->nVersion); + } else { + CAMHAL_LOGVA("Invalid OMX_TI_DCCDATATYPE"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + dccData = ( OMX_TI_DCCDATATYPE * ) extraData->data; + + if (NULL == dccData) { + CAMHAL_LOGVA("OMX_TI_DCCDATATYPE is not found in extra data"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + if (mDccData.pData) { + free(mDccData.pData); + } + + memcpy(&mDccData, dccData, sizeof(mDccData)); + + int dccDataSize = (int)dccData->nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData)); + + mDccData.pData = (OMX_PTR)malloc(dccDataSize); + + if (NULL == mDccData.pData) { + CAMHAL_LOGVA("not enough memory for DCC data"); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + } + + memcpy(mDccData.pData, &(dccData->pData), dccDataSize); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Recursively searches given directory contents for the correct DCC file. +// The directory must be opened and its stream pointer + path passed +// as arguments. As this function is called recursively, to avoid excessive +// stack usage the path param is reused -> this MUST be char array with +// enough length!!! (260 should suffice). Path must end with "/". +// The directory must also be closed in the caller function. +// If the correct camera DCC file is found (based on the OMX measurement data) +// its file stream pointer is returned. NULL is returned otherwise +FILE * OMXCameraAdapter::parseDCCsubDir(DIR *pDir, char *path) +{ + FILE *pFile; + DIR *pSubDir; + struct dirent *dirEntry; + int initialPathLength = strlen(path); + + LOG_FUNCTION_NAME; + + /* check each directory entry */ + while ((dirEntry = readdir(pDir)) != NULL) + { + if (dirEntry->d_name[0] == '.') + continue; + + strcat(path, dirEntry->d_name); + // dirEntry might be sub directory -> check it + pSubDir = opendir(path); + if (pSubDir) { + // dirEntry is sub directory -> parse it + strcat(path, "/"); + pFile = parseDCCsubDir(pSubDir, path); + closedir(pSubDir); + if (pFile) { + // the correct DCC file found! + LOG_FUNCTION_NAME_EXIT; + return pFile; + } + } else { + // dirEntry is file -> open it + pFile = fopen(path, "rb"); + if (pFile) { + // now check if this is the correct DCC file for that camera + OMX_U32 dccFileIDword; + OMX_U32 *dccFileDesc = (OMX_U32 *) &mDccData.nCameraModuleId; + int i; + + // DCC file ID is 3 4-byte words + for (i = 0; i < 3; i++) { + if (fread(&dccFileIDword, sizeof(OMX_U32), 1, pFile) != 1) { + // file too short + break; + } + if (dccFileIDword != dccFileDesc[i]) { + // DCC file ID word i does not match + break; + } + } + + fclose(pFile); + if (i == 3) { + // the correct DCC file found! + CAMHAL_LOGDB("DCC file to be updated: %s", path); + // reopen it for modification + pFile = fopen(path, "rb+"); + if (!pFile) + CAMHAL_LOGEB("ERROR: DCC file %s failed to open for modification", path); + LOG_FUNCTION_NAME_EXIT; + return pFile; + } + } else { + CAMHAL_LOGEB("ERROR: Failed to open file %s for reading", path); + } + } + // restore original path + path[initialPathLength] = '\0'; + } + + LOG_FUNCTION_NAME_EXIT; + + // DCC file not found in this directory tree + return NULL; +} + +// Finds the DCC file corresponding to the current camera based on the +// OMX measurement data, opens it and returns the file stream pointer +// (NULL on error or if file not found). +// The folder string dccFolderPath must end with "/" +FILE * OMXCameraAdapter::fopenCameraDCC(const char *dccFolderPath) +{ + FILE *pFile; + DIR *pDir; + char dccPath[260]; + + LOG_FUNCTION_NAME; + + strcpy(dccPath, dccFolderPath); + + pDir = opendir(dccPath); + if (!pDir) { + CAMHAL_LOGEB("ERROR: Opening DCC directory %s failed", dccPath); + LOG_FUNCTION_NAME_EXIT; + return NULL; + } + + pFile = parseDCCsubDir(pDir, dccPath); + closedir(pDir); + if (pFile) { + CAMHAL_LOGDB("DCC file %s opened for modification", dccPath); + } + + LOG_FUNCTION_NAME_EXIT; + + return pFile; +} + +// Positions the DCC file stream pointer to the correct offset within the +// correct usecase based on the OMX mesurement data. Returns 0 on success +status_t OMXCameraAdapter::fseekDCCuseCasePos(FILE *pFile) +{ + OMX_U32 dccNumUseCases = 0; + OMX_U32 dccUseCaseData[3]; + OMX_U32 i; + + LOG_FUNCTION_NAME; + + // position the file pointer to the DCC use cases section + if (fseek(pFile, 80, SEEK_SET)) { + CAMHAL_LOGEA("ERROR: Unexpected end of DCC file"); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + if (fread(&dccNumUseCases, sizeof(OMX_U32), 1, pFile) != 1 || + dccNumUseCases == 0) { + CAMHAL_LOGEA("ERROR: DCC file contains 0 use cases"); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + for (i = 0; i < dccNumUseCases; i++) { + if (fread(dccUseCaseData, sizeof(OMX_U32), 3, pFile) != 3) { + CAMHAL_LOGEA("ERROR: Unexpected end of DCC file"); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + if (dccUseCaseData[0] == mDccData.nUseCaseId) { + // DCC use case match! + break; + } + } + + if (i == dccNumUseCases) { + CAMHAL_LOGEB("ERROR: Use case ID %lu not found in DCC file", mDccData.nUseCaseId); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + // dccUseCaseData[1] is the offset to the beginning of the actual use case + // from the beginning of the file + // mDccData.nOffset is the offset within the actual use case (from the + // beginning of the use case to the data to be modified) + + if (fseek(pFile,dccUseCaseData[1] + mDccData.nOffset, SEEK_SET )) + { + CAMHAL_LOGEA("ERROR: Error setting the correct offset"); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t OMXCameraAdapter::saveDccFileDataSave() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mDccDataLock); + + if (mDccData.pData) + { + FILE *fd = fopenCameraDCC(DCC_PATH); + + if (fd) + { + if (!fseekDCCuseCasePos(fd)) + { + int dccDataSize = (int)mDccData.nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData)); + + if (fwrite(mDccData.pData, dccDataSize, 1, fd) != 1) + { + CAMHAL_LOGEA("ERROR: Writing to DCC file failed"); + } + else + { + CAMHAL_LOGDA("DCC file successfully updated"); + } + } + fclose(fd); + } + else + { + CAMHAL_LOGEA("ERROR: Correct DCC file not found or failed to open for modification"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::closeDccFileDataSave() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mDccDataLock); + + if (mDccData.pData) { + free(mDccData.pData); + mDccData.pData = NULL; + } + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXDefaults.cpp b/camera/OMXCameraAdapter/OMXDefaults.cpp new file mode 100644 index 0000000..80805b2 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXDefaults.cpp @@ -0,0 +1,87 @@ +/* + * 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. + */ + +/** +* @file OMXDefaults.cpp +* +* This file contains definitions are OMX Camera defaults +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace Ti { +namespace Camera { + +#define __STRINGIFY(s) __STRING(s) + +// OMX Camera defaults +const char OMXCameraAdapter::DEFAULT_ANTIBANDING[] = "auto"; +const char OMXCameraAdapter::DEFAULT_BRIGHTNESS[] = "50"; +const char OMXCameraAdapter::DEFAULT_CONTRAST[] = "100"; +const char OMXCameraAdapter::DEFAULT_EFFECT[] = "none"; +const char OMXCameraAdapter::DEFAULT_EV_COMPENSATION[] = "0"; +const char OMXCameraAdapter::DEFAULT_EV_STEP[] = "0.1"; +const char OMXCameraAdapter::DEFAULT_EXPOSURE_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_FLASH_MODE[] = "off"; +const char OMXCameraAdapter::DEFAULT_FOCUS_MODE_PREFERRED[] = "auto"; +const char OMXCameraAdapter::DEFAULT_FOCUS_MODE[] = "infinity"; +#ifndef MOTOROLA_CAMERA +const char OMXCameraAdapter::DEFAULT_IPP[] = "ldc-nsf"; +#else +const char OMXCameraAdapter::DEFAULT_IPP[] = "off"; +#endif +const char OMXCameraAdapter::DEFAULT_ISO_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_JPEG_QUALITY[] = "95"; +const char OMXCameraAdapter::DEFAULT_THUMBNAIL_QUALITY[] = "60"; +const char OMXCameraAdapter::DEFAULT_THUMBNAIL_SIZE[] = "160x120"; +const char OMXCameraAdapter::DEFAULT_PICTURE_FORMAT[] = "jpeg"; +const char OMXCameraAdapter::DEFAULT_S3D_PICTURE_LAYOUT[] = "tb-full"; +const char OMXCameraAdapter::DEFAULT_PICTURE_SIZE[] = "320x240"; +const char OMXCameraAdapter::DEFAULT_PICTURE_SS_SIZE[] = "640x240"; +const char OMXCameraAdapter::DEFAULT_PICTURE_TB_SIZE[] = "320x480"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_FORMAT[] = "yuv420sp"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE[] = "30"; +const char OMXCameraAdapter::DEFAULT_S3D_PREVIEW_LAYOUT[] = "tb-subsampled"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_SIZE[] = "640x480"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_SS_SIZE[] = "1280x480"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_TB_SIZE[] = "640x960"; +const char OMXCameraAdapter::DEFAULT_NUM_PREV_BUFS[] = "6"; +const char OMXCameraAdapter::DEFAULT_NUM_PIC_BUFS[] = "1"; +const char OMXCameraAdapter::DEFAULT_SATURATION[] = "100"; +const char OMXCameraAdapter::DEFAULT_SCENE_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_SHARPNESS[] = "100"; +const char * OMXCameraAdapter::DEFAULT_VSTAB = android::CameraParameters::FALSE; +const char * OMXCameraAdapter::DEFAULT_VNF = android::CameraParameters::FALSE; +const char OMXCameraAdapter::DEFAULT_WB[] = "auto"; +const char OMXCameraAdapter::DEFAULT_ZOOM[] = "0"; +const char OMXCameraAdapter::DEFAULT_MAX_FD_HW_FACES[] = __STRINGIFY(MAX_NUM_FACES_SUPPORTED); +const char OMXCameraAdapter::DEFAULT_MAX_FD_SW_FACES[] = "0"; +const char OMXCameraAdapter::DEFAULT_HOR_ANGLE[] = "54.8"; +const char OMXCameraAdapter::DEFAULT_VER_ANGLE[] = "42.5"; +const char * OMXCameraAdapter::DEFAULT_AE_LOCK = android::CameraParameters::FALSE; +const char * OMXCameraAdapter::DEFAULT_AWB_LOCK = android::CameraParameters::FALSE; +const char OMXCameraAdapter::DEFAULT_VIDEO_SIZE[] = "1920x1080"; +const char OMXCameraAdapter::DEFAULT_SENSOR_ORIENTATION[] = "0"; +const char OMXCameraAdapter::DEFAULT_AUTOCONVERGENCE_MODE[] = "frame"; +const char OMXCameraAdapter::DEFAULT_MANUAL_CONVERGENCE[] = "0"; +const char * OMXCameraAdapter::DEFAULT_MECHANICAL_MISALIGNMENT_CORRECTION_MODE = android::CameraParameters::TRUE; +const char OMXCameraAdapter::DEFAULT_EXIF_MAKE[] = "default_make"; +const char OMXCameraAdapter::DEFAULT_EXIF_MODEL[] = "default_model"; + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXExif.cpp b/camera/OMXCameraAdapter/OMXExif.cpp new file mode 100644 index 0000000..b4fde5a --- /dev/null +++ b/camera/OMXCameraAdapter/OMXExif.cpp @@ -0,0 +1,838 @@ +/* + * 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. + */ + +/** +* @file OMXExif.cpp +* +* This file contains functionality for handling EXIF insertion. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include + +namespace Ti { +namespace Camera { + +status_t OMXCameraAdapter::setParametersEXIF(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + double gpsPos; + + LOG_FUNCTION_NAME; + + if( ( valstr = params.get(android::CameraParameters::KEY_GPS_LATITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + + if ( convertGPSCoord(gpsPos, + mEXIFData.mGPSData.mLatDeg, + mEXIFData.mGPSData.mLatMin, + mEXIFData.mGPSData.mLatSec, + mEXIFData.mGPSData.mLatSecDiv ) == NO_ERROR ) + { + + if ( 0 < gpsPos ) + { + strncpy(mEXIFData.mGPSData.mLatRef, GPS_NORTH_REF, GPS_REF_SIZE); + } + else + { + strncpy(mEXIFData.mGPSData.mLatRef, GPS_SOUTH_REF, GPS_REF_SIZE); + } + + mEXIFData.mGPSData.mLatValid = true; + } + else + { + mEXIFData.mGPSData.mLatValid = false; + } + } + else + { + mEXIFData.mGPSData.mLatValid = false; + } + + if( ( valstr = params.get(android::CameraParameters::KEY_GPS_LONGITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + + if ( convertGPSCoord(gpsPos, + mEXIFData.mGPSData.mLongDeg, + mEXIFData.mGPSData.mLongMin, + mEXIFData.mGPSData.mLongSec, + mEXIFData.mGPSData.mLongSecDiv) == NO_ERROR ) + { + + if ( 0 < gpsPos ) + { + strncpy(mEXIFData.mGPSData.mLongRef, GPS_EAST_REF, GPS_REF_SIZE); + } + else + { + strncpy(mEXIFData.mGPSData.mLongRef, GPS_WEST_REF, GPS_REF_SIZE); + } + + mEXIFData.mGPSData.mLongValid= true; + } + else + { + mEXIFData.mGPSData.mLongValid = false; + } + } + else + { + mEXIFData.mGPSData.mLongValid = false; + } + + if( ( valstr = params.get(android::CameraParameters::KEY_GPS_ALTITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + mEXIFData.mGPSData.mAltitude = floor(fabs(gpsPos)); + if (gpsPos < 0) { + mEXIFData.mGPSData.mAltitudeRef = 1; + } else { + mEXIFData.mGPSData.mAltitudeRef = 0; + } + mEXIFData.mGPSData.mAltitudeValid = true; + } + else + { + mEXIFData.mGPSData.mAltitudeValid= false; + } + + if( (valstr = params.get(android::CameraParameters::KEY_GPS_TIMESTAMP)) != NULL ) + { + long gpsTimestamp = strtol(valstr, NULL, 10); + struct tm *timeinfo = gmtime( ( time_t * ) & (gpsTimestamp) ); + if ( NULL != timeinfo ) + { + mEXIFData.mGPSData.mTimeStampHour = timeinfo->tm_hour; + mEXIFData.mGPSData.mTimeStampMin = timeinfo->tm_min; + mEXIFData.mGPSData.mTimeStampSec = timeinfo->tm_sec; + mEXIFData.mGPSData.mTimeStampValid = true; + } + else + { + mEXIFData.mGPSData.mTimeStampValid = false; + } + } + else + { + mEXIFData.mGPSData.mTimeStampValid = false; + } + + if( ( valstr = params.get(android::CameraParameters::KEY_GPS_TIMESTAMP) ) != NULL ) + { + long gpsDatestamp = strtol(valstr, NULL, 10); + struct tm *timeinfo = gmtime( ( time_t * ) & (gpsDatestamp) ); + if ( NULL != timeinfo ) + { + strftime(mEXIFData.mGPSData.mDatestamp, GPS_DATESTAMP_SIZE, "%Y:%m:%d", timeinfo); + mEXIFData.mGPSData.mDatestampValid = true; + } + else + { + mEXIFData.mGPSData.mDatestampValid = false; + } + } + else + { + mEXIFData.mGPSData.mDatestampValid = false; + } + + if( ( valstr = params.get(android::CameraParameters::KEY_GPS_PROCESSING_METHOD) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mProcMethod, valstr, GPS_PROCESSING_SIZE-1); + mEXIFData.mGPSData.mProcMethodValid = true; + } + else + { + mEXIFData.mGPSData.mProcMethodValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_GPS_MAPDATUM) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mMapDatum, valstr, GPS_MAPDATUM_SIZE-1); + mEXIFData.mGPSData.mMapDatumValid = true; + } + else + { + mEXIFData.mGPSData.mMapDatumValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_GPS_VERSION) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mVersionId, valstr, GPS_VERSION_SIZE-1); + mEXIFData.mGPSData.mVersionIdValid = true; + } + else + { + mEXIFData.mGPSData.mVersionIdValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MODEL ) ) != NULL ) + { + CAMHAL_LOGVB("EXIF Model: %s", valstr); + strncpy(mEXIFData.mModel, valstr, EXIF_MODEL_SIZE - 1); + mEXIFData.mModelValid= true; + } + else + { + mEXIFData.mModelValid= false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MAKE ) ) != NULL ) + { + CAMHAL_LOGVB("EXIF Make: %s", valstr); + strncpy(mEXIFData.mMake, valstr, EXIF_MAKE_SIZE - 1); + mEXIFData.mMakeValid = true; + } + else + { + mEXIFData.mMakeValid= false; + } + + + if( ( valstr = params.get(android::CameraParameters::KEY_FOCAL_LENGTH) ) != NULL ) { + CAMHAL_LOGVB("EXIF Focal length: %s", valstr); + ExifElementsTable::stringToRational(valstr, + &mEXIFData.mFocalNum, + &mEXIFData.mFocalDen); + } else { + mEXIFData.mFocalNum = 0; + mEXIFData.mFocalDen = 0; + } + + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setupEXIF() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + OMX_TI_CONFIG_EXIF_TAGS *exifTags; + unsigned char *startPtr = NULL; + unsigned char *sharedPtr = NULL; + struct timeval sTv; + struct tm *pTime; + OMXCameraPortParameters * capData = NULL; + CameraBuffer *memmgr_buf_array; + int buf_size = 0; + + LOG_FUNCTION_NAME; + + sharedBuffer.pSharedBuff = NULL; + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + //We allocate the shared buffer dynamically based on the + //requirements of the EXIF tags. The additional buffers will + //get stored after the EXIF configuration structure and the pointers + //will contain offsets within the shared buffer itself. + buf_size = sizeof(OMX_TI_CONFIG_EXIF_TAGS) + + ( EXIF_MODEL_SIZE ) + + ( EXIF_MAKE_SIZE ) + + ( EXIF_DATE_TIME_SIZE ) + + ( GPS_MAPDATUM_SIZE ) + + ( GPS_PROCESSING_SIZE ); + buf_size = ((buf_size+4095)/4096)*4096; + sharedBuffer.nSharedBuffSize = buf_size; + + memmgr_buf_array = mMemMgr.allocateBufferList(0, 0, NULL, buf_size, 1); + sharedBuffer.pSharedBuff = (OMX_U8*)camera_buffer_get_omx_ptr(&memmgr_buf_array[0]); + startPtr = ( OMX_U8 * ) memmgr_buf_array[0].opaque; + + if ( NULL == startPtr) + { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = -1; + } + + //Extra data begins right after the EXIF configuration structure. + sharedPtr = startPtr + sizeof(OMX_TI_CONFIG_EXIF_TAGS); + } + + if ( NO_ERROR == ret ) + { + exifTags = ( OMX_TI_CONFIG_EXIF_TAGS * ) startPtr; + OMX_INIT_STRUCT_PTR (exifTags, OMX_TI_CONFIG_EXIF_TAGS); + exifTags->nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags, + &sharedBuffer ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving EXIF configuration structure 0x%x", eError); + ret = -1; + } + } + + if ( NO_ERROR == ret ) + { + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusModel ) && + ( mEXIFData.mModelValid ) ) + { + strncpy(( char * ) sharedPtr, + mEXIFData.mModel, + EXIF_MODEL_SIZE - 1); + + exifTags->pModelBuff = ( OMX_S8 * ) ( sharedPtr - startPtr ); + exifTags->ulModelBuffSizeBytes = strlen((char*)sharedPtr) + 1; + sharedPtr += EXIF_MODEL_SIZE; + exifTags->eStatusModel = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusMake) && + ( mEXIFData.mMakeValid ) ) + { + strncpy( ( char * ) sharedPtr, + mEXIFData.mMake, + EXIF_MAKE_SIZE - 1); + + exifTags->pMakeBuff = ( OMX_S8 * ) ( sharedPtr - startPtr ); + exifTags->ulMakeBuffSizeBytes = strlen((char*)sharedPtr) + 1; + sharedPtr += EXIF_MAKE_SIZE; + exifTags->eStatusMake = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusFocalLength )) + { + if (mEXIFData.mFocalNum || mEXIFData.mFocalDen ) { + exifTags->ulFocalLength[0] = (OMX_U32) mEXIFData.mFocalNum; + exifTags->ulFocalLength[1] = (OMX_U32) mEXIFData.mFocalDen; + CAMHAL_LOGVB("exifTags->ulFocalLength = [%u] [%u]", + (unsigned int)(exifTags->ulFocalLength[0]), + (unsigned int)(exifTags->ulFocalLength[1])); + exifTags->eStatusFocalLength = OMX_TI_TagUpdated; + } + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusDateTime ) + { + int status = gettimeofday (&sTv, NULL); + pTime = localtime (&sTv.tv_sec); + if ( ( 0 == status ) && ( NULL != pTime ) ) + { + snprintf(( char * ) sharedPtr, EXIF_DATE_TIME_SIZE, + "%04d:%02d:%02d %02d:%02d:%02d", + pTime->tm_year + 1900, + pTime->tm_mon + 1, + pTime->tm_mday, + pTime->tm_hour, + pTime->tm_min, + pTime->tm_sec ); + } + + exifTags->pDateTimeBuff = ( OMX_S8 * ) ( sharedPtr - startPtr ); + sharedPtr += EXIF_DATE_TIME_SIZE; + exifTags->ulDateTimeBuffSizeBytes = EXIF_DATE_TIME_SIZE; + exifTags->eStatusDateTime = OMX_TI_TagUpdated; + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusImageWidth ) + { + exifTags->ulImageWidth = capData->mWidth; + exifTags->eStatusImageWidth = OMX_TI_TagUpdated; + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusImageHeight ) + { + exifTags->ulImageHeight = capData->mHeight; + exifTags->eStatusImageHeight = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLatitude ) && + ( mEXIFData.mGPSData.mLatValid ) ) + { + exifTags->ulGpsLatitude[0] = abs(mEXIFData.mGPSData.mLatDeg); + exifTags->ulGpsLatitude[2] = abs(mEXIFData.mGPSData.mLatMin); + exifTags->ulGpsLatitude[4] = abs(mEXIFData.mGPSData.mLatSec); + exifTags->ulGpsLatitude[1] = 1; + exifTags->ulGpsLatitude[3] = 1; + exifTags->ulGpsLatitude[5] = abs(mEXIFData.mGPSData.mLatSecDiv); + exifTags->eStatusGpsLatitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpslatitudeRef ) && + ( mEXIFData.mGPSData.mLatValid ) ) + { + exifTags->cGpslatitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLatRef[0]; + exifTags->cGpslatitudeRef[1] = '\0'; + exifTags->eStatusGpslatitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitude ) && + ( mEXIFData.mGPSData.mLongValid ) ) + { + exifTags->ulGpsLongitude[0] = abs(mEXIFData.mGPSData.mLongDeg); + exifTags->ulGpsLongitude[2] = abs(mEXIFData.mGPSData.mLongMin); + exifTags->ulGpsLongitude[4] = abs(mEXIFData.mGPSData.mLongSec); + exifTags->ulGpsLongitude[1] = 1; + exifTags->ulGpsLongitude[3] = 1; + exifTags->ulGpsLongitude[5] = abs(mEXIFData.mGPSData.mLongSecDiv); + exifTags->eStatusGpsLongitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitudeRef ) && + ( mEXIFData.mGPSData.mLongValid ) ) + { + exifTags->cGpsLongitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLongRef[0]; + exifTags->cGpsLongitudeRef[1] = '\0'; + exifTags->eStatusGpsLongitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitude ) && + ( mEXIFData.mGPSData.mAltitudeValid) ) + { + exifTags->ulGpsAltitude[0] = ( OMX_U32 ) mEXIFData.mGPSData.mAltitude; + exifTags->ulGpsAltitude[1] = 1; + exifTags->eStatusGpsAltitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitudeRef ) && + ( mEXIFData.mGPSData.mAltitudeValid) ) + { + exifTags->ucGpsAltitudeRef = (OMX_U8) mEXIFData.mGPSData.mAltitudeRef; + exifTags->eStatusGpsAltitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsMapDatum ) && + ( mEXIFData.mGPSData.mMapDatumValid ) ) + { + memcpy(sharedPtr, mEXIFData.mGPSData.mMapDatum, GPS_MAPDATUM_SIZE); + + exifTags->pGpsMapDatumBuff = ( OMX_S8 * ) ( sharedPtr - startPtr ); + exifTags->ulGpsMapDatumBuffSizeBytes = GPS_MAPDATUM_SIZE; + exifTags->eStatusGpsMapDatum = OMX_TI_TagUpdated; + sharedPtr += GPS_MAPDATUM_SIZE; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsProcessingMethod ) && + ( mEXIFData.mGPSData.mProcMethodValid ) ) + { + exifTags->pGpsProcessingMethodBuff = ( OMX_S8 * ) ( sharedPtr - startPtr ); + memcpy(sharedPtr, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); + sharedPtr += sizeof(ExifAsciiPrefix); + + memcpy(sharedPtr, + mEXIFData.mGPSData.mProcMethod, + ( GPS_PROCESSING_SIZE - sizeof(ExifAsciiPrefix) ) ); + exifTags->ulGpsProcessingMethodBuffSizeBytes = GPS_PROCESSING_SIZE; + exifTags->eStatusGpsProcessingMethod = OMX_TI_TagUpdated; + sharedPtr += GPS_PROCESSING_SIZE; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsVersionId ) && + ( mEXIFData.mGPSData.mVersionIdValid ) ) + { + exifTags->ucGpsVersionId[0] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[0]; + exifTags->ucGpsVersionId[1] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[1]; + exifTags->ucGpsVersionId[2] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[2]; + exifTags->ucGpsVersionId[3] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[3]; + exifTags->eStatusGpsVersionId = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsTimeStamp ) && + ( mEXIFData.mGPSData.mTimeStampValid ) ) + { + exifTags->ulGpsTimeStamp[0] = mEXIFData.mGPSData.mTimeStampHour; + exifTags->ulGpsTimeStamp[2] = mEXIFData.mGPSData.mTimeStampMin; + exifTags->ulGpsTimeStamp[4] = mEXIFData.mGPSData.mTimeStampSec; + exifTags->ulGpsTimeStamp[1] = 1; + exifTags->ulGpsTimeStamp[3] = 1; + exifTags->ulGpsTimeStamp[5] = 1; + exifTags->eStatusGpsTimeStamp = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsDateStamp ) && + ( mEXIFData.mGPSData.mDatestampValid ) ) + { + strncpy( ( char * ) exifTags->cGpsDateStamp, + ( char * ) mEXIFData.mGPSData.mDatestamp, + GPS_DATESTAMP_SIZE ); + exifTags->eStatusGpsDateStamp = OMX_TI_TagUpdated; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags, + &sharedBuffer ); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting EXIF configuration 0x%x", eError); + ret = -1; + } + } + + if ( NULL != memmgr_buf_array ) + { + mMemMgr.freeBufferList(memmgr_buf_array); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setupEXIF_libjpeg(ExifElementsTable* exifTable, + OMX_TI_ANCILLARYDATATYPE* pAncillaryData, + OMX_TI_WHITEBALANCERESULTTYPE* pWhiteBalanceData) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + struct timeval sTv; + struct tm *pTime; + OMXCameraPortParameters * capData = NULL; + + LOG_FUNCTION_NAME; + + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ((NO_ERROR == ret) && (mEXIFData.mModelValid)) { + ret = exifTable->insertElement(TAG_MODEL, mEXIFData.mModel); + } + + if ((NO_ERROR == ret) && (mEXIFData.mMakeValid)) { + ret = exifTable->insertElement(TAG_MAKE, mEXIFData.mMake); + } + + if ((NO_ERROR == ret)) { + if (mEXIFData.mFocalNum || mEXIFData.mFocalDen) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u/%u", + mEXIFData.mFocalNum, + mEXIFData.mFocalDen); + ret = exifTable->insertElement(TAG_FOCALLENGTH, temp_value); + + } + } + + if ((NO_ERROR == ret)) { + int status = gettimeofday (&sTv, NULL); + pTime = localtime (&sTv.tv_sec); + char temp_value[EXIF_DATE_TIME_SIZE + 1]; + if ((0 == status) && (NULL != pTime)) { + snprintf(temp_value, EXIF_DATE_TIME_SIZE, + "%04d:%02d:%02d %02d:%02d:%02d", + pTime->tm_year + 1900, + pTime->tm_mon + 1, + pTime->tm_mday, + pTime->tm_hour, + pTime->tm_min, + pTime->tm_sec ); + ret = exifTable->insertElement(TAG_DATETIME, temp_value); + } + } + + if ((NO_ERROR == ret)) { + char temp_value[5]; + snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%lu", capData->mWidth); + ret = exifTable->insertElement(TAG_IMAGE_WIDTH, temp_value); + } + + if ((NO_ERROR == ret)) { + char temp_value[5]; + snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%lu", capData->mHeight); + ret = exifTable->insertElement(TAG_IMAGE_LENGTH, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLatValid)) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d/%d,%d/%d,%d/%d", + abs(mEXIFData.mGPSData.mLatDeg), 1, + abs(mEXIFData.mGPSData.mLatMin), 1, + abs(mEXIFData.mGPSData.mLatSec), abs(mEXIFData.mGPSData.mLatSecDiv)); + ret = exifTable->insertElement(TAG_GPS_LAT, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLatValid)) { + ret = exifTable->insertElement(TAG_GPS_LAT_REF, mEXIFData.mGPSData.mLatRef); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLongValid)) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d/%d,%d/%d,%d/%d", + abs(mEXIFData.mGPSData.mLongDeg), 1, + abs(mEXIFData.mGPSData.mLongMin), 1, + abs(mEXIFData.mGPSData.mLongSec), abs(mEXIFData.mGPSData.mLongSecDiv)); + ret = exifTable->insertElement(TAG_GPS_LONG, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLongValid)) { + ret = exifTable->insertElement(TAG_GPS_LONG_REF, mEXIFData.mGPSData.mLongRef); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mAltitudeValid)) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d/%d", + abs( mEXIFData.mGPSData.mAltitude), 1); + ret = exifTable->insertElement(TAG_GPS_ALT, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mAltitudeValid)) { + char temp_value[5]; + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d", mEXIFData.mGPSData.mAltitudeRef); + ret = exifTable->insertElement(TAG_GPS_ALT_REF, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mMapDatumValid)) { + ret = exifTable->insertElement(TAG_GPS_MAP_DATUM, mEXIFData.mGPSData.mMapDatum); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mProcMethodValid)) { + char temp_value[GPS_PROCESSING_SIZE]; + + memcpy(temp_value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); + memcpy(temp_value + sizeof(ExifAsciiPrefix), + mEXIFData.mGPSData.mProcMethod, + (GPS_PROCESSING_SIZE - sizeof(ExifAsciiPrefix))); + ret = exifTable->insertElement(TAG_GPS_PROCESSING_METHOD, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mVersionIdValid)) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d,%d,%d,%d", + mEXIFData.mGPSData.mVersionId[0], + mEXIFData.mGPSData.mVersionId[1], + mEXIFData.mGPSData.mVersionId[2], + mEXIFData.mGPSData.mVersionId[3]); + ret = exifTable->insertElement(TAG_GPS_VERSION_ID, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mTimeStampValid)) { + char temp_value[256]; // arbitrarily long string + snprintf(temp_value, + sizeof(temp_value)/sizeof(char) - 1, + "%d/%d,%d/%d,%d/%d", + mEXIFData.mGPSData.mTimeStampHour, 1, + mEXIFData.mGPSData.mTimeStampMin, 1, + mEXIFData.mGPSData.mTimeStampSec, 1); + ret = exifTable->insertElement(TAG_GPS_TIMESTAMP, temp_value); + } + + if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mDatestampValid) ) { + ret = exifTable->insertElement(TAG_GPS_DATESTAMP, mEXIFData.mGPSData.mDatestamp); + } + + if (NO_ERROR == ret) { + const char* exif_orient = + ExifElementsTable::degreesToExifOrientation(mPictureRotation); + + if (exif_orient) { + ret = exifTable->insertElement(TAG_ORIENTATION, exif_orient); + } + } + + // fill in short and ushort tags + if (NO_ERROR == ret) { + char temp_value[2]; + temp_value[1] = '\0'; + + // AWB + if (mParameters3A.WhiteBallance == OMX_WhiteBalControlAuto) { + temp_value[0] = '0'; + } else { + temp_value[0] = '1'; + } + exifTable->insertElement(TAG_WHITEBALANCE, temp_value); + + // MeteringMode + // TODO(XXX): only supporting this metering mode at the moment, may change in future + temp_value[0] = '2'; + exifTable->insertElement(TAG_METERING_MODE, temp_value); + + // ExposureProgram + // TODO(XXX): only supporting this exposure program at the moment, may change in future + temp_value[0] = '3'; + exifTable->insertElement(TAG_EXPOSURE_PROGRAM, temp_value); + + // ColorSpace + temp_value[0] = '1'; + exifTable->insertElement(TAG_COLOR_SPACE, temp_value); + + temp_value[0] = '2'; + exifTable->insertElement(TAG_SENSING_METHOD, temp_value); + + temp_value[0] = '1'; + exifTable->insertElement(TAG_CUSTOM_RENDERED, temp_value); + } + + if (pAncillaryData && (NO_ERROR == ret)) { + unsigned int numerator = 0, denominator = 0; + char temp_value[256]; + unsigned int temp_num = 0; + + // DigitalZoomRatio + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u/%u", + pAncillaryData->nDigitalZoomFactor, 1024); + exifTable->insertElement(TAG_DIGITALZOOMRATIO, temp_value); + + // ExposureTime + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u/%u", + pAncillaryData->nExposureTime, 1000000); + exifTable->insertElement(TAG_EXPOSURETIME, temp_value); + + // ApertureValue and FNumber + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u/%u", + pAncillaryData->nApertureValue, 100); + exifTable->insertElement(TAG_FNUMBER, temp_value); + exifTable->insertElement(TAG_APERTURE, temp_value); + + // ISO + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u,0,0", + pAncillaryData->nCurrentISO); + exifTable->insertElement(TAG_ISO_EQUIVALENT, temp_value); + + // ShutterSpeed + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%f", + log(pAncillaryData->nExposureTime) / log(2)); + ExifElementsTable::stringToRational(temp_value, &numerator, &denominator); + snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%u/%u", numerator, denominator); + exifTable->insertElement(TAG_SHUTTERSPEED, temp_value); + + // Flash + if (mParameters3A.FlashMode == OMX_IMAGE_FlashControlAuto) { + if(pAncillaryData->nFlashStatus) temp_num = 0x19; // Flash fired, auto mode + else temp_num = 0x18; // Flash did not fire, auto mode + } else if (mParameters3A.FlashMode == OMX_IMAGE_FlashControlOn) { + if(pAncillaryData->nFlashStatus) temp_num = 0x9; // Flash fired, compulsory flash mode + else temp_num = 0x10; // Flash did not fire, compulsory flash mode + } else if(pAncillaryData->nFlashStatus) { + temp_num = 0x1; // Flash fired + } else { + temp_num = 0x0; // Flash did not fire + } + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u", temp_num); + exifTable->insertElement(TAG_FLASH, temp_value); + + if (pWhiteBalanceData) { + unsigned int lightsource = 0; + unsigned int colourtemp = pWhiteBalanceData->nColorTemperature; + bool flash_fired = (temp_num & 0x1); // value from flash above + + // stole this from framework/tools_library/src/tools_sys_exif_tags.c + if( colourtemp <= 3200 ) { + lightsource = 3; // Tungsten + } else if( colourtemp > 3200 && colourtemp <= 4800 ) { + lightsource = 2; // Fluorescent + } else if( colourtemp > 4800 && colourtemp <= 5500 ) { + lightsource = 1; // Daylight + } else if( colourtemp > 5500 && colourtemp <= 6500 ) { + lightsource = 9; // Fine weather + } else if( colourtemp > 6500 ) { + lightsource = 10; // Cloudy weather + } + + if(flash_fired) { + lightsource = 4; // Flash + } + + snprintf(temp_value, + sizeof(temp_value)/sizeof(char), + "%u", lightsource); + exifTable->insertElement(TAG_LIGHT_SOURCE, temp_value); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::convertGPSCoord(double coord, + int °, + int &min, + int &sec, + int &secDivisor) +{ + double tmp; + + LOG_FUNCTION_NAME; + + if ( coord == 0 ) { + + CAMHAL_LOGE("Invalid GPS coordinate"); + + return -EINVAL; + } + + deg = (int) floor(fabs(coord)); + tmp = ( fabs(coord) - floor(fabs(coord)) ) * GPS_MIN_DIV; + min = (int) floor(tmp); + tmp = ( tmp - floor(tmp) ) * ( GPS_SEC_DIV * GPS_SEC_ACCURACY ); + sec = (int) floor(tmp); + secDivisor = GPS_SEC_ACCURACY; + + if( sec >= ( GPS_SEC_DIV * GPS_SEC_ACCURACY ) ) { + sec = 0; + min += 1; + } + + if( min >= 60 ) { + min = 0; + deg += 1; + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXFD.cpp b/camera/OMXCameraAdapter/OMXFD.cpp new file mode 100644 index 0000000..1a482b2 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFD.cpp @@ -0,0 +1,504 @@ +/* + * 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. + */ + +/** +* @file OMXFD.cpp +* +* This file contains functionality for handling face detection. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace Ti { +namespace Camera { + +const uint32_t OMXCameraAdapter::FACE_DETECTION_THRESHOLD = 80; + +status_t OMXCameraAdapter::setParametersFD(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startFaceDetection() +{ + status_t ret = NO_ERROR; + + android::AutoMutex lock(mFaceDetectionLock); + + ret = setFaceDetection(true, mFaceOrientation); + if (ret != NO_ERROR) { + goto out; + } + + if ( mFaceDetectionRunning ) { + mFDSwitchAlgoPriority = true; + } + + // Note: White balance will not be face prioritized, since + // the algorithm needs full frame statistics, and not face + // regions alone. + + faceDetectionNumFacesLastOutput = 0; + out: + return ret; +} + +status_t OMXCameraAdapter::stopFaceDetection() +{ + status_t ret = NO_ERROR; + const char *str = NULL; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + android::AutoMutex lock(mFaceDetectionLock); + + ret = setFaceDetection(false, mFaceOrientation); + if (ret != NO_ERROR) { + goto out; + } + + if ( mFaceDetectionRunning ) { + //Enable region priority and disable face priority for AF + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true); + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO , false); + + //Enable Region priority and disable Face priority + setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, true); + setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, false); + } + + if (mPending3Asettings) { + apply3Asettings(mParameters3A); + } + + faceDetectionNumFacesLastOutput = 0; + out: + return ret; +} + +void OMXCameraAdapter::pauseFaceDetection(bool pause) +{ + android::AutoMutex lock(mFaceDetectionLock); + // pausing will only take affect if fd is already running + if (mFaceDetectionRunning) { + mFaceDetectionPaused = pause; + faceDetectionNumFacesLastOutput = 0; + } +} + +status_t OMXCameraAdapter::setFaceDetectionOrientation(OMX_U32 orientation) +{ + status_t ret = NO_ERROR; + + android::AutoMutex lock(mFaceDetectionLock); + + mFaceOrientation = orientation; + + if (mFaceDetectionRunning) { + // restart face detection with new rotation + setFaceDetection(true, orientation); + } + + return ret; +} + +status_t OMXCameraAdapter::setFaceDetection(bool enable, OMX_U32 orientation) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_OBJDETECTIONTYPE objDetection; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + if ( orientation > 270 ) { + orientation = 0; + } + + OMX_INIT_STRUCT_PTR (&objDetection, OMX_CONFIG_OBJDETECTIONTYPE); + objDetection.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + objDetection.nDeviceOrientation = orientation; + if ( enable ) + { + objDetection.bEnable = OMX_TRUE; + } + else + { + objDetection.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigImageFaceDetection, + &objDetection); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring face detection 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Face detection configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + // TODO(XXX): Should enable/disable FD extra data separately + // on each port. + ret = setExtraData(enable, OMX_ALL, OMX_FaceDetection); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Error while configuring face detection extra data"); + } + else + { + CAMHAL_LOGDA("Face detection extra data configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + mFaceDetectionRunning = enable; + mFaceDetectionPaused = !enable; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::createPreviewMetadata(OMX_BUFFERHEADERTYPE* pBuffHeader, + android::sp &result, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + status_t faceRet = NO_ERROR; + status_t metaRet = NO_ERROR; + OMX_FACEDETECTIONTYPE *faceData = NULL; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) { + CAMHAL_LOGEA("OMX component is not in executing state"); + return NO_INIT; + } + + if ( NULL == pBuffHeader ) { + CAMHAL_LOGEA("Invalid Buffer header"); + return-EINVAL; + } + + if ( mFaceDetectionRunning && !mFaceDetectionPaused ) { + OMX_OTHER_EXTRADATATYPE *extraData; + + extraData = getExtradata(pBuffHeader->pPlatformPrivate, + (OMX_EXTRADATATYPE)OMX_FaceDetection); + + if ( NULL != extraData ) { + CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x", + extraData->nSize, + sizeof(OMX_OTHER_EXTRADATATYPE), + extraData->eType, + extraData->nDataSize, + extraData->nPortIndex, + extraData->nVersion); + } else { + CAMHAL_LOGD("FD extra data not found!"); + return -EINVAL; + } + + faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data; + if ( NULL != faceData ) { + if ( sizeof(OMX_FACEDETECTIONTYPE) == faceData->nSize ) { + CAMHAL_LOGVB("Faces detected %d", + faceData->ulFaceCount, + faceData->nSize, + sizeof(OMX_FACEDETECTIONTYPE), + faceData->eCameraView, + faceData->nPortIndex, + faceData->nVersion); + } else { + CAMHAL_LOGEB("OMX_FACEDETECTIONTYPE size mismatch: expected = %d, received = %d", + ( unsigned int ) sizeof(OMX_FACEDETECTIONTYPE), + ( unsigned int ) faceData->nSize); + return -EINVAL; + } + } else { + CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE"); + return -EINVAL; + } + } + + result = new (std::nothrow) CameraMetadataResult; + if(NULL == result.get()) { + ret = NO_MEMORY; + return ret; + } + + //Encode face coordinates + faceRet = encodeFaceCoordinates(faceData, result->getMetadataResult() + , previewWidth, previewHeight); + if ((NO_ERROR == faceRet) || (NOT_ENOUGH_DATA == faceRet)) { + // Ignore harmless errors (no error and no update) and go ahead and encode + // the preview meta data + metaRet = encodePreviewMetadata(result->getMetadataResult() + , pBuffHeader->pPlatformPrivate); + if ( (NO_ERROR != metaRet) && (NOT_ENOUGH_DATA != metaRet) ) { + // Some 'real' error occurred during preview meta data encod, clear metadata + // result and return correct error code + result.clear(); + ret = metaRet; + } + } else { + //Some real error occurred during face encoding, clear metadata result + // and return correct error code + result.clear(); + ret = faceRet; + } + + if((NOT_ENOUGH_DATA == faceRet) && (NOT_ENOUGH_DATA == metaRet)) { + //No point sending the callback if nothing is changed + result.clear(); + ret = faceRet; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData, + camera_frame_metadata_t *metadataResult, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + camera_face_t *faces; + size_t hRange, vRange; + double tmp; + bool faceArrayChanged = false; + + LOG_FUNCTION_NAME; + + hRange = CameraMetadataResult::RIGHT - CameraMetadataResult::LEFT; + vRange = CameraMetadataResult::BOTTOM - CameraMetadataResult::TOP; + + android::AutoMutex lock(mFaceDetectionLock); + + // Avoid memory leak if called twice on same CameraMetadataResult + if ( (0 < metadataResult->number_of_faces) && (NULL != metadataResult->faces) ) { + free(metadataResult->faces); + metadataResult->number_of_faces = 0; + metadataResult->faces = NULL; + } + + if ( (NULL != faceData) && (0 < faceData->ulFaceCount) ) { + int orient_mult; + int trans_left, trans_top, trans_right, trans_bot; + + faces = ( camera_face_t * ) malloc(sizeof(camera_face_t)*faceData->ulFaceCount); + if ( NULL == faces ) { + ret = NO_MEMORY; + goto out; + } + + /** + / * When device is 180 degrees oriented to the sensor, need to translate + / * the output from Ducati to what Android expects + / * Ducati always gives face coordinates in this form, irrespective of + / * rotation, i.e (l,t) always represents the point towards the left eye + / * and top of hair. + / * (l, t) + / * --------------- + / * - ,,,,,,, - + / * - | | - + / * - | a>| - + / * - | | - + / * - ,,,,,,, - + / * --------------- + / * (r, b) + */ + + if (mFaceOrientation == 180) { + orient_mult = -1; + trans_left = 2; // right is now left + trans_top = 3; // bottom is now top + trans_right = 0; // left is now right + trans_bot = 1; // top is not bottom + } else { + orient_mult = 1; + trans_left = 0; // left + trans_top = 1; // top + trans_right = 2; // right + trans_bot = 3; // bottom + } + + int j = 0, i = 0; + for ( ; j < faceData->ulFaceCount ; j++) + { + OMX_S32 nLeft = 0; + OMX_S32 nTop = 0; + //Face filtering + //For real faces, it is seen that the h/w passes a score >=80 + //For false faces, we seem to get even a score of 70 sometimes. + //In order to avoid any issue at application level, we filter + //<=70 score here. + if(faceData->tFacePosition[j].nScore <= FACE_DETECTION_THRESHOLD) + continue; + + if (mFaceOrientation == 180) { + // from sensor pov, the left pos is the right corner of the face in pov of frame + nLeft = faceData->tFacePosition[j].nLeft + faceData->tFacePosition[j].nWidth; + nTop = faceData->tFacePosition[j].nTop + faceData->tFacePosition[j].nHeight; + } else { + nLeft = faceData->tFacePosition[j].nLeft; + nTop = faceData->tFacePosition[j].nTop; + } + + tmp = ( double ) nLeft / ( double ) previewWidth; + tmp *= hRange; + tmp -= hRange/2; + faces[i].rect[trans_left] = tmp; + + tmp = ( double ) nTop / ( double )previewHeight; + tmp *= vRange; + tmp -= vRange/2; + faces[i].rect[trans_top] = tmp; + + tmp = ( double ) faceData->tFacePosition[j].nWidth / ( double ) previewWidth; + tmp *= hRange; + tmp *= orient_mult; + faces[i].rect[trans_right] = faces[i].rect[trans_left] + tmp; + + tmp = ( double ) faceData->tFacePosition[j].nHeight / ( double ) previewHeight; + tmp *= vRange; + tmp *= orient_mult; + faces[i].rect[trans_bot] = faces[i].rect[trans_top] + tmp; + + faces[i].score = faceData->tFacePosition[j].nScore; + faces[i].id = 0; + faces[i].left_eye[0] = CameraMetadataResult::INVALID_DATA; + faces[i].left_eye[1] = CameraMetadataResult::INVALID_DATA; + faces[i].right_eye[0] = CameraMetadataResult::INVALID_DATA; + faces[i].right_eye[1] = CameraMetadataResult::INVALID_DATA; + faces[i].mouth[0] = CameraMetadataResult::INVALID_DATA; + faces[i].mouth[1] = CameraMetadataResult::INVALID_DATA; + i++; + } + + metadataResult->number_of_faces = i; + metadataResult->faces = faces; + + for (int i = 0; i < metadataResult->number_of_faces; i++) + { + bool faceChanged = true; + int centerX = (faces[i].rect[trans_left] + faces[i].rect[trans_right] ) / 2; + int centerY = (faces[i].rect[trans_top] + faces[i].rect[trans_bot] ) / 2; + + int sizeX = (faces[i].rect[trans_right] - faces[i].rect[trans_left] ) ; + int sizeY = (faces[i].rect[trans_bot] - faces[i].rect[trans_top] ) ; + + for (int j = 0; j < faceDetectionNumFacesLastOutput; j++) + { + int tempCenterX = (faceDetectionLastOutput[j].rect[trans_left] + + faceDetectionLastOutput[j].rect[trans_right] ) / 2; + int tempCenterY = (faceDetectionLastOutput[j].rect[trans_top] + + faceDetectionLastOutput[j].rect[trans_bot] ) / 2; + int tempSizeX = (faceDetectionLastOutput[j].rect[trans_right] - + faceDetectionLastOutput[j].rect[trans_left] ) ; + int tempSizeY = (faceDetectionLastOutput[j].rect[trans_bot] - + faceDetectionLastOutput[j].rect[trans_top] ) ; + + if ( ( tempCenterX == centerX) && + ( tempCenterY == centerY) ) { + // Found Face. + // Now check size of rectangle + // compare to last output. + if ( ( tempSizeX == sizeX ) && + ( tempSizeY == sizeY ) ) { + faceChanged = false; + } + } + } + // Send face detection data after some face coordinate changes + if (faceChanged) { + faceArrayChanged = true; + } + } + + // Save this output for next iteration + for (int i = 0; i < metadataResult->number_of_faces; i++) + { + faceDetectionLastOutput[i] = faces[i]; + } + } else { + metadataResult->number_of_faces = 0; + metadataResult->faces = NULL; + } + + // Send face detection data after face count changes + if (faceDetectionNumFacesLastOutput != metadataResult->number_of_faces) { + faceArrayChanged = true; + } + faceDetectionNumFacesLastOutput = metadataResult->number_of_faces; + + if ( !faceArrayChanged ) { + ret = NOT_ENOUGH_DATA; + } + + LOG_FUNCTION_NAME_EXIT; + +out: + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXFocus.cpp b/camera/OMXCameraAdapter/OMXFocus.cpp new file mode 100644 index 0000000..d478035 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFocus.cpp @@ -0,0 +1,892 @@ +/* + * 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. + */ + + +/** +* @file OMXFocus.cpp +* +* This file contains functionality for handling focus configurations. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +#define TOUCH_FOCUS_RANGE 0xFF +#define AF_IMAGE_CALLBACK_TIMEOUT 5000000 //5 seconds timeout +#define AF_VIDEO_CALLBACK_TIMEOUT 2800000 //2.8 seconds timeout + +namespace Ti { +namespace Camera { + +const nsecs_t OMXCameraAdapter::CANCEL_AF_TIMEOUT = seconds_to_nanoseconds(1); + +status_t OMXCameraAdapter::setParametersFocus(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + android::Vector > tempAreas; + size_t MAX_FOCUS_AREAS; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mFocusAreasLock); + + str = params.get(android::CameraParameters::KEY_FOCUS_AREAS); + + MAX_FOCUS_AREAS = atoi(params.get(android::CameraParameters::KEY_MAX_NUM_FOCUS_AREAS)); + + if ( NULL != str ) { + ret = CameraArea::parseAreas(str, ( strlen(str) + 1 ), tempAreas); + } + + if ( (NO_ERROR == ret) && CameraArea::areAreasDifferent(mFocusAreas, tempAreas) ) { + mFocusAreas.clear(); + mFocusAreas = tempAreas; + if ( MAX_FOCUS_AREAS < mFocusAreas.size() ) { + CAMHAL_LOGEB("Focus areas supported %d, focus areas set %d", + MAX_FOCUS_AREAS, + mFocusAreas.size()); + ret = -EINVAL; + } + else { + if ( !mFocusAreas.isEmpty() ) { + setTouchFocus(); + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doAutoFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; + OMX_PARAM_FOCUSSTATUSTYPE focusStatus; + OMX_CONFIG_BOOLEANTYPE bOMX; + CameraAdapter::AdapterState state; + nsecs_t timeout = 0; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component in Invalid state"); + returnFocusStatus(false); + return -EINVAL; + } + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + returnFocusStatus(false); + return NO_ERROR; + } + + if( ((AF_ACTIVE & getState()) != AF_ACTIVE) && ((AF_ACTIVE & getNextState()) != AF_ACTIVE) ) { + CAMHAL_LOGDA("Auto focus got canceled before doAutoFocus could be called"); + return NO_ERROR; + } + + // AF when fixed focus modes are set should be a no-op. + if ( ( mParameters3A.Focus == OMX_IMAGE_FocusControlOff ) || + ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) || + ( mParameters3A.Focus == OMX_IMAGE_FocusControlHyperfocal ) ) { + returnFocusStatus(true); + return NO_ERROR; + } + + OMX_INIT_STRUCT_PTR (&focusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + // If the app calls autoFocus, the camera will stop sending face callbacks. + pauseFaceDetection(true); + + // This is needed for applying FOCUS_REGION correctly + if ( (!mFocusAreas.isEmpty()) && (!mFocusAreas.itemAt(0)->isZeroArea())) + { + //Disable face priority + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + + //Enable region algorithm priority + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true); + } + + OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) mParameters3A.Focus; + + if (mParameters3A.FocusLock) { + // this basically means user never called cancelAutoFocus after a scan... + // if this is the case we need to unlock AF to ensure we will do a scan + if (set3ALock(mUserSetExpLock, mUserSetWbLock, OMX_FALSE) != NO_ERROR) { + CAMHAL_LOGEA("Error Unlocking 3A locks"); + } else { + CAMHAL_LOGDA("AE/AWB unlocked successfully"); + } + + } else if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) { + // In case we have CAF running we should first check the AF status. + // If it has managed to lock, then do as usual and return status + // immediately. + ret = checkFocus(&focusStatus); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Focus status check failed 0x%x!", ret); + return ret; + } else { + CAMHAL_LOGDB("Focus status check 0x%x!", focusStatus.eFocusStatus); + } + } + + if ( (focusControl.eFocusControl == OMX_IMAGE_FocusControlAuto && + ( focusStatus.eFocusStatus == OMX_FocusStatusRequest || + focusStatus.eFocusStatus == OMX_FocusStatusUnableToReach || + focusStatus.eFocusStatus == OMX_FocusStatusLost ) ) || + (mParameters3A.Focus != (OMX_IMAGE_FOCUSCONTROLTYPE)OMX_IMAGE_FocusControlAuto) ) { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + bOMX.bEnabled = OMX_TRUE; + + //Enable focus scanning + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutofocusEnable, + &bOMX); + if ( OMX_ErrorNone != eError ) { + return Utils::ErrorUtils::omxToAndroidError(eError); + } + + { + android::AutoMutex lock(mDoAFMutex); + + // force AF, Ducati will take care of whether CAF + // or AF will be performed, depending on light conditions + if ( focusControl.eFocusControl == OMX_IMAGE_FocusControlAuto && + ( focusStatus.eFocusStatus == OMX_FocusStatusRequest || + focusStatus.eFocusStatus == OMX_FocusStatusUnableToReach || + focusStatus.eFocusStatus == OMX_FocusStatusLost ) ) { + focusControl.eFocusControl = OMX_IMAGE_FocusControlAutoLock; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, + &focusControl); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while starting focus 0x%x", eError); + return INVALID_OPERATION; + } else { + CAMHAL_LOGDA("Autofocus started successfully"); + } + + // No need to wait if preview is about to stop + getNextState(state); + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) { + return NO_ERROR; + } + + // configure focus timeout based on capture mode + timeout = (mCapMode == VIDEO_MODE) || (mCapMode == VIDEO_MODE_HQ) ? + ( ( nsecs_t ) AF_VIDEO_CALLBACK_TIMEOUT * 1000 ) : + ( ( nsecs_t ) AF_IMAGE_CALLBACK_TIMEOUT * 1000 ); + + + ret = mDoAFCond.waitRelative(mDoAFMutex, timeout); + } + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) { + CAMHAL_LOGEA("Invalid State after Auto Focus Exitting!!!"); + return -EINVAL; + } + + if(ret != NO_ERROR) { + CAMHAL_LOGEA("Autofocus callback timeout expired"); + ret = returnFocusStatus(true); + } else { + CAMHAL_LOGDA("Autofocus callback received"); + ret = returnFocusStatus(false); + } + } else { // Focus mode in continuous + if ( NO_ERROR == ret ) { + ret = returnFocusStatus(true); + mPending3Asettings |= SetFocus; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopAutoFocus() +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component in Invalid state"); + returnFocusStatus(false); + return -EINVAL; + } + + if ( OMX_StateExecuting != mComponentState ) { + CAMHAL_LOGEA("OMX component not in executing state"); + return NO_ERROR; + } + + if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) { + // No need to stop focus if we are in infinity mode. Nothing to stop. + return NO_ERROR; + } + + OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focusControl.eFocusControl = OMX_IMAGE_FocusControlOff; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, + &focusControl); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while stopping focus 0x%x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } +#ifdef CAMERAHAL_TUNA + else { + // This is a WA. Usually the OMX Camera component should + // generate AF status change OMX event fairly quickly + // ( after one preview frame ) and this notification should + // actually come from 'handleFocusCallback()'. + android::AutoMutex lock(mDoAFMutex); + mDoAFCond.broadcast(); + } +#endif + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t OMXCameraAdapter::getFocusMode(OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE &focusMode) +{; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&focusMode, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focusMode.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, + &focusMode); + + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error while retrieving focus mode 0x%x", eError); + } + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::cancelAutoFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusMode; + + LOG_FUNCTION_NAME; + + ret = getFocusMode(focusMode); + if ( NO_ERROR != ret ) { + return ret; + } + + //Stop the AF only for modes other than CAF, Inifinity or Off + if ( ( focusMode.eFocusControl != OMX_IMAGE_FocusControlAuto ) && + ( focusMode.eFocusControl != ( OMX_IMAGE_FOCUSCONTROLTYPE ) + OMX_IMAGE_FocusControlAutoInfinity ) && + ( focusMode.eFocusControl != OMX_IMAGE_FocusControlOff ) ) { + android::AutoMutex lock(mCancelAFMutex); + stopAutoFocus(); + ret = mCancelAFCond.waitRelative(mCancelAFMutex, CANCEL_AF_TIMEOUT); + if ( NO_ERROR != ret ) { + CAMHAL_LOGE("Cancel AF timeout!"); + } + } else if (focusMode.eFocusControl == OMX_IMAGE_FocusControlAuto) { + // This re-enabling of CAF doesn't seem to + // be needed any more. + // re-apply CAF after unlocking and canceling + // mPending3Asettings |= SetFocus; + } + + { + // Signal to 'doAutoFocus()' + android::AutoMutex lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + + // If the apps call #cancelAutoFocus()}, the face callbacks will also resume. + pauseFaceDetection(false); + + LOG_FUNCTION_NAME_EXIT; + + return ret; + +} + +status_t OMXCameraAdapter::setFocusCallback(bool enabled) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CALLBACKREQUESTTYPE focusRequstCallback; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component in Invalid state"); + ret = -EINVAL; + } + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&focusRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); + focusRequstCallback.nPortIndex = OMX_ALL; + focusRequstCallback.nIndex = OMX_IndexConfigCommonFocusStatus; + + if ( enabled ) + { + focusRequstCallback.bEnable = OMX_TRUE; + } + else + { + focusRequstCallback.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigCallbackRequest, + &focusRequstCallback); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error registering focus callback 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("Autofocus callback for index 0x%x registered successfully", + OMX_IndexConfigCommonFocusStatus); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::returnFocusStatus(bool timeoutReached) +{ + status_t ret = NO_ERROR; + OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus; + CameraHalEvent::FocusStatus focusStatus = CameraHalEvent::FOCUS_STATUS_FAIL; + BaseCameraAdapter::AdapterState state, nextState; + BaseCameraAdapter::getState(state); + BaseCameraAdapter::getNextState(nextState); + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + if( ((AF_ACTIVE & state ) != AF_ACTIVE) && ((AF_ACTIVE & nextState ) != AF_ACTIVE) ) + { + /// We don't send focus callback if focus was not started + CAMHAL_LOGDA("Not sending focus callback because focus was not started"); + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + + if ( !timeoutReached ) + { + ret = checkFocus(&eFocusStatus); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Focus status check failed!"); + } + } + } + + if ( NO_ERROR == ret ) + { + + if ( timeoutReached ) + { + focusStatus = CameraHalEvent::FOCUS_STATUS_FAIL; + } + else + { + switch (eFocusStatus.eFocusStatus) + { + case OMX_FocusStatusReached: + { + focusStatus = CameraHalEvent::FOCUS_STATUS_SUCCESS; + break; + } + case OMX_FocusStatusOff: // AF got canceled + return NO_ERROR; + case OMX_FocusStatusUnableToReach: + case OMX_FocusStatusRequest: + default: + { + focusStatus = CameraHalEvent::FOCUS_STATUS_FAIL; + break; + } + } + // Lock CAF after AF call + if( set3ALock(mUserSetExpLock, mUserSetWbLock, OMX_TRUE) != NO_ERROR) { + CAMHAL_LOGEA("Error Applying 3A locks"); + } else { + CAMHAL_LOGDA("Focus locked. Applied focus locks successfully"); + } + + stopAutoFocus(); + } + //Query current focus distance after AF is complete + updateFocusDistances(mParameters); + } + + ret = BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS); + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + if ( NO_ERROR == ret ) + { + notifyFocusSubscribers(focusStatus); + } + + // After focus, face detection will resume sending face callbacks + pauseFaceDetection(false); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( NULL == eFocusStatus ) + { + CAMHAL_LOGEA("Invalid focus status"); + ret = -EINVAL; + } + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component in Invalid state"); + ret = -EINVAL; + } + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + ret = NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonFocusStatus, + eFocusStatus); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError); + ret = -1; + } + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::updateFocusDistances(android::CameraParameters ¶ms) +{ + OMX_U32 focusNear, focusOptimal, focusFar; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + ret = getFocusDistances(focusNear, focusOptimal, focusFar); + if ( NO_ERROR == ret) + { + ret = addFocusDistances(focusNear, focusOptimal, focusFar, params); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret); + } + } + else + { + CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError; + + OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = UNKNOWN_ERROR; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE); + focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance, + &focusDist); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError); + ret = UNKNOWN_ERROR; + } + + } + + if ( NO_ERROR == ret ) + { + near = focusDist.nFocusDistanceNear; + optimal = focusDist.nFocusDistanceOptimal; + far = focusDist.nFocusDistanceFar; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length) +{ + status_t ret = NO_ERROR; + uint32_t focusScale = 1000; + float distFinal; + + LOG_FUNCTION_NAME; + + if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) + { + dist=0; + } + + if ( NO_ERROR == ret ) + { + if ( 0 == dist ) + { + strncpy(buffer, android::CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 )); + } + else + { + distFinal = dist; + distFinal /= focusScale; + snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near, + OMX_U32 &optimal, + OMX_U32 &far, + android::CameraParameters& params) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear, + mFocusDistOptimal, + mFocusDistFar); + + params.set(android::CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setTouchFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + OMX_ALGOAREASTYPE *focusAreas; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + CameraBuffer *bufferlist; + int areasSize = 0; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + + areasSize = ((sizeof(OMX_ALGOAREASTYPE)+4095)/4096)*4096; + bufferlist = mMemMgr.allocateBufferList(0, 0, NULL, areasSize, 1); + focusAreas = (OMX_ALGOAREASTYPE*) bufferlist[0].opaque; + + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + if (!focusAreas) + { + CAMHAL_LOGEB("Error allocating buffer for focus areas %d", eError); + return -ENOMEM; + } + + OMX_INIT_STRUCT_PTR (focusAreas, OMX_ALGOAREASTYPE); + + focusAreas->nPortIndex = OMX_ALL; + focusAreas->nNumAreas = mFocusAreas.size(); + focusAreas->nAlgoAreaPurpose = OMX_AlgoAreaFocus; + + // If the area is the special case of (0, 0, 0, 0, 0), then + // the algorithm needs nNumAreas to be set to 0, + // in order to automatically choose the best fitting areas. + if ( mFocusAreas.itemAt(0)->isZeroArea() ) + { + focusAreas->nNumAreas = 0; + } + + for ( unsigned int n = 0; n < mFocusAreas.size(); n++) { + int widthDivisor = 1; + int heightDivisor = 1; + + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutTopBottom) { + heightDivisor = 2; + } + if (mPreviewData->mFrameLayoutType == OMX_TI_StereoFrameLayoutLeftRight) { + widthDivisor = 2; + } + + // transform the coordinates to 3A-type coordinates + mFocusAreas.itemAt(n)->transfrom((size_t)mPreviewData->mWidth/widthDivisor, + (size_t)mPreviewData->mHeight/heightDivisor, + (size_t&)focusAreas->tAlgoAreas[n].nTop, + (size_t&)focusAreas->tAlgoAreas[n].nLeft, + (size_t&)focusAreas->tAlgoAreas[n].nWidth, + (size_t&)focusAreas->tAlgoAreas[n].nHeight); + + focusAreas->tAlgoAreas[n].nLeft = + ( focusAreas->tAlgoAreas[n].nLeft * TOUCH_FOCUS_RANGE ) / mPreviewData->mWidth; + focusAreas->tAlgoAreas[n].nTop = + ( focusAreas->tAlgoAreas[n].nTop* TOUCH_FOCUS_RANGE ) / mPreviewData->mHeight; + focusAreas->tAlgoAreas[n].nWidth = + ( focusAreas->tAlgoAreas[n].nWidth * TOUCH_FOCUS_RANGE ) / mPreviewData->mWidth; + focusAreas->tAlgoAreas[n].nHeight = + ( focusAreas->tAlgoAreas[n].nHeight * TOUCH_FOCUS_RANGE ) / mPreviewData->mHeight; + focusAreas->tAlgoAreas[n].nPriority = mFocusAreas.itemAt(n)->getWeight(); + + CAMHAL_LOGDB("Focus area %d : top = %d left = %d width = %d height = %d prio = %d", + n, (int)focusAreas->tAlgoAreas[n].nTop, (int)focusAreas->tAlgoAreas[n].nLeft, + (int)focusAreas->tAlgoAreas[n].nWidth, (int)focusAreas->tAlgoAreas[n].nHeight, + (int)focusAreas->tAlgoAreas[n].nPriority); + } + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = areasSize; + sharedBuffer.pSharedBuff = (OMX_U8 *) camera_buffer_get_omx_ptr (&bufferlist[0]); + + if ( NULL == sharedBuffer.pSharedBuff ) + { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = -ENOMEM; + goto EXIT; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_TI_IndexConfigAlgoAreas, &sharedBuffer); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting Focus Areas configuration 0x%x", eError); + ret = -EINVAL; + } + + EXIT: + if (NULL != bufferlist) + { + mMemMgr.freeBufferList (bufferlist); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void OMXCameraAdapter::handleFocusCallback() { + OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus; + CameraHalEvent::FocusStatus focusStatus = CameraHalEvent::FOCUS_STATUS_FAIL; + status_t ret = NO_ERROR; + BaseCameraAdapter::AdapterState nextState, currentState; + BaseCameraAdapter::getNextState(nextState); + BaseCameraAdapter::getState(currentState); + + // Dropping AF callback if it triggered in non AF state + if ((currentState != AF_STATE) && (currentState != AF_ZOOM_STATE) && + (currentState != VIDEO_AF_STATE) && (nextState != VIDEO_AF_STATE) && + (nextState != AF_STATE) && (nextState != AF_ZOOM_STATE)) { + return; + } + + OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + ret = checkFocus(&eFocusStatus); + + if (NO_ERROR != ret) { + CAMHAL_LOGEA("Focus status check failed!"); + // signal and unblock doAutoFocus + if (AF_ACTIVE & nextState) { + android::AutoMutex lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + return; + } + + if ( eFocusStatus.eFocusStatus == OMX_FocusStatusOff ) { + android::AutoMutex lock(mCancelAFMutex); + mCancelAFCond.signal(); + return; + } + + if (eFocusStatus.eFocusStatus != OMX_FocusStatusRequest) { + // signal doAutoFocus when a end of scan message comes + // ignore start of scan + android::AutoMutex lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + + if (mParameters3A.Focus != (OMX_IMAGE_FOCUSCONTROLTYPE) OMX_IMAGE_FocusControlAuto) { + CAMHAL_LOGDA("unregistered focus callback when not in CAF or doAutoFocus... not handling"); + return; + } + + // Handling for CAF Callbacks + switch (eFocusStatus.eFocusStatus) { + case OMX_FocusStatusRequest: + focusStatus = CameraHalEvent::FOCUS_STATUS_PENDING; + break; + case OMX_FocusStatusReached: + case OMX_FocusStatusOff: + case OMX_FocusStatusUnableToReach: + default: + focusStatus = CameraHalEvent::FOCUS_STATUS_DONE; + break; + } + + notifyFocusSubscribers(focusStatus); +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXMetadata.cpp b/camera/OMXCameraAdapter/OMXMetadata.cpp new file mode 100644 index 0000000..af8c49c --- /dev/null +++ b/camera/OMXCameraAdapter/OMXMetadata.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +/** +* @file OMX3A.cpp +* +* This file contains functionality for handling 3A configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "OMXMetaData" + +#include "OMXCameraAdapter.h" +#include + +namespace Ti { +namespace Camera { + +#ifdef OMAP_ENHANCEMENT_CPCAM +camera_memory_t * OMXCameraAdapter::getMetaData(const OMX_PTR plat_pvt, + camera_request_memory allocator) const +{ + camera_memory_t * ret = NULL; + + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_FACEDETECTIONTYPE *faceData = NULL; + OMX_TI_WHITEBALANCERESULTTYPE * WBdata = NULL; + OMX_TI_VECTSHOTINFOTYPE *shotInfo = NULL; + OMX_TI_LSCTABLETYPE *lscTbl = NULL; + camera_metadata_t *metaData; + size_t offset = 0; + + size_t metaDataSize = sizeof(camera_metadata_t); + + extraData = getExtradata(plat_pvt, (OMX_EXTRADATATYPE) OMX_FaceDetection); + if ( NULL != extraData ) { + faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data; + metaDataSize += faceData->ulFaceCount * sizeof(camera_metadata_face_t); + } + + extraData = getExtradata(plat_pvt, (OMX_EXTRADATATYPE) OMX_WhiteBalance); + if ( NULL != extraData ) { + WBdata = ( OMX_TI_WHITEBALANCERESULTTYPE * ) extraData->data; + } + + extraData = getExtradata(plat_pvt, (OMX_EXTRADATATYPE) OMX_TI_VectShotInfo); + if ( NULL != extraData ) { + shotInfo = ( OMX_TI_VECTSHOTINFOTYPE * ) extraData->data; + } + + extraData = getExtradata(plat_pvt, (OMX_EXTRADATATYPE) OMX_TI_LSCTable); + if ( NULL != extraData ) { + lscTbl = ( OMX_TI_LSCTABLETYPE * ) extraData->data; + metaDataSize += OMX_TI_LSC_GAIN_TABLE_SIZE; + } + + ret = allocator(-1, metaDataSize, 1, NULL); + if ( NULL == ret ) { + return NULL; + } else { + metaData = static_cast (ret->data); + offset += sizeof(camera_metadata_t); + } + + if ( NULL != faceData ) { + metaData->number_of_faces = 0; + int idx = 0; + metaData->faces_offset = offset; + struct camera_metadata_face *faces = reinterpret_cast (static_cast(ret->data) + offset); + for ( int j = 0; j < faceData->ulFaceCount ; j++ ) { + if(faceData->tFacePosition[j].nScore <= FACE_DETECTION_THRESHOLD) { + continue; + } + idx = metaData->number_of_faces; + metaData->number_of_faces++; + // TODO: Rework and re-use encodeFaceCoordinates() + faces[idx].left = faceData->tFacePosition[j].nLeft; + faces[idx].top = faceData->tFacePosition[j].nTop; + faces[idx].bottom = faceData->tFacePosition[j].nWidth; + faces[idx].right = faceData->tFacePosition[j].nHeight; + } + offset += sizeof(camera_metadata_face_t) * metaData->number_of_faces; + } + + if ( NULL != WBdata ) { + metaData->awb_temp = WBdata->nColorTemperature; + metaData->gain_b = WBdata->nGainB; + metaData->gain_gb = WBdata->nGainGB; + metaData->gain_gr = WBdata->nGainGR; + metaData->gain_r = WBdata->nGainR; + metaData->offset_b = WBdata->nOffsetB; + metaData->offset_gb = WBdata->nOffsetGB; + metaData->offset_gr = WBdata->nOffsetGR; + metaData->offset_r = WBdata->nOffsetR; + } + + if ( NULL != lscTbl ) { + metaData->lsc_table_applied = lscTbl->bApplied; + metaData->lsc_table_size = OMX_TI_LSC_GAIN_TABLE_SIZE; + metaData->lsc_table_offset = offset; + uint8_t *lsc_table = reinterpret_cast (static_cast(ret->data) + offset); + memcpy(lsc_table, lscTbl->pGainTable, OMX_TI_LSC_GAIN_TABLE_SIZE); + offset += metaData->lsc_table_size; + } + + if ( NULL != shotInfo ) { + metaData->frame_number = shotInfo->nFrameNum; + metaData->shot_number = shotInfo->nConfigId; + metaData->analog_gain = shotInfo->nAGain; + metaData->analog_gain_req = shotInfo->nReqGain; + metaData->analog_gain_min = shotInfo->nGainMin; + metaData->analog_gain_max = shotInfo->nGainMax; + metaData->analog_gain_error = shotInfo->nSenAGainErr; + metaData->analog_gain_dev = shotInfo->nDevAGain; + metaData->exposure_time = shotInfo->nExpTime; + metaData->exposure_time_req = shotInfo->nReqExpTime; + metaData->exposure_time_min = shotInfo->nExpMin; + metaData->exposure_time_max = shotInfo->nExpMax; + metaData->exposure_time_dev = shotInfo->nDevExpTime; + metaData->exposure_time_error = shotInfo->nSenExpTimeErr; + metaData->exposure_compensation_req = shotInfo->nReqEC; + metaData->exposure_dev = shotInfo->nDevEV; + } + + return ret; +} +#endif + +status_t OMXCameraAdapter::encodePreviewMetadata(camera_frame_metadata_t *meta, const OMX_PTR plat_pvt) +{ + status_t ret = NO_ERROR; +#ifdef OMAP_ENHANCEMENT_CPCAM + OMX_OTHER_EXTRADATATYPE *extraData = NULL; + + extraData = getExtradata(plat_pvt, (OMX_EXTRADATATYPE) OMX_TI_VectShotInfo); + + if ( (NULL != extraData) && (NULL != extraData->data) ) { + OMX_TI_VECTSHOTINFOTYPE *shotInfo; + shotInfo = (OMX_TI_VECTSHOTINFOTYPE*) extraData->data; + + meta->analog_gain = shotInfo->nAGain; + meta->exposure_time = shotInfo->nExpTime; + } else { + meta->analog_gain = -1; + meta->exposure_time = -1; + } + + // Send metadata event only after any value has been changed + if ((metadataLastAnalogGain == meta->analog_gain) && + (metadataLastExposureTime == meta->exposure_time)) { + ret = NOT_ENOUGH_DATA; + } else { + metadataLastAnalogGain = meta->analog_gain; + metadataLastExposureTime = meta->exposure_time; + } +#else + // no-op in non enhancement mode + CAMHAL_UNUSED(meta); + CAMHAL_UNUSED(plat_pvt); +#endif + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXReprocess.cpp b/camera/OMXCameraAdapter/OMXReprocess.cpp new file mode 100644 index 0000000..6fdbe7b --- /dev/null +++ b/camera/OMXCameraAdapter/OMXReprocess.cpp @@ -0,0 +1,382 @@ +/* + * 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. + */ + +/** +* @file OMXReprocess.cpp +* +* This file contains functionality for handling reprocessing operations. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + + +namespace Ti { +namespace Camera { + +status_t OMXCameraAdapter::setParametersReprocess(const android::CameraParameters ¶ms, + CameraBuffer* buffers, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + int w, h, s; + OMX_COLOR_FORMATTYPE pixFormat; + OMXCameraPortParameters *portData; + const char* valstr; + + LOG_FUNCTION_NAME; + + if (!buffers) { + CAMHAL_LOGE("invalid buffer array"); + return BAD_VALUE; + } + + portData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex]; + + w = buffers[0].width; + h = buffers[0].height; + s = buffers[0].stride; + + valstr = buffers[0].format; + if (valstr != NULL) { + if(strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } else if (strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) { + CAMHAL_LOGDA("RAW Picture format selected"); + pixFormat = OMX_COLOR_FormatRawBayer10bit; + } else if (strcmp(valstr, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + CAMHAL_LOGDA("YUV422i Picture format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } else { + CAMHAL_LOGDA("Format not supported, selecting YUV420SP by default"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + } else { + CAMHAL_LOGDA("Format not supported, selecting YUV420SP by default"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + + if ( (w != (int)portData->mWidth) || (h != (int)portData->mHeight) || + (s != (int) portData->mStride) || (pixFormat != portData->mColorFormat)) { + portData->mWidth = w; + portData->mHeight = h; + + if ( ( OMX_COLOR_FormatRawBayer10bit == pixFormat ) || + ( OMX_COLOR_FormatCbYCrY == pixFormat ) ) { + portData->mStride = w * 2; + } else { + portData->mStride = s; + } + + portData->mColorFormat = pixFormat; + + mPendingReprocessSettings |= SetFormat; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startReprocess() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * portData = NULL; + + LOG_FUNCTION_NAME; + CAMHAL_LOGD ("mReprocConfigured = %d", mReprocConfigured); + if (!mReprocConfigured) { + return NO_ERROR; + } + + portData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex]; + + CAMHAL_LOGD ("mReprocConfigured = %d", mBurstFramesQueued); + if (NO_ERROR == ret) { + android::AutoMutex lock(mBurstLock); + + for ( int index = 0 ; index < portData->mMaxQueueable ; index++ ) { + CAMHAL_LOGDB("Queuing buffer on video input port - %p, offset: %d, length: %d", + portData->mBufferHeader[index]->pBuffer, + portData->mBufferHeader[index]->nOffset, + portData->mBufferHeader[index]->nFilledLen); + portData->mStatus[index] = OMXCameraPortParameters::FILL; + eError = OMX_EmptyThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)portData->mBufferHeader[index]); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + CameraHal::PPM("startReprocess buffers queued on video port: ", &mStartCapture); +#endif + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::stopReprocess() +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *portData = NULL; + + if (!mReprocConfigured) { + return NO_ERROR; + } + + portData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex]; + + // Disable port - send command and then free all buffers + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoInPortIndex, + mStopReprocSem); + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoInPortIndex, + NULL); + if (portData) { + CAMHAL_LOGDB("Freeing buffers on reproc port - num: %d", portData->mNumBufs); + for (int index = 0 ; index < portData->mNumBufs ; index++) { + CAMHAL_LOGDB("Freeing buffer on reproc port - 0x%x", + ( unsigned int ) portData->mBufferHeader[index]->pBuffer); + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mVideoInPortIndex, + (OMX_BUFFERHEADERTYPE*)portData->mBufferHeader[index]); + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + CAMHAL_LOGDA("Waiting for port disable"); + ret = mStopReprocSem.WaitTimeout(OMX_CMD_TIMEOUT); + if (mComponentState == OMX_StateInvalid) { + CAMHAL_LOGEA("Invalid State after Disable Image Port Exitting!!!"); + goto EXIT; + } + if (NO_ERROR == ret) { + CAMHAL_LOGDA("Port disabled"); + } else { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mVideoInPortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port disable"); + goto EXIT; + } + + deinitInternalBuffers(mCameraAdapterParameters.mVideoInPortIndex); + + mReprocConfigured = false; + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::disableReprocess(){ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + // no-op..for now + +EXIT: + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::UseBuffersReprocess(CameraBuffer *bufArr, int num) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *portData = NULL; + + portData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mVideoInPortIndex]; + + if ( 0 != mUseReprocessSem.Count() ) { + CAMHAL_LOGEB("Error mUseReprocessSem semaphore count %d", mUseReprocessSem.Count()); + return BAD_VALUE; + } + + CAMHAL_ASSERT(num > 0); + + if (mAdapterState == REPROCESS_STATE) { + stopReprocess(); + } else if (mAdapterState == CAPTURE_STATE) { + stopImageCapture(); + stopReprocess(); + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Reprocess stopping image capture and disabling image port: ", &bufArr->ppmStamp); + +#endif + + portData->mNumBufs = num; + + // Configure + ret = setParametersReprocess(mParams, bufArr, mAdapterState); + + if (mReprocConfigured) { + if (mPendingReprocessSettings & ECaptureParamSettings) { + stopReprocess(); + } else { + // Tap in port has been already configured. + return NO_ERROR; + } + } + + if (mPendingReprocessSettings & SetFormat) { + mPendingReprocessSettings &= ~SetFormat; + ret = setFormat(OMX_CAMERA_PORT_VIDEO_IN_VIDEO, *portData); + if ( ret != NO_ERROR ) { + CAMHAL_LOGEB("setFormat() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + } + + // Configure DOMX to use either gralloc handles or vptrs + OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles; + OMX_INIT_STRUCT_PTR (&domxUseGrallocHandles, OMX_TI_PARAMUSENATIVEBUFFER); + + domxUseGrallocHandles.nPortIndex = mCameraAdapterParameters.mVideoInPortIndex; + if (bufArr[0].type == CAMERA_BUFFER_ANW) { + CAMHAL_LOGD("Using ANW"); + domxUseGrallocHandles.bEnable = OMX_TRUE; + + // Need to allocate tiler reservation and state we are going to be using + // pagelist buffers. Assuming this happens when buffers if from anw + initInternalBuffers(mCameraAdapterParameters.mVideoInPortIndex); + } else { + CAMHAL_LOGD("Using ION"); + domxUseGrallocHandles.bEnable = OMX_FALSE; + } + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles); + if (eError!=OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Reprocess configuration done: ", &bufArr->ppmStamp); + +#endif + + // Enable Port + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoInPortIndex, + mUseReprocessSem); + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoInPortIndex, + NULL); + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + for (int index = 0 ; index < portData->mNumBufs ; index++) + { + OMX_BUFFERHEADERTYPE *pBufferHdr; + CAMHAL_LOGDB("OMX_UseBuffer Capture address: 0x%x, size = %d", + (unsigned int)bufArr[index].opaque, + (int)portData->mBufSize); + + eError = OMX_UseBuffer(mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mVideoInPortIndex, + 0, + portData->mBufSize, + (OMX_U8*)camera_buffer_get_omx_ptr(&bufArr[index])); + + CAMHAL_LOGDB("OMX_UseBuffer = 0x%x", eError); + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR) &bufArr[index]; + bufArr[index].index = index; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0; + pBufferHdr->nVersion.s.nStep = 0; + pBufferHdr->nOffset = bufArr[index].offset; + pBufferHdr->nFilledLen = bufArr[index].actual_size; + portData->mBufferHeader[index] = pBufferHdr; + } + + // Wait for port enable event + CAMHAL_LOGDA("Waiting for port enable"); + ret = mUseReprocessSem.WaitTimeout(OMX_CMD_TIMEOUT); + + // Error out if somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) { + CAMHAL_LOGEA("Invalid State while trying to enable port for reprocessing"); + goto EXIT; + } + + if (ret == NO_ERROR) { + CAMHAL_LOGDA("Port enabled"); + } else { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mVideoInPortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port enable"); + goto EXIT; + } + + mReprocConfigured = true; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Reprocess video port enabled and buffers registered: ", &bufArr->ppmStamp); + +#endif + + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + // Release image buffers + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | Utils::ErrorUtils::omxToAndroidError(eError)); + +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OMXCameraAdapter/OMXZoom.cpp b/camera/OMXCameraAdapter/OMXZoom.cpp new file mode 100644 index 0000000..e39a3b0 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXZoom.cpp @@ -0,0 +1,289 @@ +/* + * 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. + */ + +/** +* @file OMXZoom.cpp +* +* This file contains functionality for handling zoom configurations. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace Ti { +namespace Camera { + +const int32_t OMXCameraAdapter::ZOOM_STEPS [ZOOM_STAGES] = { + 65536, 68157, 70124, 72745, + 75366, 77988, 80609, 83231, + 86508, 89784, 92406, 95683, + 99615, 102892, 106168, 110100, + 114033, 117965, 122552, 126484, + 131072, 135660, 140247, 145490, + 150733, 155976, 161219, 167117, + 173015, 178913, 185467, 192020, + 198574, 205783, 212992, 220201, + 228065, 236585, 244449, 252969, + 262144, 271319, 281149, 290980, + 300810, 311951, 322437, 334234, + 346030, 357827, 370934, 384041, + 397148, 411566, 425984, 441057, + 456131, 472515, 488899, 506593, + 524288 }; + + +status_t OMXCameraAdapter::setParametersZoom(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + android::AutoMutex lock(mZoomLock); + + LOG_FUNCTION_NAME; + + //Immediate zoom should not be avaialable while smooth zoom is running + if ( ( ZOOM_ACTIVE & state ) != ZOOM_ACTIVE ) + { + int zoom = params.getInt(android::CameraParameters::KEY_ZOOM); + if (( zoom >= 0 ) && ( zoom < mMaxZoomSupported )) { + mTargetZoomIdx = zoom; + + //Immediate zoom should be applied instantly ( CTS requirement ) + mCurrentZoomIdx = mTargetZoomIdx; + if(!mZoomUpdating) { + doZoom(mCurrentZoomIdx); + mZoomUpdating = true; + } else { + mZoomUpdate = true; + } + + CAMHAL_LOGDB("Zoom by App %d", zoom); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doZoom(int index) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SCALEFACTORTYPE zoomControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if (( 0 > index) || ((mMaxZoomSupported - 1 ) < index )) { + CAMHAL_LOGEB("Zoom index %d out of range", index); + ret = -EINVAL; + } + + if (mPreviousZoomIndx == index ) + { + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&zoomControl, OMX_CONFIG_SCALEFACTORTYPE); + zoomControl.nPortIndex = OMX_ALL; + zoomControl.xHeight = ZOOM_STEPS[index]; + zoomControl.xWidth = ZOOM_STEPS[index]; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonDigitalZoom, + &zoomControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while applying digital zoom 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Digital zoom applied successfully"); + mPreviousZoomIndx = index; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::advanceZoom() +{ + status_t ret = NO_ERROR; + AdapterState state; + android::AutoMutex lock(mZoomLock); + + BaseCameraAdapter::getState(state); + + if ( mReturnZoomStatus ) + { + mCurrentZoomIdx +=mZoomInc; + mTargetZoomIdx = mCurrentZoomIdx; + mReturnZoomStatus = false; + ret = doZoom(mCurrentZoomIdx); + notifyZoomSubscribers(mCurrentZoomIdx, true); + } + else if ( mCurrentZoomIdx != mTargetZoomIdx ) + { + if ( ZOOM_ACTIVE & state ) + { + if ( mCurrentZoomIdx < mTargetZoomIdx ) + { + mZoomInc = 1; + } + else + { + mZoomInc = -1; + } + + mCurrentZoomIdx += mZoomInc; + } + else + { + mCurrentZoomIdx = mTargetZoomIdx; + } + + ret = doZoom(mCurrentZoomIdx); + + if ( ZOOM_ACTIVE & state ) + { + if ( mCurrentZoomIdx == mTargetZoomIdx ) + { + CAMHAL_LOGDB("[Goal Reached] Smooth Zoom notify currentIdx = %d, targetIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + + if ( NO_ERROR == ret ) + { + + ret = BaseCameraAdapter::setState(CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + mReturnZoomStatus = false; + notifyZoomSubscribers(mCurrentZoomIdx, true); + } + else + { + CAMHAL_LOGDB("[Advancing] Smooth Zoom notify currentIdx = %d, targetIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + notifyZoomSubscribers(mCurrentZoomIdx, false); + } + } + } + else if ( (mCurrentZoomIdx == mTargetZoomIdx ) && + ( ZOOM_ACTIVE & state ) ) + { + ret = BaseCameraAdapter::setState(CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + + if(mZoomUpdate) { + doZoom(mTargetZoomIdx); + mZoomUpdate = false; + mZoomUpdating = true; + } else { + mZoomUpdating = false; + } + + return ret; +} + +status_t OMXCameraAdapter::startSmoothZoom(int targetIdx) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mZoomLock); + + CAMHAL_LOGDB("Start smooth zoom target = %d, mCurrentIdx = %d", + targetIdx, + mCurrentZoomIdx); + + if (( targetIdx >= 0 ) && ( targetIdx < mMaxZoomSupported )) { + mTargetZoomIdx = targetIdx; + mZoomParameterIdx = mCurrentZoomIdx; + mReturnZoomStatus = false; + } else { + CAMHAL_LOGEB("Smooth value out of range %d!", targetIdx); + ret = -EINVAL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopSmoothZoom() +{ + status_t ret = NO_ERROR; + android::AutoMutex lock(mZoomLock); + + LOG_FUNCTION_NAME; + + if ( mTargetZoomIdx != mCurrentZoomIdx ) + { + if ( mCurrentZoomIdx < mTargetZoomIdx ) + { + mZoomInc = 1; + } + else + { + mZoomInc = -1; + } + mReturnZoomStatus = true; + mReturnZoomStatus = true; + CAMHAL_LOGDB("Stop smooth zoom mCurrentZoomIdx = %d, mTargetZoomIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/OmxFrameDecoder.cpp b/camera/OmxFrameDecoder.cpp new file mode 100644 index 0000000..be794e5 --- /dev/null +++ b/camera/OmxFrameDecoder.cpp @@ -0,0 +1,1077 @@ +/* + * 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 "ErrorUtils.h" +#include "OmxFrameDecoder.h" +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Index.h" +#include "Decoder_libjpeg.h" + + +namespace Ti { +namespace Camera { + +const static uint32_t kMaxColorFormatSupported = 1000; +const static int kMaxStateSwitchTimeOut = 1 * 1000 * 1000 * 1000; // 1 sec + +static const char* gDecoderRole[2] = {"video_decoder.mjpeg", "video_decoder.avc"}; +static const OMX_VIDEO_CODINGTYPE gCompressionFormat[2] = {OMX_VIDEO_CodingMJPEG, OMX_VIDEO_CodingAVC}; + + +template +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + + + +CallbackDispatcher::CallbackDispatcher() +: mDone(false) { + mThread = new CallbackDispatcherThread(this); + mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND); +} + +CallbackDispatcher::~CallbackDispatcher() { + { + android::Mutex::Autolock autoLock(mLock); + + mDone = true; + mQueueChanged.signal(); + } + + status_t status = mThread->join(); + if (status != WOULD_BLOCK) { + //CAMHAL_ASSERT(status, (status_t)NO_ERROR); + } +} + +void CallbackDispatcher::post(const OmxMessage &msg) { + android::Mutex::Autolock autoLock(mLock); + + mQueue.push_back(msg); + mQueueChanged.signal(); +} + +void CallbackDispatcher::dispatch(const OmxMessage &msg) { + + switch(msg.type) + { + case OmxMessage::EVENT : + { + static_cast(msg.u.eventData.appData)->eventHandler(msg.u.eventData.event, msg.u.eventData.data1, msg.u.eventData.data2, msg.u.eventData.pEventData); + break; + } + + case OmxMessage::EMPTY_BUFFER_DONE: + { + static_cast(msg.u.bufferData.appData)->emptyBufferDoneHandler(msg.u.bufferData.pBuffHead); + break; + } + + case OmxMessage::FILL_BUFFER_DONE: + { + static_cast(msg.u.bufferData.appData)->fillBufferDoneHandler(msg.u.bufferData.pBuffHead); + break; + } + }; +} + +bool CallbackDispatcher::loop() { + for (;;) { + OmxMessage msg; + + { + android::Mutex::Autolock autoLock(mLock); + while (!mDone && mQueue.empty()) { + mQueueChanged.wait(mLock); + } + + if (mDone) { + break; + } + + msg = *mQueue.begin(); + mQueue.erase(mQueue.begin()); + } + + dispatch(msg); + } + + return false; +} + +bool CallbackDispatcherThread::threadLoop() { + return mDispatcher->loop(); +} + +//Static +OMX_ERRORTYPE OmxFrameDecoder::eventCallback(const OMX_HANDLETYPE component, + const OMX_PTR appData, const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2, + const OMX_PTR pEventData) { + OmxMessage msg; + msg.type = OmxMessage::EVENT; + msg.u.eventData.appData = appData; + msg.u.eventData.event = event; + msg.u.eventData.data1 = data1; + msg.u.eventData.data2 = data2; + ((OmxFrameDecoder *)appData)->mDispatcher.post(msg); + return OMX_ErrorNone; +} + +//Static +OMX_ERRORTYPE OmxFrameDecoder::emptyBufferDoneCallback(OMX_HANDLETYPE hComponent, + OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead) { + OmxMessage msg; + msg.type = OmxMessage::EMPTY_BUFFER_DONE; + msg.u.bufferData.appData = appData; + msg.u.bufferData.pBuffHead = pBuffHead; + ((OmxFrameDecoder *)appData)->mDispatcher.post(msg); + return OMX_ErrorNone; +} + +//Static +OMX_ERRORTYPE OmxFrameDecoder::fillBufferDoneCallback(OMX_HANDLETYPE hComponent, + OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead) { + OmxMessage msg; + msg.type = OmxMessage::FILL_BUFFER_DONE; + msg.u.bufferData.appData = appData; + msg.u.bufferData.pBuffHead = pBuffHead; + ((OmxFrameDecoder *)appData)->mDispatcher.post(msg); + return OMX_ErrorNone; +} + +OmxFrameDecoder::OmxFrameDecoder(DecoderType type) + : mOmxInialized(false), mCurrentState(OmxDecoderState_Unloaded), mPreviousState(OmxDecoderState_Unloaded), + mStopping(false), mDecoderType(type), mIsNeedCheckDHT(true), mAlwaysAppendDHT(false) { +} + +OmxFrameDecoder::~OmxFrameDecoder() { +} + +OMX_ERRORTYPE OmxFrameDecoder::emptyBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead) { + LOG_FUNCTION_NAME; + android::AutoMutex lock(mHwLock); + + int bufferIndex = reinterpret_cast(pBuffHead->pAppPrivate); + CAMHAL_LOGD("Got header %p id = %d", pBuffHead, bufferIndex); + android::sp& in = mInBuffers->editItemAt(bufferIndex); + + android::AutoMutex itemLock(in->getLock()); + in->setStatus((getOmxState() == OmxDecoderState_Executing) ? BufferStatus_InDecoded : BufferStatus_InQueued); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OmxFrameDecoder::fillBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead) { + LOG_FUNCTION_NAME; + android::AutoMutex lock(mHwLock); + + int index = (int)pBuffHead->pAppPrivate; + android::sp& out = mOutBuffers->editItemAt(index); + + android::AutoMutex itemLock(out->getLock()); + CameraBuffer* frame = static_cast(out->buffer); + out->setOffset(pBuffHead->nOffset); + out->setTimestamp(pBuffHead->nTimeStamp); + out->setStatus((getOmxState() == OmxDecoderState_Executing) ? BufferStatus_OutFilled : BufferStatus_OutQueued); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OmxFrameDecoder::eventHandler(const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2, + const OMX_PTR pEventData) { + + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE ret = OMX_ErrorNone; + android::AutoMutex lock(mHwLock); + + switch(event) { + + case OMX_EventCmdComplete: + { + if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateIdle)) { + CAMHAL_LOGD("Component State Changed To OMX_StateIdle\n"); + commitState(OmxDecoderState_Idle); + mStateCondition.signal(); + } + else if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateExecuting)) { + CAMHAL_LOGD("Component State Changed To OMX_StateExecuting\n"); + commitState(OmxDecoderState_Executing); + mStateCondition.signal(); + } + else if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateLoaded)) { + CAMHAL_LOGD("Component State Changed To OMX_StateLoaded\n"); + if(getOmxState() == OmxDecoderState_Executing) + commitState(OmxDecoderState_Loaded); + mStateCondition.signal(); + } + else if (data1 == OMX_CommandFlush) { + CAMHAL_LOGD("OMX_CommandFlush done on %d port\n", data2); + mStateCondition.signal(); + } + else if (data1 == OMX_CommandPortDisable) { + CAMHAL_LOGD("OMX_CommandPortDisable done on %d port\n", data2); + mStateCondition.signal(); + } + else if (data1 == OMX_CommandPortEnable) { + CAMHAL_LOGD("OMX_CommandPortEnable done on %d port\n", data2); + mStateCondition.signal(); + } else { + CAMHAL_LOGD("Event %d done on %d port\n", data1, data2); + } + break; + } + case OMX_EventError: + { + CAMHAL_LOGD("\n\n\nOMX Component reported an Error!!!! 0x%x 0x%x\n\n\n", data1, data2); + commitState(OmxDecoderState_Error); + omxSendCommand(OMX_CommandStateSet, OMX_StateInvalid); + mStateCondition.signal(); + break; + } + case OMX_EventPortSettingsChanged: + { + CAMHAL_LOGD("\n\n\nOMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)\n\n\n", + data1, data2); + if (data2 == 0) { + // This means that some serious change to port happens + commitState(OmxDecoderState_Reconfigure); + } else if (data2 == OMX_IndexConfigCommonOutputCrop) { +#if 0 + OMX_CONFIG_RECTTYPE rect; + InitOMXParams(&rect); + rect.nPortIndex = PortIndexOutput; + status_t ret = omxGetConfig(OMX_IndexConfigCommonOutputCrop, &rect); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Can't get new crop parameters 0x%x", ret); + break; + } + + CAMHAL_LOGV("Crop should change to %d %d %d %d", rect.nLeft, rect.nTop, rect.nLeft + rect.nWidth, rect.nTop + rect.nHeight); +#endif + } + break; + } + default: + { + CAMHAL_LOGD("\n\n\nOMX Unhandelled event ID=0x%x!!!!\n\n\n", event); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; + } + +void OmxFrameDecoder::doConfigure(const DecoderParameters& config) { + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OmxFrameDecoder::enableGrallockHandles() { + OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles; + InitOMXParams(&domxUseGrallocHandles); + + domxUseGrallocHandles.nPortIndex = PortIndexOutput; + domxUseGrallocHandles.bEnable = OMX_TRUE; + + return omxSetParameter((OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles); +} + +status_t OmxFrameDecoder::omxSwitchToExecutingSync() { + CAMHAL_LOGV("Try set OMX_StateExecuting"); + android::AutoMutex lock(mHwLock); + omxSendCommand(OMX_CommandStateSet, OMX_StateExecuting); + status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to EXECUTING ERROR 0x%x", ret); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + +void OmxFrameDecoder::dumpPortSettings(PortType port) { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = port; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + omxDumpPortSettings(def); +} + +status_t OmxFrameDecoder::disablePortSync(int port) { + OMX_ERRORTYPE eError; + android::AutoMutex lock(mHwLock); + eError = OMX_SendCommand(mHandleComp, OMX_CommandPortDisable, port, NULL); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_CommandPortDisable OMX_ALL returned error 0x%x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + +status_t OmxFrameDecoder::enablePortSync(int port) { + android::AutoMutex lock(mHwLock); + OMX_ERRORTYPE eError = OMX_SendCommand(mHandleComp, OMX_CommandPortEnable, port, NULL); + status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_SendCommand OMX_CommandPortEnable OUT returned error 0x%x", eError); + return Utils::ErrorUtils::omxToAndroidError(eError); + } + return NO_ERROR; +} + + +status_t OmxFrameDecoder::doPortReconfigure() { + OMX_ERRORTYPE eError; + status_t ret = NO_ERROR; + + CAMHAL_LOGD("Starting port reconfiguration !"); + dumpPortSettings(PortIndexInput); + dumpPortSettings(PortIndexOutput); + + android::AutoMutex lock(mHwLock); + + omxSendCommand(OMX_CommandFlush, PortIndexOutput); + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to OMX_CommandFlush ERROR 0x%x", ret); + return UNKNOWN_ERROR; + } + + omxSendCommand(OMX_CommandFlush, PortIndexInput); + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to OMX_CommandFlush ERROR 0x%x", ret); + return UNKNOWN_ERROR; + } + + ret = omxSendCommand(OMX_CommandPortDisable, PortIndexOutput); + if (ret != NO_ERROR) { + CAMHAL_LOGE("OMX_CommandPortDisable PortIndexOutput returned error 0x%x", ret); + return ret; + } + + freeBuffersOnOutput(); + + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret); + return UNKNOWN_ERROR; + } + + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = PortIndexOutput; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + def.nBufferCountActual = mParams.outputBufferCount; + CAMHAL_LOGD("Will set def.nBufferSize=%d stride=%d height=%d", def.nBufferSize , def.format.video.nStride, def.format.video.nFrameHeight); + omxSetParameter(OMX_IndexParamPortDefinition, &def); + + + + ret = omxSendCommand(OMX_CommandPortEnable, PortIndexOutput); + if (ret != NO_ERROR) { + CAMHAL_LOGE("omxSendCommand OMX_CommandPortEnable returned error 0x%x", ret); + return ret; + } + + allocateBuffersOutput(); + + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("omxSendCommand OMX_CommandPortEnable timeout 0x%x", ret); + return UNKNOWN_ERROR; + } + + CAMHAL_LOGD("Port reconfiguration DONE!"); + //dumpPortSettings(PortIndexOutput); + + return NO_ERROR; +} + +void OmxFrameDecoder::queueOutputBuffers() { + + LOG_FUNCTION_NAME; + + android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get(); + + for (size_t i = 0; i < mOutQueue.size(); i++) { + int index = mOutQueue[i]; + android::sp &outBuffer = mOutBuffers->editItemAt(index); + android::AutoMutex bufferLock(outBuffer->getLock()); + if (outBuffer->getStatus() == BufferStatus_OutQueued) { + outBuffer->setStatus(BufferStatus_OutWaitForFill); + CameraBuffer* frame = static_cast(outBuffer->buffer); + OMX_BUFFERHEADERTYPE *pOutBufHdr = mOutBufferHeaders[outBuffer->bufferId]; + CAMHAL_LOGV("Fill this buffer cf=%p bh=%p id=%d", frame, pOutBufHdr, outBuffer->bufferId); + status_t status = omxFillThisBuffer(pOutBufHdr); + CAMHAL_ASSERT(status == NO_ERROR); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::doProcessInputBuffer() { + + LOG_FUNCTION_NAME; + + if (getOmxState() == OmxDecoderState_Reconfigure) { + if (doPortReconfigure() == NO_ERROR) { + commitState(OmxDecoderState_Executing); + queueOutputBuffers(); + } else { + commitState(OmxDecoderState_Error); + return; + } + + } + + if (getOmxState() == OmxDecoderState_Idle) { + CAMHAL_ASSERT(omxSwitchToExecutingSync() == NO_ERROR); + queueOutputBuffers(); + } + + if (getOmxState() == OmxDecoderState_Executing) { + for (size_t i = 0; i < mInQueue.size(); i++) { + int index = mInQueue[i]; + CAMHAL_LOGD("Got in inqueue[%d] buffer id=%d", i, index); + android::sp &inBuffer = mInBuffers->editItemAt(index); + android::AutoMutex bufferLock(inBuffer->getLock()); + if (inBuffer->getStatus() == BufferStatus_InQueued) { + OMX_BUFFERHEADERTYPE *pInBufHdr = mInBufferHeaders[index]; + inBuffer->setStatus(BufferStatus_InWaitForEmpty); + omxEmptyThisBuffer(inBuffer, pInBufHdr); + } + } + queueOutputBuffers(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OmxFrameDecoder::omxInit() { + + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_Init() failed, error: 0x%x", eError); + } + else mOmxInialized = true; + + LOG_FUNCTION_NAME_EXIT; + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxFillThisBuffer(OMX_BUFFERHEADERTYPE *pOutBufHdr) { + OMX_ERRORTYPE eError = OMX_ErrorUndefined; + + pOutBufHdr->nFilledLen = 0; + pOutBufHdr->nOffset = 0; + pOutBufHdr->nFlags = 0; + + eError = OMX_FillThisBuffer(mHandleComp, pOutBufHdr); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_FillThisBuffer ERROR 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + + +status_t OmxFrameDecoder::omxGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData, + OMX_CALLBACKTYPE & callbacks) { + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorUndefined; + + eError = OMX_GetHandle(handle, (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.DECODER", pAppData, &callbacks); + if((eError != OMX_ErrorNone) || (handle == NULL)) { + handle = NULL; + return Utils::ErrorUtils::omxToAndroidError(eError); + } + commitState(OmxDecoderState_Loaded); + + LOG_FUNCTION_NAME_EXIT; + + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxEmptyThisBuffer(android::sp& inBuffer, OMX_BUFFERHEADERTYPE *pInBufHdr) { + + LOG_FUNCTION_NAME; + + OMX_PARAM_PORTDEFINITIONTYPE def; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + InitOMXParams(&def); + def.nPortIndex = PortIndexInput; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + CAMHAL_LOGD("Founded id for empty is %d ", inBuffer->bufferId); + if (inBuffer->filledLen > def.nBufferSize) { + CAMHAL_LOGE("Can't copy IN buffer due to it too small %d than needed %d", def.nBufferSize, inBuffer->filledLen); + return UNKNOWN_ERROR; + } + + int filledLen = inBuffer->filledLen; + unsigned char* dataBuffer = reinterpret_cast(inBuffer->buffer); + + //If decoder type MJPEG we check if append DHT forced and if true append it + //in other case we check mIsNeedCheckDHT and if true search for DHT in buffer + //if we don't found it - will do append + //once we find that buffer not contain DHT we will append it each time + if ((mDecoderType == DecoderType_MJPEG) && ((mAlwaysAppendDHT) || ((mIsNeedCheckDHT) && + (mIsNeedCheckDHT = !Decoder_libjpeg::isDhtExist(dataBuffer, filledLen))))) { + CAMHAL_LOGV("Will append DHT to buffer"); + Decoder_libjpeg::appendDHT(dataBuffer, filledLen, pInBufHdr->pBuffer, filledLen + Decoder_libjpeg::readDHTSize()); + filledLen += Decoder_libjpeg::readDHTSize(); + mIsNeedCheckDHT = false; + mAlwaysAppendDHT = true; + } else { + memcpy(pInBufHdr->pBuffer, dataBuffer, filledLen); + } + + CAMHAL_LOGV("Copied %d bytes into In buffer with bh=%p", filledLen, pInBufHdr); + CAMHAL_LOGV("Empty this buffer id=%d timestamp %lld offset=%d", inBuffer->bufferId, pInBufHdr->nTimeStamp, pInBufHdr->nOffset); + pInBufHdr->nFilledLen = filledLen; + pInBufHdr->nTimeStamp = inBuffer->getTimestamp(); + pInBufHdr->nFlags = 16; + pInBufHdr->nOffset = 0; + eError = OMX_EmptyThisBuffer(mHandleComp, pInBufHdr); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_EmptyThisBuffer ERROR 0x%x", eError); + Utils::ErrorUtils::omxToAndroidError(eError); + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + + +status_t OmxFrameDecoder::allocateBuffersOutput() { + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = PortIndexOutput; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + def.nBufferCountActual = mParams.outputBufferCount; + + CAMHAL_LOGD("Will set def.nBufferSize=%d stride=%d height=%d", def.nBufferSize , def.format.video.nStride, def.format.video.nFrameHeight); + + OMX_BUFFERHEADERTYPE *pOutBufHdr; + mOutBufferHeaders.clear(); + for (size_t i = 0; i < mOutBuffers->size(); i++) { + android::sp& outBuffer = mOutBuffers->editItemAt(i); + android::AutoMutex lock(outBuffer->getLock()); + CameraBuffer* cb = static_cast(outBuffer->buffer); + OMX_U8 * outPtr = static_cast(camera_buffer_get_omx_ptr(cb)); + CAMHAL_LOGV("Try to set OMX_UseBuffer [0x%x] for output port with length %d ", outPtr, def.nBufferSize); + eError = OMX_UseBuffer(mHandleComp, &pOutBufHdr, PortIndexOutput, (void*)i, def.nBufferSize, outPtr); + + if (eError != OMX_ErrorNone) { + ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", eError, eError); + commitState(OmxDecoderState_Error); + return UNKNOWN_ERROR; + } + + CAMHAL_LOGD("Got buffer header %p", pOutBufHdr); + mOutBufferHeaders.add(pOutBufHdr); + } + + omxDumpPortSettings(def); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; + +} + +status_t OmxFrameDecoder::allocateBuffersInput() { + LOG_FUNCTION_NAME; + + OMX_PARAM_PORTDEFINITIONTYPE def; + OMX_BUFFERHEADERTYPE *pInBufHdr; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + InitOMXParams(&def); + def.nPortIndex = PortIndexInput; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + + // TODO: Will be changed since port reconfiguration will be handled + def.nBufferCountActual = mInBuffers->size(); + def.bEnabled = OMX_TRUE; + omxSetParameter(OMX_IndexParamPortDefinition, &def); + + mInBufferHeaders.clear(); + + for (size_t i = 0; i < mInBuffers->size(); i++) { + CAMHAL_LOGD("Will do OMX_AllocateBuffer for input port with size %d id=%d", def.nBufferSize, i); + eError = OMX_AllocateBuffer(mHandleComp, &pInBufHdr, PortIndexInput, (void*)i, def.nBufferSize); + if (eError != OMX_ErrorNone) { + ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", eError, eError); + commitState(OmxDecoderState_Error); + return UNKNOWN_ERROR; + } + CAMHAL_LOGD("Got new buffer header [%p] for IN port", pInBufHdr); + mInBufferHeaders.push_back(pInBufHdr); + } + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + +status_t OmxFrameDecoder::getAndConfigureDecoder() { + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError; + + ret = omxInit(); + if (ret != NO_ERROR) { + CAMHAL_LOGE("OMX_Init returned error 0x%x", ret); + return ret; + } + OMX_CALLBACKTYPE callbacks; + callbacks.EventHandler = OmxFrameDecoder::eventCallback; + callbacks.EmptyBufferDone = OmxFrameDecoder::emptyBufferDoneCallback; + callbacks.FillBufferDone = OmxFrameDecoder::fillBufferDoneCallback; + ret = omxGetHandle(&mHandleComp, this, callbacks); + if (ret != NO_ERROR) { + CAMHAL_LOGE("OMX_GetHandle returned error 0x%x", ret); + OMX_Deinit(); + mOmxInialized = false; + return ret; + } + ret = setComponentRole(); + if (ret != NO_ERROR) { + CAMHAL_LOGE("setComponentRole returned error 0x%x", ret); + OMX_Deinit(); + mOmxInialized = false; + return ret; + } + disablePortSync(PortIndexOutput); + ret = setVideoOutputFormat(mParams.width, mParams.height); + enablePortSync(PortIndexOutput); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Can't set output format error 0x%x", ret); + OMX_Deinit(); + mOmxInialized = false; + return ret; + } + enableGrallockHandles(); + return NO_ERROR; +} + +status_t OmxFrameDecoder::switchToIdle() { + CAMHAL_ASSERT(getOmxState() == OmxDecoderState_Loaded); + CAMHAL_LOGD("Try set OMX_StateIdle"); + android::AutoMutex lock(mHwLock); + status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateIdle); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret); + OMX_Deinit(); + mOmxInialized = false; + return ret; + } + + allocateBuffersInput(); + + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = PortIndexOutput; + omxGetParameter(OMX_IndexParamPortDefinition, &def); + def.nBufferCountActual = mParams.outputBufferCount; + omxSetParameter(OMX_IndexParamPortDefinition, &def); + + allocateBuffersOutput(); + + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to IDLE ERROR 0x%x", ret); + return ret; + } + commitState(OmxDecoderState_Idle); + return NO_ERROR; +} + +status_t OmxFrameDecoder::doStart() { + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + mStopping = false; + OMX_ERRORTYPE eError; + + ret = getAndConfigureDecoder(); + +#if 0 + OMX_TI_PARAM_ENHANCEDPORTRECONFIG tParamStruct; + tParamStruct.nSize = sizeof(OMX_TI_PARAM_ENHANCEDPORTRECONFIG); + tParamStruct.nVersion.s.nVersionMajor = 0x1; + tParamStruct.nVersion.s.nVersionMinor = 0x1; + tParamStruct.nVersion.s.nRevision = 0x0; + tParamStruct.nVersion.s.nStep = 0x0; + tParamStruct.nPortIndex = PortIndexOutput; + tParamStruct.bUsePortReconfigForCrop = OMX_TRUE; + tParamStruct.bUsePortReconfigForPadding = OMX_FALSE; + omxSetParameter((OMX_INDEXTYPE)OMX_TI_IndexParamUseEnhancedPortReconfig, &tParamStruct); +#endif + + // Transition to IDLE + ret = switchToIdle(); + dumpPortSettings(PortIndexInput); + dumpPortSettings(PortIndexOutput); + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t OmxFrameDecoder::omxGetParameter(OMX_INDEXTYPE index, OMX_PTR ptr) { + OMX_ERRORTYPE eError = OMX_GetParameter(mHandleComp, index, ptr); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_GetParameter - error 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxGetConfig(OMX_INDEXTYPE index, OMX_PTR ptr) { + OMX_ERRORTYPE eError = OMX_GetConfig(mHandleComp, index, ptr); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_GetConfig - error 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxSetParameter(OMX_INDEXTYPE index, OMX_PTR ptr) { + OMX_ERRORTYPE eError = OMX_SetParameter(mHandleComp, index, ptr); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_SetParameter - error 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxSetConfig(OMX_INDEXTYPE index, OMX_PTR ptr) { + OMX_ERRORTYPE eError = OMX_SetConfig(mHandleComp, index, ptr); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_SetConfig - error 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::omxSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) { + OMX_ERRORTYPE eError = OMX_SendCommand(mHandleComp, cmd, param, NULL); + if(eError != OMX_ErrorNone) { + CAMHAL_LOGE("OMX_SendCommand - error 0x%x", eError); + } + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) { + LOG_FUNCTION_NAME; + + CAMHAL_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height); + + OMX_VIDEO_CODINGTYPE compressionFormat = gCompressionFormat[mDecoderType]; + + status_t err = setVideoPortFormatType( + PortIndexInput, compressionFormat, OMX_COLOR_FormatUnused); + + if (err != NO_ERROR) { + CAMHAL_LOGE("Error during setVideoPortFormatType 0x%x", err); + return err; + } + + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = PortIndexInput; + + OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; + + err = omxGetParameter(OMX_IndexParamPortDefinition, &def); + + if (err != NO_ERROR) { + return err; + } + + video_def->nFrameWidth = width; + video_def->nFrameHeight = height; + + video_def->eCompressionFormat = compressionFormat; + video_def->eColorFormat = OMX_COLOR_FormatUnused; + + + err = omxSetParameter(OMX_IndexParamPortDefinition, &def); + + + if (err != OK) { + return err; + } + + OMX_PARAM_PORTDEFINITIONTYPE odef; + OMX_VIDEO_PORTDEFINITIONTYPE *out_video_def = &odef.format.video; + + InitOMXParams(&odef); + odef.nPortIndex = PortIndexOutput; + + err = omxGetParameter(OMX_IndexParamPortDefinition, &odef); + if (err != NO_ERROR) { + return err; + } + + out_video_def->nFrameWidth = width; + out_video_def->nFrameHeight = height; + out_video_def->xFramerate = 30<< 16;//((width >= 720) ? 60 : 30) << 16; + out_video_def->nStride = 4096; + + err = omxSetParameter(OMX_IndexParamPortDefinition, &odef); + CAMHAL_LOGD("OUT port is configured"); + dumpPortSettings(PortIndexOutput); + + LOG_FUNCTION_NAME_EXIT; + return err; +} + +status_t OmxFrameDecoder::setVideoPortFormatType( + OMX_U32 portIndex, + OMX_VIDEO_CODINGTYPE compressionFormat, + OMX_COLOR_FORMATTYPE colorFormat) { + + LOG_FUNCTION_NAME; + + OMX_VIDEO_PARAM_PORTFORMATTYPE format; + InitOMXParams(&format); + format.nPortIndex = portIndex; + format.nIndex = 0; + bool found = false; + + OMX_U32 index = 0; + for (;;) { + CAMHAL_LOGV("Will check index = %d", index); + format.nIndex = index; + OMX_ERRORTYPE eError = OMX_GetParameter( + mHandleComp, OMX_IndexParamVideoPortFormat, + &format); + + CAMHAL_LOGV("format.eCompressionFormat=0x%x format.eColorFormat=0x%x", format.eCompressionFormat, format.eColorFormat); + + if (format.eCompressionFormat == compressionFormat + && format.eColorFormat == colorFormat) { + found = true; + break; + } + + ++index; + if (index >= kMaxColorFormatSupported) { + CAMHAL_LOGE("color format %d or compression format %d is not supported", + colorFormat, compressionFormat); + return UNKNOWN_ERROR; + } + } + + if (!found) { + return UNKNOWN_ERROR; + } + + CAMHAL_LOGV("found a match."); + OMX_ERRORTYPE eError = OMX_SetParameter( + mHandleComp, OMX_IndexParamVideoPortFormat, + &format); + + LOG_FUNCTION_NAME_EXIT; + return Utils::ErrorUtils::omxToAndroidError(eError); +} + +status_t OmxFrameDecoder::setComponentRole() { + OMX_PARAM_COMPONENTROLETYPE roleParams; + const char *role = gDecoderRole[mDecoderType]; + InitOMXParams(&roleParams); + + strncpy((char *)roleParams.cRole, + role, OMX_MAX_STRINGNAME_SIZE - 1); + roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; + + return omxSetParameter(OMX_IndexParamStandardComponentRole, &roleParams); +} + +void OmxFrameDecoder::freeBuffersOnOutput() { + LOG_FUNCTION_NAME; + for (size_t i = 0; i < mOutBufferHeaders.size(); i++) { + OMX_BUFFERHEADERTYPE* header = mOutBufferHeaders[i]; + CAMHAL_LOGD("Freeing OUT buffer header %p", header); + OMX_FreeBuffer(mHandleComp, PortIndexOutput, header); + } + mOutBufferHeaders.clear(); + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::freeBuffersOnInput() { + LOG_FUNCTION_NAME; + for (size_t i = 0; i < mInBufferHeaders.size(); i++) { + OMX_BUFFERHEADERTYPE* header = mInBufferHeaders[i]; + CAMHAL_LOGD("Freeing IN buffer header %p", header); + OMX_FreeBuffer(mHandleComp, PortIndexInput, header); + } + mInBufferHeaders.clear(); + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::doStop() { + LOG_FUNCTION_NAME; + + mStopping = true; + android::AutoMutex lock(mHwLock); + + CAMHAL_LOGD("HwFrameDecoder::doStop state id=%d", getOmxState()); + + if ((getOmxState() == OmxDecoderState_Executing) || (getOmxState() == OmxDecoderState_Reconfigure)) { + + CAMHAL_LOGD("Try set OMX_StateIdle"); + status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateIdle); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret); + } + + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to IDLE ERROR 0x%x", ret); + } + commitState(OmxDecoderState_Idle); + } + + if (getOmxState() == OmxDecoderState_Idle) { + + CAMHAL_LOGD("Try set OMX_StateLoaded"); + status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateLoaded); + if (ret != NO_ERROR) { + CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret); + return; + } + freeBuffersOnOutput(); + freeBuffersOnInput(); + ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut); + if (ret != NO_ERROR) { + CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret); + } + commitState(OmxDecoderState_Loaded); + + } + + if (getOmxState() == OmxDecoderState_Error) { + CAMHAL_LOGD("In state ERROR will try to free buffers!"); + freeBuffersOnOutput(); + freeBuffersOnInput(); + } + + CAMHAL_LOGD("Before OMX_FreeHandle ...."); + OMX_FreeHandle(mHandleComp); + CAMHAL_LOGD("After OMX_FreeHandle ...."); + + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::doFlush() { + LOG_FUNCTION_NAME; + mIsNeedCheckDHT = true; + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::doRelease() { + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + +void OmxFrameDecoder::omxDumpPortSettings(OMX_PARAM_PORTDEFINITIONTYPE& def) { + CAMHAL_LOGD("----------Port settings start--------------------"); + CAMHAL_LOGD("nSize=%d nPortIndex=%d eDir=%d nBufferCountActual=%d", def.nSize, def.nPortIndex, def.eDir, def.nBufferCountActual); + CAMHAL_LOGD("nBufferCountMin=%d nBufferSize=%d bEnabled=%d bPopulated=%d bBuffersContiguous=%d nBufferAlignment=%d", def.nBufferCountMin, def.nBufferSize, def.bEnabled, def.bPopulated, def.bBuffersContiguous, def.nBufferAlignment); + + CAMHAL_LOGD("eDomain = %d",def.eDomain); + + if (def.eDomain == OMX_PortDomainVideo) { + CAMHAL_LOGD("===============Video Port==================="); + CAMHAL_LOGD("cMIMEType=%s",def.format.video.cMIMEType); + CAMHAL_LOGD("nFrameWidth=%d nFrameHeight=%d", def.format.video.nFrameWidth, def.format.video.nFrameHeight); + CAMHAL_LOGD("nStride=%d nSliceHeight=%d", def.format.video.nStride, def.format.video.nSliceHeight); + CAMHAL_LOGD("nBitrate=%d xFramerate=%d", def.format.video.nBitrate, def.format.video.xFramerate>>16); + CAMHAL_LOGD("bFlagErrorConcealment=%d eCompressionFormat=%d", def.format.video.bFlagErrorConcealment, def.format.video.eCompressionFormat); + CAMHAL_LOGD("eColorFormat=0x%x pNativeWindow=%p", def.format.video.eColorFormat, def.format.video.pNativeWindow); + CAMHAL_LOGD("===============END Video Part==================="); + } + else if (def.eDomain == OMX_PortDomainImage) { + CAMHAL_LOGD("===============Image Port==================="); + CAMHAL_LOGD("cMIMEType=%s",def.format.image.cMIMEType); + CAMHAL_LOGD("nFrameWidth=%d nFrameHeight=%d", def.format.image.nFrameWidth, def.format.image.nFrameHeight); + CAMHAL_LOGD("nStride=%d nSliceHeight=%d", def.format.image.nStride, def.format.image.nSliceHeight); + CAMHAL_LOGD("bFlagErrorConcealment=%d eCompressionFormat=%d", def.format.image.bFlagErrorConcealment, def.format.image.eCompressionFormat); + CAMHAL_LOGD("eColorFormat=0x%x pNativeWindow=%p", def.format.image.eColorFormat, def.format.image.pNativeWindow); + CAMHAL_LOGD("===============END Image Part==================="); + } + CAMHAL_LOGD("----------Port settings end--------------------"); +} + +void OmxFrameDecoder::omxDumpBufferHeader(OMX_BUFFERHEADERTYPE* bh) { + CAMHAL_LOGD("==============OMX_BUFFERHEADERTYPE start=============="); + CAMHAL_LOGD("nAllocLen=%d nFilledLen=%d nOffset=%d nFlags=0x%x", bh->nAllocLen, bh->nFilledLen, bh->nOffset, bh->nFlags); + CAMHAL_LOGD("pBuffer=%p nOutputPortIndex=%d nInputPortIndex=%d nSize=0x%x", bh->pBuffer, bh->nOutputPortIndex, bh->nInputPortIndex, bh->nSize); + CAMHAL_LOGD("nVersion=0x%x", bh->nVersion); + CAMHAL_LOGD("==============OMX_BUFFERHEADERTYPE end=============="); +} + +bool OmxFrameDecoder::getPaddedDimensions(size_t &width, size_t &height) { + + switch (height) { + + case 480: { + height = 576; + if (width == 640) { + width = 768; + } + break; + } + case 720: { + height = 832; + if (width == 1280) { + width = 1408; + } + break; + } + case 1080: { + height = 1184; + if (width == 1920) { + width = 2048; + } + break; + } + + } + + CAMHAL_LOGD("WxH updated to padded values : %d x %d", width, height); + return true; +} + +} // namespace Camera +} // namespace Ti + diff --git a/camera/SensorListener.cpp b/camera/SensorListener.cpp new file mode 100644 index 0000000..e53fa83 --- /dev/null +++ b/camera/SensorListener.cpp @@ -0,0 +1,236 @@ +/* + * 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. + */ + +/** +* @file SensorListener.cpp +* +* This file listens and propogates sensor events to CameraHal. +* +*/ + +#include "SensorListener.h" + +#include +#include +#include + +namespace Ti { +namespace Camera { + +/*** static declarations ***/ +static const float RADIANS_2_DEG = (float) (180 / M_PI); +// measured values on device...might need tuning +static const int DEGREES_90_THRESH = 50; +static const int DEGREES_180_THRESH = 170; +static const int DEGREES_270_THRESH = 250; + +static int sensor_events_listener(int fd, int events, void* data) +{ + SensorListener* listener = (SensorListener*) data; + ssize_t num_sensors; + ASensorEvent sen_events[8]; + while ((num_sensors = listener->mSensorEventQueue->read(sen_events, 8)) > 0) { + for (int i = 0; i < num_sensors; i++) { + if (sen_events[i].type == android::Sensor::TYPE_ACCELEROMETER) { + float x = sen_events[i].vector.azimuth; + float y = sen_events[i].vector.pitch; + float z = sen_events[i].vector.roll; + float radius = 0; + int tilt = 0, orient = 0; + + CAMHAL_LOGVA("ACCELEROMETER EVENT"); + CAMHAL_LOGVB(" azimuth = %f pitch = %f roll = %f", + sen_events[i].vector.azimuth, + sen_events[i].vector.pitch, + sen_events[i].vector.roll); + // see http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates + // about conversion from cartesian to spherical for orientation calculations + radius = (float) sqrt(x * x + y * y + z * z); + tilt = (int) asinf(z / radius) * RADIANS_2_DEG; + orient = (int) atan2f(-x, y) * RADIANS_2_DEG; + + if (orient < 0) { + orient += 360; + } + + if (orient >= DEGREES_270_THRESH) { + orient = 270; + } else if (orient >= DEGREES_180_THRESH) { + orient = 180; + } else if (orient >= DEGREES_90_THRESH) { + orient = 90; + } else { + orient = 0; + } + listener->handleOrientation(orient, tilt); + CAMHAL_LOGVB(" tilt = %d orientation = %d", tilt, orient); + } else if (sen_events[i].type == android::Sensor::TYPE_GYROSCOPE) { + CAMHAL_LOGVA("GYROSCOPE EVENT"); + } + } + } + + if (num_sensors < 0 && num_sensors != -EAGAIN) { + CAMHAL_LOGEB("reading events failed: %s", strerror(-num_sensors)); + } + + return 1; +} + +/****** public - member functions ******/ +SensorListener::SensorListener() { + LOG_FUNCTION_NAME; + + sensorsEnabled = 0; + mOrientationCb = NULL; + mSensorEventQueue = NULL; + mSensorLooperThread = NULL; + + LOG_FUNCTION_NAME_EXIT; +} + +SensorListener::~SensorListener() { + LOG_FUNCTION_NAME; + + CAMHAL_LOGDA("Kill looper thread"); + if (mSensorLooperThread.get()) { + // 1. Request exit + // 2. Wake up looper which should be polling for an event + // 3. Wait for exit + mSensorLooperThread->requestExit(); + mSensorLooperThread->wake(); + mSensorLooperThread->join(); + mSensorLooperThread.clear(); + mSensorLooperThread = NULL; + } + + CAMHAL_LOGDA("Kill looper"); + if (mLooper.get()) { + mLooper->removeFd(mSensorEventQueue->getFd()); + mLooper.clear(); + mLooper = NULL; + } + CAMHAL_LOGDA("SensorListener destroyed"); + + LOG_FUNCTION_NAME_EXIT; +} + +status_t SensorListener::initialize() { + status_t ret = NO_ERROR; + android::SensorManager& mgr(android::SensorManager::getInstance()); + + LOG_FUNCTION_NAME; + + android::sp mLooper; + + mSensorEventQueue = mgr.createEventQueue(); + if (mSensorEventQueue == NULL) { + CAMHAL_LOGEA("createEventQueue returned NULL"); + ret = NO_INIT; + goto out; + } + + mLooper = new android::Looper(false); + mLooper->addFd(mSensorEventQueue->getFd(), 0, ALOOPER_EVENT_INPUT, sensor_events_listener, this); + + if (mSensorLooperThread.get() == NULL) + mSensorLooperThread = new SensorLooperThread(mLooper.get()); + + if (mSensorLooperThread.get() == NULL) { + CAMHAL_LOGEA("Couldn't create sensor looper thread"); + ret = NO_MEMORY; + goto out; + } + + ret = mSensorLooperThread->run("sensor looper thread", android::PRIORITY_URGENT_DISPLAY); + if (ret == INVALID_OPERATION){ + CAMHAL_LOGDA("thread already running ?!?"); + } else if (ret != NO_ERROR) { + CAMHAL_LOGEA("couldn't run thread"); + goto out; + } + + out: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +void SensorListener::setCallbacks(orientation_callback_t orientation_cb, void *cookie) { + LOG_FUNCTION_NAME; + + if (orientation_cb) { + mOrientationCb = orientation_cb; + } + mCbCookie = cookie; + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::handleOrientation(uint32_t orientation, uint32_t tilt) { + LOG_FUNCTION_NAME; + + android::AutoMutex lock(&mLock); + + if (mOrientationCb && (sensorsEnabled & SENSOR_ORIENTATION)) { + mOrientationCb(orientation, tilt, mCbCookie); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::enableSensor(sensor_type_t type) { + android::Sensor const* sensor; + android::SensorManager& mgr(android::SensorManager::getInstance()); + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(&mLock); + + if ((type & SENSOR_ORIENTATION) && !(sensorsEnabled & SENSOR_ORIENTATION)) { + sensor = mgr.getDefaultSensor(android::Sensor::TYPE_ACCELEROMETER); + if(sensor) { + CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string()); + mSensorEventQueue->enableSensor(sensor); + mSensorEventQueue->setEventRate(sensor, ms2ns(100)); + sensorsEnabled |= SENSOR_ORIENTATION; + } else { + CAMHAL_LOGDB("not enabling absent orientation sensor"); + } + } + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::disableSensor(sensor_type_t type) { + android::Sensor const* sensor; + android::SensorManager& mgr(android::SensorManager::getInstance()); + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(&mLock); + + if ((type & SENSOR_ORIENTATION) && (sensorsEnabled & SENSOR_ORIENTATION)) { + sensor = mgr.getDefaultSensor(android::Sensor::TYPE_ACCELEROMETER); + CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string()); + mSensorEventQueue->disableSensor(sensor); + sensorsEnabled &= ~SENSOR_ORIENTATION; + } + + LOG_FUNCTION_NAME_EXIT; +} + +} // namespace Camera +} // namespace Ti diff --git a/camera/SwFrameDecoder.cpp b/camera/SwFrameDecoder.cpp new file mode 100644 index 0000000..2ce2c0f --- /dev/null +++ b/camera/SwFrameDecoder.cpp @@ -0,0 +1,85 @@ +/* + * 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 "Common.h" +#include "SwFrameDecoder.h" + +namespace Ti { +namespace Camera { + +SwFrameDecoder::SwFrameDecoder() +: mjpegWithHdrSize(0), mJpegWithHeaderBuffer(NULL) { +} + +SwFrameDecoder::~SwFrameDecoder() { + delete [] mJpegWithHeaderBuffer; + mJpegWithHeaderBuffer = NULL; +} + + +void SwFrameDecoder::doConfigure(const DecoderParameters& params) { + LOG_FUNCTION_NAME; + + mjpegWithHdrSize = (mParams.width * mParams.height / 2) + + mJpgdecoder.readDHTSize(); + if (mJpegWithHeaderBuffer != NULL) { + delete [] mJpegWithHeaderBuffer; + mJpegWithHeaderBuffer = NULL; + } + mJpegWithHeaderBuffer = new unsigned char[mjpegWithHdrSize]; + + LOG_FUNCTION_NAME_EXIT; +} + + +void SwFrameDecoder::doProcessInputBuffer() { + LOG_FUNCTION_NAME; + nsecs_t timestamp = 0; + + CAMHAL_LOGV("Will add header to MJPEG"); + int final_jpg_sz = 0; + { + int inIndex = mInQueue.itemAt(0); + android::sp& inBuffer = mInBuffers->editItemAt(inIndex); + android::AutoMutex lock(inBuffer->getLock()); + timestamp = inBuffer->getTimestamp(); + final_jpg_sz = mJpgdecoder.appendDHT( + reinterpret_cast(inBuffer->buffer), + inBuffer->filledLen, mJpegWithHeaderBuffer, mjpegWithHdrSize); + inBuffer->setStatus(BufferStatus_InDecoded); + } + CAMHAL_LOGV("Added header to MJPEG"); + { + int outIndex = mOutQueue.itemAt(0); + android::sp& outBuffer = mOutBuffers->editItemAt(outIndex); + android::AutoMutex lock(outBuffer->getLock()); + CameraBuffer* buffer = reinterpret_cast(outBuffer->buffer); + if (!mJpgdecoder.decode(mJpegWithHeaderBuffer, final_jpg_sz, + reinterpret_cast(buffer->mapped), 4096)) { + CAMHAL_LOGEA("Error while decoding JPEG"); + return; + } + outBuffer->setTimestamp(timestamp); + outBuffer->setStatus(BufferStatus_OutFilled); + } + CAMHAL_LOGV("JPEG decoded!"); + + LOG_FUNCTION_NAME_EXIT; +} + + +} // namespace Camera +} // namespace Ti diff --git a/camera/TICameraParameters.cpp b/camera/TICameraParameters.cpp new file mode 100644 index 0000000..c8b8619 --- /dev/null +++ b/camera/TICameraParameters.cpp @@ -0,0 +1,241 @@ +/* + * 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 + +#include +#include +#include + +#define TI_KEY_ALGO_PREFIX "ti-algo-" + +namespace Ti { +namespace Camera { + +//TI extensions to camera mode +const char TICameraParameters::HIGH_PERFORMANCE_MODE[] = "high-performance"; +const char TICameraParameters::HIGH_QUALITY_MODE[] = "high-quality"; +const char TICameraParameters::HIGH_QUALITY_ZSL_MODE[] = "high-quality-zsl"; +const char TICameraParameters::CP_CAM_MODE[] = "cp-cam"; +const char TICameraParameters::VIDEO_MODE[] = "video-mode"; +const char TICameraParameters::VIDEO_MODE_HQ[] = "video-mode-hq"; +const char TICameraParameters::EXPOSURE_BRACKETING[] = "exposure-bracketing"; +const char TICameraParameters::ZOOM_BRACKETING[] = "zoom-bracketing"; +const char TICameraParameters::TEMP_BRACKETING[] = "temporal-bracketing"; + +// TI extensions to standard android Parameters +const char TICameraParameters::KEY_SUPPORTED_CAMERAS[] = "camera-indexes"; +const char TICameraParameters::KEY_CAMERA[] = "camera-index"; +const char TICameraParameters::KEY_SHUTTER_ENABLE[] = "shutter-enable"; +const char TICameraParameters::KEY_CAMERA_NAME[] = "camera-name"; +const char TICameraParameters::KEY_BURST[] = "burst-capture"; +const char TICameraParameters::KEY_CAP_MODE[] = "mode"; +const char TICameraParameters::KEY_CAP_MODE_VALUES[] = "mode-values"; +const char TICameraParameters::KEY_VNF[] = "vnf"; +const char TICameraParameters::KEY_VNF_SUPPORTED[] = "vnf-supported"; +const char TICameraParameters::KEY_SATURATION[] = "saturation"; +const char TICameraParameters::KEY_BRIGHTNESS[] = "brightness"; +const char TICameraParameters::KEY_SUPPORTED_EXPOSURE[] = "exposure-mode-values"; +const char TICameraParameters::KEY_EXPOSURE_MODE[] = "exposure"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MIN[] = "supported-manual-exposure-min"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_MAX[] = "supported-manual-exposure-max"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_EXPOSURE_STEP[] = "supported-manual-exposure-step"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN[] = "supported-manual-gain-iso-min"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_MAX[] = "supported-manual-gain-iso-max"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_GAIN_ISO_STEP[] = "supported-manual-gain-iso-step"; +const char TICameraParameters::KEY_MANUAL_EXPOSURE[] = "manual-exposure"; +const char TICameraParameters::KEY_MANUAL_EXPOSURE_RIGHT[] = "manual-exposure-right"; +const char TICameraParameters::KEY_MANUAL_GAIN_ISO[] = "manual-gain-iso"; +const char TICameraParameters::KEY_MANUAL_GAIN_ISO_RIGHT[] = "manual-gain-iso-right"; +const char TICameraParameters::KEY_CONTRAST[] = "contrast"; +const char TICameraParameters::KEY_SHARPNESS[] = "sharpness"; +const char TICameraParameters::KEY_ISO[] = "iso"; +const char TICameraParameters::KEY_SUPPORTED_ISO_VALUES[] = "iso-mode-values"; +const char TICameraParameters::KEY_SUPPORTED_IPP[] = "ipp-values"; +const char TICameraParameters::KEY_IPP[] = "ipp"; +const char TICameraParameters::KEY_METERING_MODE[] = "meter-mode"; +const char TICameraParameters::KEY_EXP_BRACKETING_RANGE[] = "exp-bracketing-range"; +const char TICameraParameters::KEY_EXP_GAIN_BRACKETING_RANGE[] = "exp-gain-bracketing-range"; +const char TICameraParameters::KEY_ZOOM_BRACKETING_RANGE[] = "zoom-bracketing-range"; +const char TICameraParameters::KEY_TEMP_BRACKETING[] = "temporal-bracketing"; +const char TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS[] = "temporal-bracketing-range-positive"; +const char TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG[] = "temporal-bracketing-range-negative"; +const char TICameraParameters::KEY_FLUSH_SHOT_CONFIG_QUEUE[] = "flush-shot-config-queue"; +const char TICameraParameters::KEY_MEASUREMENT_ENABLE[] = "measurement"; +const char TICameraParameters::KEY_GBCE[] = "gbce"; +const char TICameraParameters::KEY_GBCE_SUPPORTED[] = "gbce-supported"; +const char TICameraParameters::KEY_GLBCE[] = "glbce"; +const char TICameraParameters::KEY_GLBCE_SUPPORTED[] = "glbce-supported"; +const char TICameraParameters::KEY_CURRENT_ISO[] = "current-iso"; +const char TICameraParameters::KEY_SENSOR_ORIENTATION[] = "sensor-orientation"; +const char TICameraParameters::KEY_RECORDING_HINT[] = "internal-recording-hint"; +const char TICameraParameters::KEY_AUTO_FOCUS_LOCK[] = "auto-focus-lock"; +const char TICameraParameters::KEY_FRAMERATE_RANGES_EXT_SUPPORTED[] = "preview-fps-range-ext-values"; +const char TICameraParameters::KEY_FRAMERATES_EXT_SUPPORTED[] = "preview-fps-ext-values"; + +const char TICameraParameters::RAW_WIDTH[] = "raw-width"; +const char TICameraParameters::RAW_HEIGHT[] = "raw-height"; + +// TI extensions for Stereo Mode +const char TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT[] = "s3d-prv-frame-layout"; +const char TICameraParameters::KEY_S3D_PRV_FRAME_LAYOUT_VALUES[] = "s3d-prv-frame-layout-values"; +const char TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT[] = "s3d-cap-frame-layout"; +const char TICameraParameters::KEY_S3D_CAP_FRAME_LAYOUT_VALUES[] = "s3d-cap-frame-layout-values"; + +//TI extentions fo 3D resolutions +const char TICameraParameters::KEY_SUPPORTED_PICTURE_SUBSAMPLED_SIZES[] = "supported-picture-subsampled-size-values"; +const char TICameraParameters::KEY_SUPPORTED_PICTURE_TOPBOTTOM_SIZES[] = "supported-picture-topbottom-size-values"; +const char TICameraParameters::KEY_SUPPORTED_PICTURE_SIDEBYSIDE_SIZES[] = "supported-picture-sidebyside-size-values"; +const char TICameraParameters::KEY_SUPPORTED_PREVIEW_SUBSAMPLED_SIZES[] = "supported-preview-subsampled-size-values"; +const char TICameraParameters::KEY_SUPPORTED_PREVIEW_TOPBOTTOM_SIZES[] = "supported-preview-topbottom-size-values"; +const char TICameraParameters::KEY_SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES[] = "supported-preview-sidebyside-size-values"; + +//TI extensions for SAC/SMC +const char TICameraParameters::KEY_AUTOCONVERGENCE_MODE[] = "auto-convergence-mode"; +const char TICameraParameters::KEY_AUTOCONVERGENCE_MODE_VALUES[] = "auto-convergence-mode-values"; +const char TICameraParameters::KEY_MANUAL_CONVERGENCE[] = "manual-convergence"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_MIN[] = "supported-manual-convergence-min"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_MAX[] = "supported-manual-convergence-max"; +const char TICameraParameters::KEY_SUPPORTED_MANUAL_CONVERGENCE_STEP[] = "supported-manual-convergence-step"; + +//TI extensions for setting EXIF tags +const char TICameraParameters::KEY_EXIF_MODEL[] = "exif-model"; +const char TICameraParameters::KEY_EXIF_MAKE[] = "exif-make"; + +//TI extensions for additiona GPS data +const char TICameraParameters::KEY_GPS_MAPDATUM[] = "gps-mapdatum"; +const char TICameraParameters::KEY_GPS_VERSION[] = "gps-version"; +const char TICameraParameters::KEY_GPS_DATESTAMP[] = "gps-datestamp"; + +// TI extensions for slice mode implementation for VTC +const char TICameraParameters::KEY_VTC_HINT[] = "internal-vtc-hint"; +const char TICameraParameters::KEY_VIDEO_ENCODER_HANDLE[] = "encoder_handle"; +const char TICameraParameters::KEY_VIDEO_ENCODER_SLICE_HEIGHT[] = "encoder_slice_height"; + +//TI extensions to Image post-processing +const char TICameraParameters::IPP_LDCNSF[] = "ldc-nsf"; +const char TICameraParameters::IPP_LDC[] = "ldc"; +const char TICameraParameters::IPP_NSF[] = "nsf"; +const char TICameraParameters::IPP_NONE[] = "off"; + +// TI extensions to standard android pixel formats +const char TICameraParameters::PIXEL_FORMAT_UNUSED[] = "unused"; +const char TICameraParameters::PIXEL_FORMAT_JPS[] = "jps"; +const char TICameraParameters::PIXEL_FORMAT_MPO[] = "mpo"; +const char TICameraParameters::PIXEL_FORMAT_YUV422I_UYVY[] = "yuv422i-uyvy"; + +// TI extensions to standard android scene mode settings +const char TICameraParameters::SCENE_MODE_CLOSEUP[] = "closeup"; +const char TICameraParameters::SCENE_MODE_AQUA[] = "aqua"; +const char TICameraParameters::SCENE_MODE_SNOWBEACH[] = "snow-beach"; +const char TICameraParameters::SCENE_MODE_MOOD[] = "mood"; +const char TICameraParameters::SCENE_MODE_NIGHT_INDOOR[] = "night-indoor"; +const char TICameraParameters::SCENE_MODE_DOCUMENT[] = "document"; +const char TICameraParameters::SCENE_MODE_BARCODE[] = "barcode"; +const char TICameraParameters::SCENE_MODE_VIDEO_SUPER_NIGHT[] = "super-night"; +const char TICameraParameters::SCENE_MODE_VIDEO_CINE[] = "cine"; +const char TICameraParameters::SCENE_MODE_VIDEO_OLD_FILM[] = "old-film"; + +// TI extensions to standard android white balance values. +const char TICameraParameters::WHITE_BALANCE_TUNGSTEN[] = "tungsten"; +const char TICameraParameters::WHITE_BALANCE_HORIZON[] = "horizon"; +const char TICameraParameters::WHITE_BALANCE_SUNSET[] = "sunset"; +const char TICameraParameters::WHITE_BALANCE_FACE[] = "face-priority"; + +// TI extensions to standard android focus modes. +const char TICameraParameters::FOCUS_MODE_PORTRAIT[] = "portrait"; +const char TICameraParameters::FOCUS_MODE_EXTENDED[] = "extended"; +const char TICameraParameters::FOCUS_MODE_FACE[] = "face-priority"; +const char TICameraParameters::FOCUS_MODE_OFF[] = "off"; + +// TI extensions to add values for effect settings. +const char TICameraParameters::EFFECT_NATURAL[] = "natural"; +const char TICameraParameters::EFFECT_VIVID[] = "vivid"; +const char TICameraParameters::EFFECT_COLOR_SWAP[] = "color-swap"; +const char TICameraParameters::EFFECT_BLACKWHITE[] = "blackwhite"; + +// TI extensions to add exposure preset modes +const char TICameraParameters::EXPOSURE_MODE_MANUAL[] = "manual"; +const char TICameraParameters::EXPOSURE_MODE_AUTO[] = "auto"; +const char TICameraParameters::EXPOSURE_MODE_NIGHT[] = "night"; +const char TICameraParameters::EXPOSURE_MODE_BACKLIGHT[] = "backlighting"; +const char TICameraParameters::EXPOSURE_MODE_SPOTLIGHT[] = "spotlight"; +const char TICameraParameters::EXPOSURE_MODE_SPORTS[] = "sports"; +const char TICameraParameters::EXPOSURE_MODE_SNOW[] = "snow"; +const char TICameraParameters::EXPOSURE_MODE_BEACH[] = "beach"; +const char TICameraParameters::EXPOSURE_MODE_APERTURE[] = "aperture"; +const char TICameraParameters::EXPOSURE_MODE_SMALL_APERTURE[] = "small-aperture"; +const char TICameraParameters::EXPOSURE_MODE_FACE[] = "face-priority"; + +// TI extensions to add iso values +const char TICameraParameters::ISO_MODE_AUTO[] = "auto"; +const char TICameraParameters::ISO_MODE_100[] = "100"; +const char TICameraParameters::ISO_MODE_200[] = "200"; +const char TICameraParameters::ISO_MODE_400[] = "400"; +const char TICameraParameters::ISO_MODE_800[] = "800"; +const char TICameraParameters::ISO_MODE_1000[] = "1000"; +const char TICameraParameters::ISO_MODE_1200[] = "1200"; +const char TICameraParameters::ISO_MODE_1600[] = "1600"; + +//TI extensions for stereo frame layouts +const char TICameraParameters::S3D_NONE[] = "none"; +const char TICameraParameters::S3D_TB_FULL[] = "tb-full"; +const char TICameraParameters::S3D_SS_FULL[] = "ss-full"; +const char TICameraParameters::S3D_TB_SUBSAMPLED[] = "tb-subsampled"; +const char TICameraParameters::S3D_SS_SUBSAMPLED[] = "ss-subsampled"; + +// TI extensions to add auto convergence values +const char TICameraParameters::AUTOCONVERGENCE_MODE_DISABLE[] = "disable"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_FRAME[] = "frame"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_CENTER[] = "center"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_TOUCH[] = "touch"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_MANUAL[] = "manual"; + +//TI values for camera direction +const char TICameraParameters::FACING_FRONT[]="front"; +const char TICameraParameters::FACING_BACK[]="back"; + +//TI extensions to flash settings +const char TICameraParameters::FLASH_MODE_FILL_IN[] = "fill-in"; + +//TI extensions to add sensor orientation parameters +const char TICameraParameters::ORIENTATION_SENSOR_NONE[] = "0"; +const char TICameraParameters::ORIENTATION_SENSOR_90[] = "90"; +const char TICameraParameters::ORIENTATION_SENSOR_180[] = "180"; +const char TICameraParameters::ORIENTATION_SENSOR_270[] = "270"; + +const char TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED[] = "mechanical-misalignment-correction-supported"; +const char TICameraParameters::KEY_MECHANICAL_MISALIGNMENT_CORRECTION[] = "mechanical-misalignment-correction"; + +//TI extensions for enable/disable algos +const char TICameraParameters::KEY_ALGO_EXTERNAL_GAMMA[] = TI_KEY_ALGO_PREFIX "external-gamma"; +const char TICameraParameters::KEY_ALGO_NSF1[] = TI_KEY_ALGO_PREFIX "nsf1"; +const char TICameraParameters::KEY_ALGO_NSF2[] = TI_KEY_ALGO_PREFIX "nsf2"; +const char TICameraParameters::KEY_ALGO_SHARPENING[] = TI_KEY_ALGO_PREFIX "sharpening"; +const char TICameraParameters::KEY_ALGO_THREELINCOLORMAP[] = TI_KEY_ALGO_PREFIX "threelinecolormap"; +const char TICameraParameters::KEY_ALGO_GIC[] = TI_KEY_ALGO_PREFIX "gic"; + +const char TICameraParameters::KEY_GAMMA_TABLE[] = "gamma-table"; + +const char TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE[] = "preview-frame-rate-range"; + +#ifdef MOTOROLA_CAMERA +const char TICameraParameters::KEY_MOT_LEDFLASH[] = "mot-led-flash"; // U32, default 100, percent +const char TICameraParameters::KEY_MOT_LEDTORCH[] = "mot-led-torch"; // U32, default 100, percent +#endif + +} // namespace Camera +} // namespace Ti diff --git a/camera/V4LCameraAdapter/V4LCameraAdapter.cpp b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp new file mode 100644 index 0000000..e2cc5f3 --- /dev/null +++ b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp @@ -0,0 +1,1684 @@ +/* + * 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. + */ + +/** +* @file V4LCameraAdapter.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + + +#include "V4LCameraAdapter.h" +#include "CameraHal.h" +#include "TICameraParameters.h" +#include "DebugUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DecoderFactory.h" + +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +static int mDebugFps = 0; + +#define Q16_OFFSET 16 + +#define HERE(Msg) {CAMHAL_LOGEB("--=== %s===--\n", Msg);} + +namespace Ti { +namespace Camera { + +//frames skipped before recalculating the framerate +#define FPS_PERIOD 30 + +//Proto Types +static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ); +static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ); +static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ); + +android::Mutex gV4LAdapterLock; +char device[15]; + +static void debugShowFPS() +{ + static int mFrameCount = 0; + static int mLastFrameCount = 0; + static nsecs_t mLastFpsTime = 0; + static float mFps = 0; + if(mDebugFps) { + mFrameCount++; + if ((mFrameCount % 30 == 0)) { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + CAMHAL_LOGE("Camera %d Frames, %f FPS", mFrameCount, mFps); + } + } +} + + +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +/*--------------------V4L wrapper functions -------------------------------*/ + +bool V4LCameraAdapter::isNeedToUseDecoder() const { + return mPixelFormat != V4L2_PIX_FMT_YUYV; +} + +status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) { + status_t ret = NO_ERROR; + errno = 0; + + android::AutoMutex lock(mV4LLock); + + do { + ret = ioctl (fd, req, argp); + }while (-1 == ret && EINTR == errno); + + return ret; +} + +status_t V4LCameraAdapter::v4lInitMmap(int& count, int width, int height) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + //First allocate adapter internal buffers at V4L level for USB Cam + //These are the buffers from which we will copy the data into overlay buffers + /* Check if camera can handle NB_BUFFER buffers */ + mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; + mVideoInfo->rb.count = count; + + ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); + return ret; + } + + count = mVideoInfo->rb.count; + + //Since we will do mapping of new In buffers - clear input MediaBuffer storage + mInBuffers.clear(); + + for (int i = 0; i < count; i++) { + + memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno)); + return ret; + } + + mVideoInfo->mem[i] = mmap (NULL, + mVideoInfo->buf.length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + mCameraHandle, + mVideoInfo->buf.m.offset); + + CAMHAL_LOGVB(" mVideoInfo->mem[%d]=%p ; mVideoInfo->buf.length = %d", i, mVideoInfo->mem[i], mVideoInfo->buf.length); + if (mVideoInfo->mem[i] == MAP_FAILED) { + CAMHAL_LOGEB("Unable to map buffer [%d]. (%s)", i, strerror(errno)); + return -1; + } + + MediaBuffer* buffer = new MediaBuffer(i, mVideoInfo->mem[i], mVideoInfo->buf.length); + mInBuffers.push_back(buffer); + } + + if (isNeedToUseDecoder()) { + mDecoder->registerInputBuffers(&mInBuffers); + DecoderParameters params; + params.width = width; + params.height = height; + params.inputBufferCount = count; + params.outputBufferCount = count; + mDecoder->configure(params); + } + + + + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::v4lInitUsrPtr(int& count) { + status_t ret = NO_ERROR; + + mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->rb.memory = V4L2_MEMORY_USERPTR; + mVideoInfo->rb.count = count; + + ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_REQBUFS failed for USERPTR: %s", strerror(errno)); + return ret; + } + + count = mVideoInfo->rb.count; + return ret; +} + +status_t V4LCameraAdapter::v4lStartStreaming () { + status_t ret = NO_ERROR; + enum v4l2_buf_type bufType; + + LOG_FUNCTION_NAME; + + if (!mVideoInfo->isStreaming) { + bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = applyFpsValue(); + if (ret != NO_ERROR) { + return ret; + } + ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMON, &bufType); + if (ret < 0) { + CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno)); + return ret; + } + mVideoInfo->isStreaming = true; + } + + // This is WA for some cameras with incorrect driver behavior + // there is possibility that fist frame after VIDIOC_STREAMON + // will remain from previous resolution/will be distorted + // for such cameras can be dynamically set frame count that will be + // skipped after frame on. + for (int i = 0; i < mSkipFramesCount; i++) { + int id = 0, length = 0; + if (GetFrame(id, length) != NULL) { + returnBufferToV4L(id); + } + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::v4lStopStreaming (int nBufferCount) { + status_t ret = NO_ERROR; + enum v4l2_buf_type bufType; + + LOG_FUNCTION_NAME; + + if (mVideoInfo->isStreaming) { + bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType); + if (ret != 0) { + CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno)); + return ret; + } + mVideoInfo->isStreaming = false; + + /* Unmap buffers */ + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + for (int i = 0; i < nBufferCount; i++) { + if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) { + CAMHAL_LOGEA("munmap() failed"); + } + mVideoInfo->mem[i] = 0; + } + + //free the memory allocated during REQBUFS, by setting the count=0 + mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; + mVideoInfo->rb.count = 0; + + ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); + goto EXIT; + } + } +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::v4lSetFormat (int width, int height, uint32_t pix_format) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_G_FMT Failed: %s", strerror(errno)); + } + + mVideoInfo->width = width; + mVideoInfo->height = height; + mVideoInfo->framesizeIn = (width * height << 1); + mVideoInfo->formatIn = pix_format; + + mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->format.fmt.pix.width = width; + mVideoInfo->format.fmt.pix.height = height; + mVideoInfo->format.fmt.pix.pixelformat = pix_format; + + ret = v4lIoctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_S_FMT Failed: %s", strerror(errno)); + return ret; + } + v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); + CAMHAL_LOGDB("VIDIOC_G_FMT : WxH = %dx%d", mVideoInfo->format.fmt.pix.width, mVideoInfo->format.fmt.pix.height); + CAMHAL_LOGD("### Using: WxH = %dx%d pixelformat=0x%x ", mVideoInfo->format.fmt.pix.width, mVideoInfo->format.fmt.pix.height, mVideoInfo->format.fmt.pix.pixelformat); + CAMHAL_LOGD("### Using: bytesperline=%d sizeimage=%d colorspace=0x%x", mVideoInfo->format.fmt.pix.bytesperline, mVideoInfo->format.fmt.pix.sizeimage, mVideoInfo->format.fmt.pix.colorspace); + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::restartPreview () +{ + status_t ret = NO_ERROR; + int width = 0; + int height = 0; + struct v4l2_streamparm streamParams; + + LOG_FUNCTION_NAME; + + //configure for preview size and pixel format. + mParams.getPreviewSize(&width, &height); + + ret = v4lSetFormat (width, height, mPixelFormat); + if (ret < 0) { + CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); + goto EXIT; + } + + ret = v4lInitMmap(mPreviewBufferCount, width, height); + if (ret < 0) { + CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); + goto EXIT; + } + + for (int i = 0; i < mPreviewBufferCountQueueable; i++) { + + v4l2_buffer buf; + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed"); + goto EXIT; + } + nQueued++; + } + + if (isNeedToUseDecoder()) { + for (int i = 0; i < mPreviewBufferCountQueueable; i++) { + mDecoder->queueOutputBuffer(i); + CAMHAL_LOGV("Queued output buffer with id=%d ", i); + } + mDecoder->start(); + } + + ret = v4lStartStreaming(); + CAMHAL_LOGDA("Ready for preview...."); +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +/*--------------------Camera Adapter Functions-----------------------------*/ +status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps) +{ + char value[PROPERTY_VALUE_MAX]; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + property_get("debug.camera.showfps", value, "0"); + mDebugFps = atoi(value); + + int ret = NO_ERROR; + + // Allocate memory for video info structure + mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo)); + if(!mVideoInfo) { + ret = NO_MEMORY; + goto EXIT; + } + + if ((mCameraHandle = open(device, O_RDWR | O_NONBLOCK) ) == -1) { + CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno)); + ret = BAD_VALUE; + goto EXIT; + } + + ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap); + if (ret < 0) { + CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); + ret = BAD_VALUE; + goto EXIT; + } + + if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { + CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); + ret = BAD_VALUE; + goto EXIT; + } + + if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING)) { + CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o"); + ret = BAD_VALUE; + goto EXIT; + } + + // Initialize flags + mPreviewing = false; + mVideoInfo->isStreaming = false; + mRecording = false; + mCapturing = false; +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::FrameType frameType) +{ + status_t ret = NO_ERROR; + int idx = 0; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if ( frameType == CameraFrame::IMAGE_FRAME) { //(1 > mCapturedFrames) + // Signal end of image capture + if ( NULL != mEndImageCaptureCallback) { + CAMHAL_LOGDB("===========Signal End Image Capture=========="); + mLock.unlock(); + mEndImageCaptureCallback(mEndCaptureData); + mLock.lock(); + } + return ret; + } + + if ( !mVideoInfo->isStreaming ) { + return ret; + } + + for (int xx = 0; xx < NB_BUFFER; xx++){ + if (mPreviewBufs[xx] == frameBuf){ + idx = xx; + break; + } + } + if (idx == NB_BUFFER){ + CAMHAL_LOGEB("Wrong index = %d. What do i do? What do i do?",idx); + return ret; + } + if(idx < 0) { + CAMHAL_LOGEB("Wrong index = %d",idx); + return ret; + } + if (isNeedToUseDecoder()) { + for (int i = 0; i < mOutBuffers.size(); i++) { + android::sp& outBuffer = mOutBuffers.editItemAt(i); + CameraBuffer* buffer = static_cast(outBuffer->buffer); + if (buffer == frameBuf) { + mDecoder->queueOutputBuffer(outBuffer->bufferId); + break; + } + } + + int inIndex = -1; + ret = mDecoder->dequeueInputBuffer(inIndex); + + if (ret == NO_ERROR) { + ret = returnBufferToV4L(inIndex); + } + + } else { + v4l2_buffer buf; + buf.index = idx; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + CAMHAL_LOGD("Will return buffer to V4L with id=%d", idx); + ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed"); + goto EXIT; + } + + nQueued++; + } + +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; + +} + +status_t V4LCameraAdapter::applyFpsValue() { + struct v4l2_streamparm streamParams; + status_t ret = NO_ERROR; + streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; + streamParams.parm.capture.timeperframe.denominator = mFrameRate / CameraHal::VFR_SCALE; + streamParams.parm.capture.timeperframe.numerator= 1; + ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams); + if (ret < 0) { + CAMHAL_LOGEB(" VIDIOC_S_PARM Failed: %s", strerror(errno)); + return ret; + } + int actualFps = streamParams.parm.capture.timeperframe.denominator / streamParams.parm.capture.timeperframe.numerator; + CAMHAL_LOGDB("Actual FPS set is : %d.", actualFps); + return NO_ERROR; +} + +status_t V4LCameraAdapter::setParameters(const android::CameraParameters ¶ms) +{ + status_t ret = NO_ERROR; + int width, height; + int minFps = 0, maxFps = 0; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if(!mPreviewing && !mCapturing) { + params.getPreviewSize(&width, &height); + CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, mPixelFormat); + ret = v4lSetFormat( width, height, mPixelFormat); + if (ret < 0) { + CAMHAL_LOGEB(" VIDIOC_S_FMT Failed: %s", strerror(errno)); + goto EXIT; + } + const char *frameRateRange = params.get(TICameraParameters::KEY_PREVIEW_FRAME_RATE_RANGE); + bool fpsRangeParsed = CameraHal::parsePair(frameRateRange, &minFps, &maxFps, ','); + CAMHAL_ASSERT(fpsRangeParsed); + CAMHAL_LOGD("Current fps is %d new fps is (%d,%d)", mFrameRate, minFps, maxFps); + if (maxFps != mFrameRate) { + mFrameRate = maxFps; + } + + } + + // Udpate the current parameter set + mParams = params; + +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +void V4LCameraAdapter::getParameters(android::CameraParameters& params) +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + // Return the current parameter set + params = mParams; + + LOG_FUNCTION_NAME_EXIT; +} + + +///API to give the buffers to Adapter +status_t V4LCameraAdapter::useBuffers(CameraMode mode, CameraBuffer *bufArr, int num, size_t length, unsigned int queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + switch(mode) + { + case CAMERA_PREVIEW: + mPreviewBufferCountQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_IMAGE_CAPTURE: + mCaptureBufferCountQueueable = queueable; + ret = UseBuffersCapture(bufArr, num); + break; + + case CAMERA_VIDEO: + //@warn Video capture is not fully supported yet + mPreviewBufferCountQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_MEASUREMENT: + break; + + default: + break; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::UseBuffersCapture(CameraBuffer *bufArr, int num) { + int ret = NO_ERROR; + + LOG_FUNCTION_NAME; + if(NULL == bufArr) { + ret = BAD_VALUE; + goto EXIT; + } + + for (int i = 0; i < num; i++) { + //Associate each Camera internal buffer with the one from Overlay + mCaptureBufs.add(&bufArr[i], i); + CAMHAL_LOGDB("capture- buff [%d] = 0x%x ",i, mCaptureBufs.keyAt(i)); + } + + mCaptureBuffersAvailable.clear(); + for (int i = 0; i < mCaptureBufferCountQueueable; i++ ) { + mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 0); + } + + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for (int i = mCaptureBufferCountQueueable; i < num; i++ ) { + mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 1); + } + + // Update the preview buffer count + mCaptureBufferCount = num; +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; + +} + +status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num) +{ + int ret = NO_ERROR; + int width = 0, height = 0; + + LOG_FUNCTION_NAME; + + if(NULL == bufArr) { + ret = BAD_VALUE; + goto EXIT; + } + + mParams.getPreviewSize(&width, &height); + ret = v4lInitMmap(num, width, height); + + mOutBuffers.clear(); + + if (ret == NO_ERROR) { + for (int i = 0; i < num; i++) { + //Associate each Camera internal buffer with the one from Overlay + mPreviewBufs[i] = &bufArr[i]; + MediaBuffer* buffer = new MediaBuffer(i, mPreviewBufs[i]); + mOutBuffers.push_back(buffer); + CAMHAL_LOGDB("Preview- buff [%d] = 0x%x length=%d",i, mPreviewBufs[i], mFrameQueue.valueFor(mPreviewBufs[i])->mLength); + } + if (isNeedToUseDecoder()) { + mDecoder->registerOutputBuffers(&mOutBuffers); + } + // Update the preview buffer count + mPreviewBufferCount = num; + } +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::takePicture() { + status_t ret = NO_ERROR; + int width = 0; + int height = 0; + size_t yuv422i_buff_size = 0; + int index = 0; + char *fp = NULL; + CameraBuffer *buffer = NULL; + CameraFrame frame; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if (mCapturing) { + CAMHAL_LOGEA("Already Capture in Progress..."); + return BAD_VALUE; + } + + mPreviewing = false; + mLock.unlock(); + + { + android::AutoMutex stopLock(mStopLock); + CAMHAL_LOGW("Wait till preview stops"); + ret = mStopCondition.waitRelative(mStopLock, 100000000); + if (ret != NO_ERROR) { + CAMHAL_LOGW("Timeout waiting for preview stop"); + } + } + + if (isNeedToUseDecoder()) { + mDecoder->stop(); + mDecoder->flush(); + } + mLock.lock(); + mCapturing = true; + mPreviewing = false; + + // Stop preview streaming + ret = v4lStopStreaming(mPreviewBufferCount); + if (ret < 0 ) { + CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); + goto EXIT; + } + + //configure for capture image size and pixel format. + mParams.getPictureSize(&width, &height); + CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height); + yuv422i_buff_size = width * height * 2; + + ret = v4lSetFormat (width, height, DEFAULT_CAPTURE_FORMAT); + if (ret < 0) { + CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); + goto EXIT; + } + + ret = v4lInitMmap(mCaptureBufferCount, width, height); + if (ret < 0) { + CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); + goto EXIT; + } + + for (int i = 0; i < mCaptureBufferCountQueueable; i++) { + + v4l2_buffer buf; + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed"); + return BAD_VALUE; + } + nQueued++; + } + + ret = v4lStartStreaming(); + if (ret < 0) { + CAMHAL_LOGEB("v4lStartStreaming Failed: %s", strerror(errno)); + goto EXIT; + } + + CAMHAL_LOGDA("Streaming started for Image Capture"); + + //get the frame and send to encode as JPG + int filledLen; + CAMHAL_LOGD("*********Will dequeue frame for Image Capture***********"); + + fp = this->GetFrame(index, filledLen); + if (!fp) { + CAMHAL_LOGEA("!!! Captured frame is NULL !!!!"); + return BAD_VALUE; + } + + + + CAMHAL_LOGDA("::Capture Frame received from V4L::"); + buffer = mCaptureBufs.keyAt(index); + CAMHAL_LOGVB("## captureBuf[%d] = 0x%x, yuv422i_buff_size=%d fill_length=%d", index, buffer->opaque, yuv422i_buff_size, filledLen); + + //copy the yuv422i data to the image buffer. + memcpy(buffer->opaque, fp, filledLen); + +#ifdef DUMP_CAPTURE_FRAME + //dump the YUV422 buffer in to a file + //a folder should have been created at /data/misc/camera/raw/ + { + int fd =-1; + fd = open("/data/misc/camera/raw/captured_yuv422i_dump.yuv", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + if(fd < 0) { + CAMHAL_LOGEB("Unable to open file: %s", strerror(fd)); + } + else { + write(fd, fp, yuv422i_buff_size ); + close(fd); + CAMHAL_LOGDB("::Captured Frame dumped at /data/misc/camera/raw/captured_yuv422i_dump.yuv::"); + } + } +#endif + + CAMHAL_LOGDA("::sending capture frame to encoder::"); + frame.mFrameType = CameraFrame::IMAGE_FRAME; + frame.mBuffer = buffer; + frame.mLength = yuv422i_buff_size; + frame.mWidth = width; + frame.mHeight = height; + frame.mAlignment = width*2; + frame.mOffset = 0; + frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); + frame.mFrameMask = (unsigned int)CameraFrame::IMAGE_FRAME; + frame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG; + frame.mQuirks |= CameraFrame::FORMAT_YUV422I_YUYV; + + ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); + if (ret != NO_ERROR) { + CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); + } else { + ret = sendFrameToSubscribers(&frame); + } + + // Stop streaming after image capture + ret = v4lStopStreaming(mCaptureBufferCount); + if (ret < 0 ) { + CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); + goto EXIT; + } + ret = restartPreview(); +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::stopImageCapture() +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + //Release image buffers + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + mCaptureBufs.clear(); + + mCapturing = false; + mPreviewing = true; + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::autoFocus() +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + //autoFocus is not implemented. Just return. + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if(mPreviewing) { + ret = BAD_VALUE; + goto EXIT; + } + + for (int i = 0; i < mPreviewBufferCountQueueable; i++) { + v4l2_buffer buf; + + memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno)); + return ret; + } + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed"); + goto EXIT; + } + nQueued++; + } + + if (isNeedToUseDecoder()) { + for (int i = 0; i < mPreviewBufferCountQueueable; i++) { + mDecoder->queueOutputBuffer(i); + CAMHAL_LOGV("Queued output buffer with id=%d ", i); + } + mDecoder->start(); + } + ret = v4lStartStreaming(); + + // Create and start preview thread for receiving buffers from V4L Camera + if(!mCapturing) { + mPreviewThread = new PreviewThread(this); + CAMHAL_LOGDA("Created preview thread"); + } + + //Update the flag to indicate we are previewing + mPreviewing = true; + mCapturing = false; + +EXIT: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t V4LCameraAdapter::stopPreview() +{ + enum v4l2_buf_type bufType; + int ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + if(!mPreviewing) { + return NO_INIT; + } + mPreviewing = false; + if (isNeedToUseDecoder()) { + android::AutoMutex lock(mStopLock); + mStopCondition.waitRelative(mStopLock, 100000000); + mDecoder->stop(); + mDecoder->flush(); + } + ret = v4lStopStreaming(mPreviewBufferCount); + if (ret < 0) { + CAMHAL_LOGEB("StopStreaming: FAILED: %s", strerror(errno)); + } + + nQueued = 0; + nDequeued = 0; + mFramesWithEncoder = 0; + + mLock.unlock(); + + mPreviewThread->requestExitAndWait(); + mPreviewThread.clear(); + + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +void saveFile(unsigned char* buff, int buff_size) { + static int counter = 1; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + if (counter > 30) { + return; + } + //dump nv12 buffer + counter++; + sprintf(fn, "/data/tmp/dump_%03d.h264", counter); + CAMHAL_LOGEB("Dumping h264 frame to a file : %s.", fn); + + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + if(fd < 0) { + CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd)); + return; + } + + write(fd, buff, buff_size ); + close(fd); + + LOG_FUNCTION_NAME_EXIT; +} + +char * V4LCameraAdapter::GetFrame(int &index, int &filledLen) +{ + int ret = NO_ERROR; + LOG_FUNCTION_NAME; + + v4l2_buffer buf; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + /* DQ */ + // Some V4L drivers, notably uvc, protect each incoming call with + // a driver-wide mutex. If we use poll() or blocking VIDIOC_DQBUF ioctl + // here then we sometimes would run into a deadlock on VIDIO_QBUF ioctl. + while(true) { + if(!mVideoInfo->isStreaming) { + return NULL; + } + + ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &buf); + if((ret == 0) || (errno != EAGAIN)) { + break; + } + } + + if (ret < 0) { + CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed"); + return NULL; + } + + index = buf.index; + filledLen = buf.bytesused; + + android::sp& inBuffer = mInBuffers.editItemAt(index); + { + android::AutoMutex bufferLock(inBuffer->getLock()); + inBuffer->setTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)); + inBuffer->filledLen = buf.bytesused; + } + debugShowFPS(); + LOG_FUNCTION_NAME_EXIT; + return (char *)mVideoInfo->mem[index]; +} + + + + + +//API to get the frame size required to be allocated. This size is used to override the size passed +//by camera service when VSTAB/VNF is turned ON for example +status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + // Just return the current preview size, nothing more to do here. + mParams.getPreviewSize(( int * ) &width,( int * ) &height); + + // TODO: This will reside until correct port reconfiguration handling will done. + if (isNeedToUseDecoder()) { + mDecoder->getPaddedDimensions(width, height); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + android::AutoMutex lock(mLock); + // We don't support meta data, so simply return + return NO_ERROR; +} + +status_t V4LCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount) +{ + int width = 0; + int height = 0; + int bytesPerPixel = 2; // for YUV422i; default pixel format + + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + mParams.getPictureSize( &width, &height ); + frame.mLength = width * height * bytesPerPixel; + frame.mWidth = width; + frame.mHeight = height; + frame.mAlignment = width * bytesPerPixel; + + CAMHAL_LOGDB("Picture size: W x H = %u x %u (size=%u bytes, alignment=%u bytes)", + frame.mWidth, frame.mHeight, frame.mLength, frame.mAlignment); + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + +status_t V4LCameraAdapter::recalculateFPS() +{ + float currentFPS; + + mFrameCount++; + + if ( ( mFrameCount % FPS_PERIOD ) == 0 ) + { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFPSTime; + currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFPSTime = now; + mLastFrameCount = mFrameCount; + + if ( 1 == mIter ) + { + mFPS = currentFPS; + } + else + { + //cumulative moving average + mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; + } + + mLastFPS = mFPS; + mIter++; + } + + return NO_ERROR; +} + +void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + + android::AutoMutex lock(mLock); + + LOG_FUNCTION_NAME_EXIT; +} + +void V4LCameraAdapter::setupWorkingMode() { + char value[PROPERTY_VALUE_MAX]; + int v4lMode = 0; + + property_get("camera.v4l.mode", value, "3"); + v4lMode = atoi(value); + + if (mDecoder) { + delete mDecoder; + mDecoder = NULL; + } + + switch (v4lMode) { + case 0 : { + mPixelFormat = V4L2_PIX_FMT_MJPEG; + mCameraHal->setExternalLocking(true); + mDecoder = DecoderFactory::createDecoderByType(DecoderType_MJPEG, false); + CAMHAL_LOGI("Using V4L preview format: V4L2_PIX_FMT_MJPEG with HW decoding"); + break; + } + + case 1 : { + mPixelFormat = V4L2_PIX_FMT_MJPEG; + mCameraHal->setExternalLocking(false); + mDecoder = DecoderFactory::createDecoderByType(DecoderType_MJPEG, true); + CAMHAL_LOGI("Using V4L preview format: V4L2_PIX_FMT_MJPEG with SW decoding"); + break; + } + + case 2 : { + mPixelFormat = V4L2_PIX_FMT_H264; + mCameraHal->setExternalLocking(true); + mDecoder = DecoderFactory::createDecoderByType(DecoderType_H264, false); + CAMHAL_LOGI("Using V4L preview format: V4L2_PIX_FMT_H264"); + break; + } + default: + case 3 : { + mCameraHal->setExternalLocking(false); + mPixelFormat = V4L2_PIX_FMT_YUYV; + CAMHAL_LOGI("Using V4L preview format: V4L2_PIX_FMT_YUYV"); + } + + } +} + +V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index, CameraHal* hal) + :mPixelFormat(DEFAULT_PIXEL_FORMAT), mFrameRate(0), mCameraHal(hal), + mSkipFramesCount(0) +{ + LOG_FUNCTION_NAME; + + char value[PROPERTY_VALUE_MAX]; + + // Nothing useful to do in the constructor + mFramesWithEncoder = 0; + mDecoder = 0; + nQueued = 0; + nDequeued = 0; + + setupWorkingMode(); + + property_get("camera.v4l.skipframes", value, "1"); + mSkipFramesCount = atoi(value); + + LOG_FUNCTION_NAME_EXIT; +} + +V4LCameraAdapter::~V4LCameraAdapter() +{ + LOG_FUNCTION_NAME; + + // Close the camera handle and free the video info structure + close(mCameraHandle); + + if (mVideoInfo) + { + free(mVideoInfo); + mVideoInfo = NULL; + } + + delete mDecoder; + + mInBuffers.clear(); + mOutBuffers.clear(); + + LOG_FUNCTION_NAME_EXIT; +} + +static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ) { + //convert YUV422I yuyv to uyvy format. + uint32_t *bf = (uint32_t*)src; + uint32_t *dst = (uint32_t*)dest; + + LOG_FUNCTION_NAME; + + if (!src || !dest) { + return; + } + + for(size_t i = 0; i < size; i = i+4) + { + dst[0] = ((bf[0] & 0x00FF00FF) << 8) | ((bf[0] & 0xFF00FF00) >> 8); + bf++; + dst++; + } + + LOG_FUNCTION_NAME_EXIT; +} + +static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ) { + //convert YUV422I to YUV420 NV12 format and copies directly to preview buffers (Tiler memory). + int stride = 4096; + unsigned char *bf = src; + unsigned char *dst_y = dest; + unsigned char *dst_uv = dest + ( height * stride); +#ifdef PPM_PER_FRAME_CONVERSION + static int frameCount = 0; + static nsecs_t ppm_diff = 0; + nsecs_t ppm_start = systemTime(); +#endif + + LOG_FUNCTION_NAME; + + if (width % 16 ) { + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) { + *dst_y = *bf; + dst_y++; + bf = bf + 2; + } + dst_y += (stride - width); + } + + bf = src; + bf++; //UV sample + for(int i = 0; i < height/2; i++) { + for(int j=0; j= 30) { + ppm_diff = ppm_diff / frameCount; + LOGD("PPM: YUV422i to NV12 Conversion(%d x %d): %llu us ( %llu ms )", width, height, + ns2us(ppm_diff), ns2ms(ppm_diff) ); + ppm_diff = 0; + frameCount = 0; + } +#endif + + LOG_FUNCTION_NAME_EXIT; +} + +static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ) { + //convert YUV422I to YUV420 NV12 format. + unsigned char *bf = src; + unsigned char *dst_y = dest; + unsigned char *dst_uv = dest + (width * height); + + LOG_FUNCTION_NAME; + + if (width % 16 ) { + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) { + *dst_y = *bf; + dst_y++; + bf = bf + 2; + } + } + + bf = src; + bf++; //UV sample + for(int i = 0; i < height/2; i++) { + for(int j=0; j& buffer = mOutBuffers.editItemAt(index); + + CameraBuffer* cbuffer = static_cast(buffer->buffer); + + frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; + frame.mBuffer = cbuffer; + if (isNeedToUseDecoder()) { + //We always get NV12 on out, when using decoder. + frame.mLength = height * stride * 3 / 2; + } else { + frame.mLength = CameraHal::calculateBufferSize(mParams.getPreviewFormat(), width, height); + } + frame.mAlignment = stride; + frame.mOffset = buffer->getOffset(); + frame.mTimestamp = buffer->getTimestamp(); + frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC; + + if (mRecording) + { + frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC; + mFramesWithEncoder++; + } + + int ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); + if (ret != NO_ERROR) { + CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); + } else { + ret = sendFrameToSubscribers(&frame); + } + //debugShowFPS(); + LOG_FUNCTION_NAME_EXIT; +} + +status_t V4LCameraAdapter::returnBufferToV4L(int id) { + status_t ret = NO_ERROR; + v4l2_buffer buf; + buf.index = id; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed 0x%x", ret); + return FAILED_TRANSACTION; + } + + return NO_ERROR; +} + +int V4LCameraAdapter::previewThread() +{ + status_t ret = NO_ERROR; + int width, height; + CameraFrame frame; + void *y_uv[2]; + int index = 0; + int filledLen = 0; + int stride = 4096; + char *fp = NULL; + + mParams.getPreviewSize(&width, &height); + + { + android::AutoMutex lock(mLock); + if (!mPreviewing) { + //If stop preview is called - it can now go on. + android::AutoMutex stopLock(mStopLock); + mStopCondition.signal(); + return ret; + } + } + + { + android::Mutex::Autolock lock(mSubscriberLock); + if ( mFrameSubscribers.size() == 0 ) { + return BAD_VALUE; + } + } + + if (isNeedToUseDecoder()){ + + CAMHAL_LOGV("########### Decoder ###########"); + int inIndex = -1, outIndex = -1; + + if (GetFrame(index, filledLen) != NULL) { + CAMHAL_LOGD("Dequeued buffer from V4L with ID=%d", index); + mDecoder->queueInputBuffer(index); + } + + while (NO_ERROR == mDecoder->dequeueInputBuffer(inIndex)) { + returnBufferToV4L(inIndex); + } + + while (NO_ERROR == mDecoder->dequeueOutputBuffer(outIndex)) { + returnOutputBuffer(outIndex); + } + + CAMHAL_LOGV("########### End Decode ###########"); + goto EXIT; + } + else + { + fp = GetFrame(index, filledLen); + + if(!fp) { + ret = BAD_VALUE; + goto EXIT; + } + CAMHAL_LOGD("GOT IN frame with ID=%d",index); + + CameraBuffer *buffer = mPreviewBufs[index]; + if (mPixelFormat == V4L2_PIX_FMT_YUYV) { + convertYUV422ToNV12Tiler(reinterpret_cast(fp), reinterpret_cast(buffer->mapped), width, height); + } + CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; mapped= 0x%x.",index, buffer, buffer->mapped); + +#ifdef SAVE_RAW_FRAMES + unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2); + //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file + convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height); + saveFile( nv12_buff, ((width*height)*3/2) ); + free (nv12_buff); +#endif + + android::Mutex::Autolock lock(mSubscriberLock); + + frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; + frame.mBuffer = buffer; + frame.mLength = width*height*3/2; + frame.mAlignment = stride; + frame.mOffset = 0; + frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); + frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC; + + if (mRecording) + { + frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC; + mFramesWithEncoder++; + } + + ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); + if (ret != NO_ERROR) { + CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); + } else { + ret = sendFrameToSubscribers(&frame); + } + } + +EXIT: + + return ret; +} + +//scan for video devices +void detectVideoDevice(char** video_device_list, int& num_device) { + char dir_path[20]; + char* filename; + char** dev_list = video_device_list; + DIR *d; + struct dirent *dir; + int index = 0; + + strcpy(dir_path, DEVICE_PATH); + d = opendir(dir_path); + if(d) { + //read each entry in the /dev/ and find if there is videox entry. + while ((dir = readdir(d)) != NULL) { + filename = dir->d_name; + if (strncmp(filename, DEVICE_NAME, 5) == 0) { + strcpy(dev_list[index],DEVICE_PATH); + strncat(dev_list[index],filename,sizeof(DEVICE_NAME)); + index++; + } + } //end of while() + closedir(d); + num_device = index; + + for(int i=0; iset(CameraProperties::PREVIEW_FORMAT, DEFAULT_PREVIEW_FORMAT); + + params->set(CameraProperties::PICTURE_FORMAT, DEFAULT_PICTURE_FORMAT); + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_SIZE); + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_SIZE); + params->set(CameraProperties::PREVIEW_FRAME_RATE, DEFAULT_FRAMERATE); + params->set(CameraProperties::REQUIRED_PREVIEW_BUFS, DEFAULT_NUM_PREV_BUFS); + params->set(CameraProperties::FOCUS_MODE, DEFAULT_FOCUS_MODE); + + params->set(CameraProperties::CAMERA_NAME, "USBCAMERA"); + params->set(CameraProperties::JPEG_THUMBNAIL_SIZE, "320x240"); + params->set(CameraProperties::JPEG_QUALITY, "90"); + params->set(CameraProperties::JPEG_THUMBNAIL_QUALITY, "50"); + params->set(CameraProperties::FRAMERATE_RANGE, DEFAULT_FRAMERATE_RANGE); + params->set(CameraProperties::S3D_PRV_FRAME_LAYOUT, "none"); + params->set(CameraProperties::SUPPORTED_EXPOSURE_MODES, "auto"); + params->set(CameraProperties::SUPPORTED_ISO_VALUES, "auto"); + params->set(CameraProperties::SUPPORTED_ANTIBANDING, "auto"); + params->set(CameraProperties::SUPPORTED_EFFECTS, "none"); + params->set(CameraProperties::SUPPORTED_IPP_MODES, "ldc-nsf"); + params->set(CameraProperties::FACING_INDEX, TICameraParameters::FACING_FRONT); + params->set(CameraProperties::ORIENTATION_INDEX, 0); + params->set(CameraProperties::SENSOR_ORIENTATION, "0"); + params->set(CameraProperties::VSTAB, DEFAULT_VSTAB); + params->set(CameraProperties::VNF, DEFAULT_VNF); + + //For compatibility + params->set(CameraProperties::SUPPORTED_ZOOM_RATIOS,"0"); + params->set(CameraProperties::SUPPORTED_ZOOM_STAGES, "0"); + params->set(CameraProperties::ZOOM, "0"); + params->set(CameraProperties::ZOOM_SUPPORTED, "true"); + + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::insertPreviewFormats(CameraProperties::Properties* params, V4L_TI_CAPTYPE &caps) { + + char supported[MAX_PROP_VALUE_LENGTH]; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for (int i = 0; i < caps.ulPreviewFormatCount; i++) { + for (unsigned int j = 0; j < ARRAY_SIZE(mPixelformats); j++) { + if(caps.ePreviewFormats[i] == mPixelformats[j].pixelformat ) { + strncat (supported, mPixelformats[j].param, MAX_PROP_VALUE_LENGTH-1 ); + strncat (supported, PARAM_SEP, 1 ); + } + } + } + strncat(supported, android::CameraParameters::PIXEL_FORMAT_YUV420P, MAX_PROP_VALUE_LENGTH - 1); + strncat (supported, PARAM_SEP, 1 ); + strncat(supported, android::CameraParameters::PIXEL_FORMAT_YUV420SP, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PREVIEW_FORMATS, supported); + return NO_ERROR; +} + +status_t V4LCameraAdapter::insertPreviewSizes(CameraProperties::Properties* params, V4L_TI_CAPTYPE &caps) { + + char supported[MAX_PROP_VALUE_LENGTH]; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for (int i = 0; i < caps.ulPreviewResCount; i++) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat (supported, caps.tPreviewRes[i].param, MAX_PROP_VALUE_LENGTH-1 ); + } + + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, supported); + params->set(CameraProperties::SUPPORTED_PREVIEW_SUBSAMPLED_SIZES, supported); + return NO_ERROR; +} + +status_t V4LCameraAdapter::insertImageSizes(CameraProperties::Properties* params, V4L_TI_CAPTYPE &caps) { + + char supported[MAX_PROP_VALUE_LENGTH]; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for (int i = 0; i < caps.ulCaptureResCount; i++) { + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat (supported, caps.tCaptureRes[i].param, MAX_PROP_VALUE_LENGTH-1 ); + } + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, supported); + return NO_ERROR; +} + +status_t V4LCameraAdapter::insertFrameRates(CameraProperties::Properties* params, V4L_TI_CAPTYPE &caps) { + + char supported[MAX_PROP_VALUE_LENGTH]; + char temp[MAX_PROP_VALUE_LENGTH]; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + for (int i = 0; i < caps.ulFrameRateCount; i++) { + snprintf (temp, sizeof(temp) - 1, "%d", caps.ulFrameRates[i] ); + if (supported[0] != '\0') { + strncat(supported, PARAM_SEP, 1); + } + strncat (supported, temp, MAX_PROP_VALUE_LENGTH-1 ); + } + + params->set(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES, supported); + + memset(supported, 0, sizeof(supported)); + + for (int i = caps.ulFrameRateCount - 1; i >= 0 ; i--) { + if ( supported[0] ) strncat(supported, PARAM_SEP, 1); + snprintf(temp, sizeof(temp) - 1, "(%d,%d)", caps.ulFrameRates[i] * CameraHal::VFR_SCALE, caps.ulFrameRates[i] * CameraHal::VFR_SCALE); + strcat(supported, temp); + } + + params->set(CameraProperties::FRAMERATE_RANGE_SUPPORTED, supported); + + return NO_ERROR; +} + +status_t V4LCameraAdapter::insertCapabilities(CameraProperties::Properties* params, V4L_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) { + ret = insertPreviewFormats(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertImageSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertPreviewSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFrameRates(params, caps); + } + + //Insert Supported Focus modes. + params->set(CameraProperties::SUPPORTED_FOCUS_MODES, "infinity"); + + params->set(CameraProperties::SUPPORTED_PICTURE_FORMATS, "jpeg"); + + if ( NO_ERROR == ret ) { + ret = insertDefaults(params, caps); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::sortAscend(V4L_TI_CAPTYPE &caps, uint16_t count) { + size_t tempRes; + size_t w, h, tmpW,tmpH; + for (int i=0; i (tmpW * tmpH) ) { + caps.tPreviewRes[j].width = w; + caps.tPreviewRes[j].height = h; + w = tmpW; + h = tmpH; + } + } + caps.tPreviewRes[i].width = w; + caps.tPreviewRes[i].height = h; + + } + return NO_ERROR; +} + +/***************************************** + * public exposed function declarations + *****************************************/ + +status_t V4LCameraAdapter::getCaps(const int sensorId, CameraProperties::Properties* params, + V4L_HANDLETYPE handle) { + status_t status = NO_ERROR; + V4L_TI_CAPTYPE caps; + int i = 0; + int j = 0; + struct v4l2_fmtdesc fmtDesc; + struct v4l2_frmsizeenum frmSizeEnum; + struct v4l2_frmivalenum frmIvalEnum; + + //get supported pixel formats + for ( i = 0; status == NO_ERROR; i++) { + fmtDesc.index = i; + fmtDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + status = ioctl (handle, VIDIOC_ENUM_FMT, &fmtDesc); + if (status == NO_ERROR) { + CAMHAL_LOGDB("fmtDesc[%d].description::pixelformat::flags== (%s::%d::%d)",i, fmtDesc.description,fmtDesc.pixelformat,fmtDesc.flags); + caps.ePreviewFormats[i] = fmtDesc.pixelformat; + } + } + caps.ulPreviewFormatCount = i; + + //get preview sizes & capture image sizes + status = NO_ERROR; + for ( i = 0; status == NO_ERROR; i++) { + frmSizeEnum.index = i; + //Check for frame sizes for default pixel format + //TODO: Check for frame sizes for all supported pixel formats + frmSizeEnum.pixel_format = DEFAULT_PIXEL_FORMAT; + status = ioctl (handle, VIDIOC_ENUM_FRAMESIZES, &frmSizeEnum); + if(frmSizeEnum.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + break; + } + if (status == NO_ERROR) { + CAMHAL_LOGDB("frmSizeEnum.index[%d].width x height == (%d x %d)", i, frmSizeEnum.discrete.width, frmSizeEnum.discrete.height); + caps.tPreviewRes[i].width = frmSizeEnum.discrete.width; + caps.tPreviewRes[i].height = frmSizeEnum.discrete.height; + snprintf(caps.tPreviewRes[i].param, MAX_RES_STRING_LENGTH,"%dx%d",frmSizeEnum.discrete.width,frmSizeEnum.discrete.height); + + caps.tCaptureRes[i].width = frmSizeEnum.discrete.width; + caps.tCaptureRes[i].height = frmSizeEnum.discrete.height; + snprintf(caps.tCaptureRes[i].param, MAX_RES_STRING_LENGTH,"%dx%d",frmSizeEnum.discrete.width,frmSizeEnum.discrete.height); + } + else { + caps.ulCaptureResCount = i; + caps.ulPreviewResCount = i; + } + } + if(frmSizeEnum.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + CAMHAL_LOGDB("\nmin_width x height = %d x %d ",frmSizeEnum.stepwise.min_width, frmSizeEnum.stepwise.min_height); + CAMHAL_LOGDB("\nmax_width x height = %d x %d ",frmSizeEnum.stepwise.max_width, frmSizeEnum.stepwise.max_height); + CAMHAL_LOGDB("\nstep width x height = %d x %d ",frmSizeEnum.stepwise.step_width,frmSizeEnum.stepwise.step_height); + //TODO: populate the sizes when type = V4L2_FRMSIZE_TYPE_STEPWISE + } + + //sort the preview sizes in ascending order + sortAscend(caps, caps.ulPreviewResCount); + + //get supported frame rates + bool fps30 = false; + for ( j=caps.ulPreviewResCount-1; j >= 0; j--) { + CAMHAL_LOGDB(" W x H = %d x %d", caps.tPreviewRes[j].width, caps.tPreviewRes[j].height); + status = NO_ERROR; + for ( i = 0; status == NO_ERROR; i++) { + frmIvalEnum.index = i; + //Check for supported frame rates for the default pixel format. + frmIvalEnum.pixel_format = DEFAULT_PIXEL_FORMAT; + frmIvalEnum.width = caps.tPreviewRes[j].width; + frmIvalEnum.height = caps.tPreviewRes[j].height; + + status = ioctl (handle, VIDIOC_ENUM_FRAMEINTERVALS, &frmIvalEnum); + if(frmIvalEnum.type != V4L2_FRMIVAL_TYPE_DISCRETE) { + break; + } + if (status == NO_ERROR) { + CAMHAL_LOGDB("frmIvalEnum[%d].frame rate= %d)",i, (frmIvalEnum.discrete.denominator/frmIvalEnum.discrete.numerator)); + caps.ulFrameRates[i] = (frmIvalEnum.discrete.denominator/frmIvalEnum.discrete.numerator); + if (caps.ulFrameRates[i] == 30) { + fps30 = true; + } + } + else { + caps.ulFrameRateCount = i; + } + } + if(fps30) { + break; + } + } + + if(frmIvalEnum.type != V4L2_FRMIVAL_TYPE_DISCRETE) { + //TODO: populate the frame rates when type = V4L2_FRMIVAL_TYPE_STEPWISE; + } + + //update the preview resolution with the highest resolution which supports 30fps. +/* // for video preview the application choose the resolution from the mediaprofiles.xml. + // so populating all supported preview resolution is required for video mode. + caps.tPreviewRes[0].width = caps.tPreviewRes[j].width; + caps.tPreviewRes[0].height = caps.tPreviewRes[j].height; + snprintf(caps.tPreviewRes[0].param, MAX_RES_STRING_LENGTH,"%dx%d",caps.tPreviewRes[j].width,caps.tPreviewRes[j].height); + caps.ulPreviewResCount = 1; +*/ + insertCapabilities (params, caps); + return NO_ERROR; +} + + + +} // namespace Camera +} // namespace Ti diff --git a/camera/android-api.mk b/camera/android-api.mk new file mode 100644 index 0000000..da3f56e --- /dev/null +++ b/camera/android-api.mk @@ -0,0 +1,39 @@ + +# Makefile variables and C/C++ macros to recognize API level +ANDROID_API_LP_OR_LATER := +ANDROID_API_KK_OR_LATER := +ANDROID_API_JB_MR1_OR_LATER := +ANDROID_API_JB_OR_LATER := +ANDROID_API_ICS_OR_LATER := +ANDROID_API_CFLAGS := + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 20 || echo 1),) + ANDROID_API_LP_OR_LATER := true + ANDROID_API_CFLAGS += -DANDROID_API_LP_OR_LATER +endif +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 19 || echo 1),) + ANDROID_API_KK_OR_LATER := true + ANDROID_API_CFLAGS += -DANDROID_API_KK_OR_LATER +endif +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 17 || echo 1),) + ANDROID_API_JB_MR1_OR_LATER := true + ANDROID_API_CFLAGS += -DANDROID_API_JB_MR1_OR_LATER +endif +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 16 || echo 1),) + ANDROID_API_JB_OR_LATER := true + ANDROID_API_CFLAGS += -DANDROID_API_JB_OR_LATER +endif +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 14 || echo 1),) + ANDROID_API_ICS_OR_LATER := true + ANDROID_API_CFLAGS += -DANDROID_API_ICS_OR_LATER +endif + +define clear-android-api-vars +$(eval ANDROID_API_LP_OR_LATER:=) \ +$(eval ANDROID_API_KK_OR_LATER:=) \ +$(eval ANDROID_API_JB_MR1_OR_LATER:=) \ +$(eval ANDROID_API_JB_OR_LATER:=) \ +$(eval ANDROID_API_ICS_OR_LATER:=) \ +$(eval ANDROID_API_CFLAGS:=) \ +$(eval clear-android-api-vars:=) +endef diff --git a/camera/inc/ANativeWindowDisplayAdapter.h b/camera/inc/ANativeWindowDisplayAdapter.h new file mode 100644 index 0000000..eba91bb --- /dev/null +++ b/camera/inc/ANativeWindowDisplayAdapter.h @@ -0,0 +1,196 @@ +/* + * 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 "CameraHal.h" +#include +#include + +namespace Ti { +namespace Camera { + +/** + * Display handler class - This class basically handles the buffer posting to display + */ + +class ANativeWindowDisplayAdapter : public DisplayAdapter +{ +public: + + typedef struct + { + CameraBuffer *mBuffer; + void *mUser; + int mOffset; + int mWidth; + int mHeight; + int mWidthStride; + int mHeightStride; + int mLength; + CameraFrame::FrameType mType; + } DisplayFrame; + + enum DisplayStates + { + DISPLAY_INIT = 0, + DISPLAY_STARTED, + DISPLAY_STOPPED, + DISPLAY_EXITED + }; + +public: + + ANativeWindowDisplayAdapter(); + virtual ~ANativeWindowDisplayAdapter(); + + ///Initializes the display adapter creates any resources required + virtual status_t initialize(); + + virtual int setPreviewWindow(struct preview_stream_ops *window); + virtual int setFrameProvider(FrameNotifier *frameProvider); + virtual int setErrorHandler(ErrorNotifier *errorNotifier); + virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL); + virtual int disableDisplay(bool cancel_buffer = true); + virtual status_t pauseDisplay(bool pause); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Used for shot to snapshot measurement + virtual status_t setSnapshotTimeRef(struct timeval *refTime = NULL); + +#endif + + virtual bool supportsExternalBuffering(); + + //Implementation of inherited interfaces + virtual CameraBuffer * allocateBufferList(int width, int height, const char* format, int &bytes, int numBufs); + virtual CameraBuffer *getBufferList(int *numBufs); + virtual uint32_t * getOffsets() ; + virtual int getFd() ; + virtual int freeBufferList(CameraBuffer * buflist); + + virtual status_t maxQueueableBuffers(unsigned int& queueable); + virtual status_t minUndequeueableBuffers(int& unqueueable); + + // If set to true ANativeWindowDisplayAdapter will not lock/unlock graphic buffers + void setExternalLocking(bool extBuffLocking); + + ///Class specific functions + static void frameCallbackRelay(CameraFrame* caFrame); + void frameCallback(CameraFrame* caFrame); + + void displayThread(); + + private: + void destroy(); + bool processHalMsg(); + status_t PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame); + bool handleFrameReturn(); + status_t returnBuffersToWindow(); + +public: + + static const int DISPLAY_TIMEOUT; + static const int FAILED_DQS_TO_SUSPEND; + + class DisplayThread : public android::Thread + { + ANativeWindowDisplayAdapter* mDisplayAdapter; + Utils::MessageQueue mDisplayThreadQ; + + public: + DisplayThread(ANativeWindowDisplayAdapter* da) + : Thread(false), mDisplayAdapter(da) { } + + ///Returns a reference to the display message Q for display adapter to post messages + Utils::MessageQueue& msgQ() + { + return mDisplayThreadQ; + } + + virtual bool threadLoop() + { + mDisplayAdapter->displayThread(); + return false; + } + + enum DisplayThreadCommands + { + DISPLAY_START, + DISPLAY_STOP, + DISPLAY_FRAME, + DISPLAY_EXIT + }; + }; + + //friend declarations +friend class DisplayThread; + +private: + int postBuffer(void* displayBuf); + +private: + bool mFirstInit; + bool mSuspend; + int mFailedDQs; + bool mPaused; //Pause state + preview_stream_ops_t* mANativeWindow; + android::sp mDisplayThread; + FrameProvider *mFrameProvider; ///Pointer to the frame provider interface + Utils::MessageQueue mDisplayQ; + unsigned int mDisplayState; + ///@todo Have a common class for these members + mutable android::Mutex mLock; + bool mDisplayEnabled; + int mBufferCount; + CameraBuffer *mBuffers; + //buffer_handle_t** mBufferHandleMap; // -> frames[i].BufferHandle + //IMG_native_handle_t** mGrallocHandleMap; // -> frames[i].GrallocHandle + uint32_t* mOffsetsMap; // -> frames[i].Offset + int mFD; + android::KeyedVector mFramesWithCameraAdapterMap; + android::KeyedVector mFramesType; + android::sp mErrorNotifier; + + uint32_t mFrameWidth; + uint32_t mFrameHeight; + uint32_t mPreviewWidth; + uint32_t mPreviewHeight; + + uint32_t mXOff; + uint32_t mYOff; + + const char *mPixelFormat; + + //In case if we ,as example, using out buffers in Ducati Decoder + //DOMX will handle lock/unlock of graphic buffers + bool mUseExternalBufferLocking; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + //Used for calculating standby to first shot + struct timeval mStandbyToShot; + bool mMeasureStandby; + //Used for shot to snapshot/shot calculation + struct timeval mStartCapture; + bool mShotToShot; + +#endif + +}; + +} // namespace Camera +} // namespace Ti diff --git a/camera/inc/BaseCameraAdapter.h b/camera/inc/BaseCameraAdapter.h new file mode 100644 index 0000000..ffe0492 --- /dev/null +++ b/camera/inc/BaseCameraAdapter.h @@ -0,0 +1,308 @@ +/* + * 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. + */ + + + +#ifndef BASE_CAMERA_ADAPTER_H +#define BASE_CAMERA_ADAPTER_H + +#include "CameraHal.h" + +namespace Ti { +namespace Camera { + +struct LUT { + const char * userDefinition; + int halDefinition; +}; + +struct LUTtypeHAL{ + int size; + const LUT *Table; +}; + +class BaseCameraAdapter : public CameraAdapter +{ + +public: + + BaseCameraAdapter(); + virtual ~BaseCameraAdapter(); + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*) = 0; + + virtual int setErrorHandler(ErrorNotifier *errorNotifier); + + //Message/Frame notification APIs + virtual void enableMsgType(int32_t msgs, frame_callback callback=NULL, event_callback eventCb=NULL, void* cookie=NULL); + virtual void disableMsgType(int32_t msgs, void* cookie); + virtual void returnFrame(CameraBuffer * frameBuf, CameraFrame::FrameType frameType); + virtual void addFramePointers(CameraBuffer *frameBuf, void *y_uv); + virtual void removeFramePointers(); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const android::CameraParameters& params) = 0; + virtual void getParameters(android::CameraParameters& params) = 0; + + //API to send a command to the camera + virtual status_t sendCommand(CameraCommands operation, int value1 = 0, int value2 = 0, int value3 = 0, int value4 = 0 ); + + virtual status_t registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data); + + virtual status_t registerEndCaptureCallback(end_image_capture_callback callback, void *user_data); + + //Retrieves the current Adapter state + virtual AdapterState getState(); + //Retrieves the next Adapter state + virtual AdapterState getNextState(); + + virtual status_t setSharedAllocator(camera_request_memory shmem_alloc) { mSharedAllocator = shmem_alloc; return NO_ERROR; }; + + // Rolls the state machine back to INTIALIZED_STATE from the current state + virtual status_t rollbackToInitializedState(); + +protected: + //The first two methods will try to switch the adapter state. + //Every call to setState() should be followed by a corresponding + //call to commitState(). If the state switch fails, then it will + //get reset to the previous state via rollbackState(). + virtual status_t setState(CameraCommands operation); + virtual status_t commitState(); + virtual status_t rollbackState(); + + // Retrieves the current Adapter state - for internal use (not locked) + virtual status_t getState(AdapterState &state); + // Retrieves the next Adapter state - for internal use (not locked) + virtual status_t getNextState(AdapterState &state); + + //-----------Interface that needs to be implemented by deriving classes -------------------- + + //Should be implmented by deriving classes in order to start image capture + virtual status_t takePicture(); + + //Should be implmented by deriving classes in order to start image capture + virtual status_t stopImageCapture(); + + //Should be implmented by deriving classes in order to start temporal bracketing + virtual status_t startBracketing(int range); + + //Should be implemented by deriving classes in order to stop temporal bracketing + virtual status_t stopBracketing(); + + //Should be implemented by deriving classes in oder to initiate autoFocus + virtual status_t autoFocus(); + + //Should be implemented by deriving classes in oder to initiate autoFocus + virtual status_t cancelAutoFocus(); + + //Should be called by deriving classes in order to do some bookkeeping + virtual status_t startVideoCapture(); + + //Should be called by deriving classes in order to do some bookkeeping + virtual status_t stopVideoCapture(); + + //Should be implemented by deriving classes in order to start camera preview + virtual status_t startPreview(); + + //Should be implemented by deriving classes in order to stop camera preview + virtual status_t stopPreview(); + + //Should be implemented by deriving classes in order to start smooth zoom + virtual status_t startSmoothZoom(int targetIdx); + + //Should be implemented by deriving classes in order to stop smooth zoom + virtual status_t stopSmoothZoom(); + + //Should be implemented by deriving classes in order to stop smooth zoom + virtual status_t useBuffers(CameraMode mode, CameraBuffer* bufArr, int num, size_t length, unsigned int queueable); + + //Should be implemented by deriving classes in order queue a released buffer in CameraAdapter + virtual status_t fillThisBuffer(CameraBuffer* frameBuf, CameraFrame::FrameType frameType); + + //API to get the frame size required to be allocated. This size is used to override the size passed + //by camera service when VSTAB/VNF is turned ON for example + virtual status_t getFrameSize(size_t &width, size_t &height); + + //API to get required data frame size + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + + //API to get required picture buffers size with the current configuration in CameraParameters + virtual status_t getPictureBufferSize(CameraFrame &frame, size_t bufferCount); + + // Should be implemented by deriving classes in order to start face detection + // ( if supported ) + virtual status_t startFaceDetection(); + + // Should be implemented by deriving classes in order to stop face detection + // ( if supported ) + virtual status_t stopFaceDetection(); + + virtual status_t switchToExecuting(); + + virtual status_t setupTunnel(uint32_t SliceHeight, uint32_t EncoderHandle, uint32_t width, uint32_t height); + + virtual status_t destroyTunnel(); + + virtual status_t cameraPreviewInitialization(); + + // Receive orientation events from CameraHal + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); + + // ---------------------Interface ends----------------------------------- + + status_t notifyFocusSubscribers(CameraHalEvent::FocusStatus status); + status_t notifyShutterSubscribers(); + status_t notifyZoomSubscribers(int zoomIdx, bool targetReached); + status_t notifyMetadataSubscribers(android::sp &meta); + + //Send the frame to subscribers + status_t sendFrameToSubscribers(CameraFrame *frame); + + //Resets the refCount for this particular frame + status_t resetFrameRefCount(CameraFrame &frame); + + //A couple of helper functions + void setFrameRefCountByType(CameraBuffer* frameBuf, CameraFrame::FrameType frameType, int refCount); + int getFrameRefCount(CameraBuffer* frameBuf); + int getFrameRefCountByType(CameraBuffer* frameBuf, CameraFrame::FrameType frameType); + int setInitFrameRefCount(CameraBuffer* buf, unsigned int mask); + static const char* getLUTvalue_translateHAL(int Value, LUTtypeHAL LUT); + +// private member functions +private: + status_t __sendFrameToSubscribers(CameraFrame* frame, + android::KeyedVector *subscribers, + CameraFrame::FrameType frameType); + status_t rollbackToPreviousState(); + +// protected data types and variables +protected: + enum FrameState { + STOPPED = 0, + RUNNING + }; + + enum FrameCommands { + START_PREVIEW = 0, + START_RECORDING, + RETURN_FRAME, + STOP_PREVIEW, + STOP_RECORDING, + DO_AUTOFOCUS, + TAKE_PICTURE, + FRAME_EXIT + }; + + enum AdapterCommands { + ACK = 0, + ERROR + }; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + struct timeval mStartFocus; + struct timeval mStartCapture; + +#endif + + mutable android::Mutex mReturnFrameLock; + + //Lock protecting the Adapter state + mutable android::Mutex mLock; + AdapterState mAdapterState; + AdapterState mNextState; + + //Different frame subscribers get stored using these + android::KeyedVector mFrameSubscribers; + android::KeyedVector mSnapshotSubscribers; + android::KeyedVector mFrameDataSubscribers; + android::KeyedVector mVideoSubscribers; + android::KeyedVector mVideoInSubscribers; + android::KeyedVector mImageSubscribers; + android::KeyedVector mRawSubscribers; + android::KeyedVector mFocusSubscribers; + android::KeyedVector mZoomSubscribers; + android::KeyedVector mShutterSubscribers; + android::KeyedVector mMetadataSubscribers; + + //Preview buffer management data + CameraBuffer *mPreviewBuffers; + int mPreviewBufferCount; + size_t mPreviewBuffersLength; + android::KeyedVector mPreviewBuffersAvailable; + mutable android::Mutex mPreviewBufferLock; + + //Snapshot buffer management data + android::KeyedVector mSnapshotBuffersAvailable; + mutable android::Mutex mSnapshotBufferLock; + + //Video buffer management data + CameraBuffer *mVideoBuffers; + android::KeyedVector mVideoBuffersAvailable; + int mVideoBuffersCount; + size_t mVideoBuffersLength; + mutable android::Mutex mVideoBufferLock; + + //Image buffer management data + CameraBuffer *mCaptureBuffers; + android::KeyedVector mCaptureBuffersAvailable; + int mCaptureBuffersCount; + size_t mCaptureBuffersLength; + mutable android::Mutex mCaptureBufferLock; + + //Metadata buffermanagement + CameraBuffer *mPreviewDataBuffers; + android::KeyedVector mPreviewDataBuffersAvailable; + int mPreviewDataBuffersCount; + size_t mPreviewDataBuffersLength; + mutable android::Mutex mPreviewDataBufferLock; + + //Video input buffer management data (used for reproc pipe) + CameraBuffer *mVideoInBuffers; + android::KeyedVector mVideoInBuffersAvailable; + mutable android::Mutex mVideoInBufferLock; + + Utils::MessageQueue mFrameQ; + Utils::MessageQueue mAdapterQ; + mutable android::Mutex mSubscriberLock; + ErrorNotifier *mErrorNotifier; + release_image_buffers_callback mReleaseImageBuffersCallback; + end_image_capture_callback mEndImageCaptureCallback; + void *mReleaseData; + void *mEndCaptureData; + bool mRecording; + + camera_request_memory mSharedAllocator; + + uint32_t mFramesWithDucati; + uint32_t mFramesWithDisplay; + uint32_t mFramesWithEncoder; + +#ifdef CAMERAHAL_DEBUG + android::Mutex mBuffersWithDucatiLock; + android::KeyedVector mBuffersWithDucati; +#endif + + android::KeyedVector mFrameQueue; +}; + +} // namespace Camera +} // namespace Ti + +#endif //BASE_CAMERA_ADAPTER_H + + diff --git a/camera/inc/BufferSourceAdapter.h b/camera/inc/BufferSourceAdapter.h new file mode 100644 index 0000000..c006b9d --- /dev/null +++ b/camera/inc/BufferSourceAdapter.h @@ -0,0 +1,228 @@ +/* + * 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. + */ + +#ifndef BUFFER_SOURCE_ADAPTER_H +#define BUFFER_SOURCE_ADAPTER_H + +#ifdef OMAP_ENHANCEMENT_CPCAM + +#include "CameraHal.h" +#include +#include + +namespace Ti { +namespace Camera { + +/** + * Handles enqueueing/dequeing buffers to tap-in/tap-out points + * TODO(XXX): this class implements DisplayAdapter for now + * but this will most likely change once tap-in/tap-out points + * are better defined + */ + +class BufferSourceAdapter : public DisplayAdapter +{ +// private types +private: + ///Constant declarations + static const int NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP; + + + // helper class to return frame in different thread context + class ReturnFrame : public android::Thread { + public: + ReturnFrame(BufferSourceAdapter* __this) : mBufferSourceAdapter(__this) { + android::AutoMutex lock(mReturnFrameMutex); + mDestroying = false; + mFrameCount = 0; + } + + ~ReturnFrame() { + android::AutoMutex lock(mReturnFrameMutex); + } + + void signal() { + android::AutoMutex lock(mReturnFrameMutex); + mFrameCount++; + mReturnFrameCondition.signal(); + } + + virtual void requestExit() { + Thread::requestExit(); + + android::AutoMutex lock(mReturnFrameMutex); + mDestroying = true; + mReturnFrameCondition.signal(); + } + + virtual bool threadLoop() { + android::AutoMutex lock(mReturnFrameMutex); + if ( 0 >= mFrameCount ) { + mReturnFrameCondition.wait(mReturnFrameMutex); + } + if (!mDestroying) { + mBufferSourceAdapter->handleFrameReturn(); + mFrameCount--; + } + return true; + } + + private: + BufferSourceAdapter* mBufferSourceAdapter; + android::Condition mReturnFrameCondition; + android::Mutex mReturnFrameMutex; + int mFrameCount; + bool mDestroying; + }; + + // helper class to queue frame in different thread context + class QueueFrame : public android::Thread { + public: + QueueFrame(BufferSourceAdapter* __this) : mBufferSourceAdapter(__this) { + mDestroying = false; + } + + ~QueueFrame() { + } + + void addFrame(CameraFrame *frame) { + android::AutoMutex lock(mFramesMutex); + mFrames.add(new CameraFrame(*frame)); + mFramesCondition.signal(); + } + + virtual void requestExit() { + Thread::requestExit(); + + mDestroying = true; + + android::AutoMutex lock(mFramesMutex); + while (!mFrames.empty()) { + CameraFrame *frame = mFrames.itemAt(0); + mFrames.removeAt(0); + frame->mMetaData.clear(); + delete frame; + } + mFramesCondition.signal(); + } + + virtual bool threadLoop() { + CameraFrame *frame = NULL; + { + android::AutoMutex lock(mFramesMutex); + while (mFrames.empty() && !mDestroying) mFramesCondition.wait(mFramesMutex); + if (!mDestroying) { + frame = mFrames.itemAt(0); + mFrames.removeAt(0); + } + } + + if (frame) { + mBufferSourceAdapter->handleFrameCallback(frame); + frame->mMetaData.clear(); + + if (frame->mFrameType != CameraFrame::REPROCESS_INPUT_FRAME) { + // signal return frame thread that it can dequeue a buffer now + mBufferSourceAdapter->mReturnFrame->signal(); + } + + delete frame; + } + + return true; + } + + private: + BufferSourceAdapter* mBufferSourceAdapter; + android::Vector mFrames; + android::Condition mFramesCondition; + android::Mutex mFramesMutex; + bool mDestroying; + }; + + enum { + BUFFER_SOURCE_TAP_IN, + BUFFER_SOURCE_TAP_OUT + }; + +// public member functions +public: + BufferSourceAdapter(); + virtual ~BufferSourceAdapter(); + + virtual status_t initialize(); + virtual int setPreviewWindow(struct preview_stream_ops *source); + virtual int setFrameProvider(FrameNotifier *frameProvider); + virtual int setErrorHandler(ErrorNotifier *errorNotifier); + virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL); + virtual int disableDisplay(bool cancel_buffer = true); + virtual status_t pauseDisplay(bool pause); +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + // Not implemented in this class + virtual status_t setSnapshotTimeRef(struct timeval *refTime = NULL) { return NO_ERROR; } +#endif + virtual bool supportsExternalBuffering(); + virtual CameraBuffer * allocateBufferList(int width, int dummyHeight, const char* format, int &bytes, int numBufs); + virtual CameraBuffer *getBufferList(int *numBufs); + virtual uint32_t * getOffsets() ; + virtual int getFd() ; + virtual int freeBufferList(CameraBuffer * buflist); + virtual int maxQueueableBuffers(unsigned int& queueable); + virtual int minUndequeueableBuffers(int& unqueueable); + virtual bool match(const char * str); + + virtual CameraBuffer * getBuffers(bool reset = false); + virtual unsigned int getSize(); + virtual int getBufferCount(); + + static void frameCallback(CameraFrame* caFrame); + void addFrame(CameraFrame* caFrame); + void handleFrameCallback(CameraFrame* caFrame); + bool handleFrameReturn(); + +private: + void destroy(); + status_t returnBuffersToWindow(); + +private: + preview_stream_ops_t* mBufferSource; + FrameProvider *mFrameProvider; // Pointer to the frame provider interface + + mutable android::Mutex mLock; + int mBufferCount; + CameraBuffer *mBuffers; + + android::KeyedVector mFramesWithCameraAdapterMap; + android::sp mErrorNotifier; + android::sp mReturnFrame; + android::sp mQueueFrame; + + uint32_t mFrameWidth; + uint32_t mFrameHeight; + uint32_t mPreviewWidth; + uint32_t mPreviewHeight; + + int mBufferSourceDirection; + + const char *mPixelFormat; +}; + +} // namespace Camera +} // namespace Ti + +#endif + +#endif diff --git a/camera/inc/CameraHal.h b/camera/inc/CameraHal.h new file mode 100644 index 0000000..b6d19b7 --- /dev/null +++ b/camera/inc/CameraHal.h @@ -0,0 +1,1562 @@ +/* + * 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. + */ + + + +#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_H +#define ANDROID_HARDWARE_CAMERA_HARDWARE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef OMAP_ENHANCEMENT_CPCAM +#include +#include +#endif +#include +#include + +/* For IMG_native_handle_t */ +#include +#include + +#ifdef USE_LIBION_TI +#include +#else +#include +#endif + +#include "Common.h" +#include "MessageQueue.h" +#include "Semaphore.h" +#include "CameraProperties.h" +#include "SensorListener.h" + +//temporarily define format here +#define HAL_PIXEL_FORMAT_TI_NV12 0x100 +#define HAL_PIXEL_FORMAT_TI_Y8 0x103 +#define HAL_PIXEL_FORMAT_TI_Y16 0x104 +#define HAL_PIXEL_FORMAT_TI_UYVY 0x105 + +#define MIN_WIDTH 640 +#define MIN_HEIGHT 480 +#define PICTURE_WIDTH 3264 /* 5mp - 2560. 8mp - 3280 */ /* Make sure it is a multiple of 16. */ +#define PICTURE_HEIGHT 2448 /* 5mp - 2048. 8mp - 2464 */ /* Make sure it is a multiple of 16. */ +#define PREVIEW_WIDTH 176 +#define PREVIEW_HEIGHT 144 +#define PIXEL_FORMAT V4L2_PIX_FMT_UYVY + +#define VIDEO_FRAME_COUNT_MAX 8 //NUM_OVERLAY_BUFFERS_REQUESTED +#define MAX_CAMERA_BUFFERS 8 //NUM_OVERLAY_BUFFERS_REQUESTED +#define MAX_ZOOM 3 +#define THUMB_WIDTH 80 +#define THUMB_HEIGHT 60 +#define PIX_YUV422I 0 +#define PIX_YUV420P 1 + +#define SATURATION_OFFSET 100 +#define SHARPNESS_OFFSET 100 +#define CONTRAST_OFFSET 100 + +#ifdef MOTOROLA_CAMERA +#define DEFAULT_INTENSITY 100 +#define FLASH_VOLTAGE_THRESHOLD1 3700000 // intensity will be reduced to 50% below threshold1 +#define FLASH_VOLTAGE_THRESHOLD2 3300000 // flash disabled below threshold2 +#endif + +#define FRAME_RATE_HIGH_HD 60 + +#define CAMHAL_GRALLOC_USAGE GRALLOC_USAGE_HW_TEXTURE | \ + GRALLOC_USAGE_HW_RENDER | \ + GRALLOC_USAGE_SW_READ_RARELY | \ + GRALLOC_USAGE_SW_WRITE_NEVER + +//Enables Absolute PPM measurements in logcat +#define PPM_INSTRUMENTATION_ABS 1 + +#define LOCK_BUFFER_TRIES 5 +#define HAL_PIXEL_FORMAT_NV12 0x100 + +#define OP_STR_SIZE 100 + +#define NONNEG_ASSIGN(x,y) \ + if(x > -1) \ + y = x + +#define CAMHAL_SIZE_OF_ARRAY(x) static_cast(sizeof(x)/sizeof(x[0])) + +namespace Ti { +namespace Camera { + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING +extern const char * const kRawImagesOutputDirPath; +extern const char * const kYuvImagesOutputDirPath; +#endif +#define V4L_CAMERA_NAME_USB "USBCAMERA" +#define OMX_CAMERA_NAME_OV "OV5640" +#define OMX_CAMERA_NAME_SONY "IMX060" +#ifdef MOTOROLA_CAMERA +#define OMX_CAMERA_NAME_OV8820 "OV8820" +#define OMX_CAMERA_NAME_OV7739 "OV7739" +#define OMX_CAMERA_NAME_MT9M114 "MT9M114" +#endif + + +///Forward declarations +class CameraHal; +class CameraFrame; +class CameraHalEvent; +class DisplayFrame; + +class FpsRange { +public: + static int compare(const FpsRange * left, const FpsRange * right); + + FpsRange(int min, int max); + FpsRange(); + + bool operator==(const FpsRange & fpsRange) const; + + bool isNull() const; + bool isFixed() const; + + int min() const; + int max() const; + +private: + int mMin; + int mMax; +}; + + +inline int FpsRange::compare(const FpsRange * const left, const FpsRange * const right) { + if ( left->max() < right->max() ) { + return -1; + } + + if ( left->max() > right->max() ) { + return 1; + } + + if ( left->min() < right->min() ) { + return -1; + } + + if ( left->min() > right->min() ) { + return 1; + } + + return 0; +} + +inline FpsRange::FpsRange(const int min, const int max) : mMin(min), mMax(max) {} + +inline FpsRange::FpsRange() : mMin(-1), mMax(-1) {} + +inline bool FpsRange::operator==(const FpsRange & fpsRange) const { + return mMin == fpsRange.mMin && mMax == fpsRange.mMax; +} + +inline bool FpsRange::isNull() const { + return mMin == -1 || mMax == -1; +} + +inline bool FpsRange::isFixed() const { + return mMin == mMax; +} + +inline int FpsRange::min() const { return mMin; } + +inline int FpsRange::max() const { return mMax; } + +class CameraArea : public android::RefBase +{ +public: + + CameraArea(ssize_t top, + ssize_t left, + ssize_t bottom, + ssize_t right, + size_t weight) : mTop(top), + mLeft(left), + mBottom(bottom), + mRight(right), + mWeight(weight) {} + + status_t transfrom(size_t width, + size_t height, + size_t &top, + size_t &left, + size_t &areaWidth, + size_t &areaHeight); + + bool isValid() + { + return ( ( 0 != mTop ) || ( 0 != mLeft ) || ( 0 != mBottom ) || ( 0 != mRight) ); + } + + bool isZeroArea() + { + return ( (0 == mTop ) && ( 0 == mLeft ) && ( 0 == mBottom ) + && ( 0 == mRight ) && ( 0 == mWeight )); + } + + size_t getWeight() + { + return mWeight; + } + + bool compare(const android::sp &area); + + static status_t parseAreas(const char *area, + size_t areaLength, + android::Vector< android::sp > &areas); + + static status_t checkArea(ssize_t top, + ssize_t left, + ssize_t bottom, + ssize_t right, + ssize_t weight); + + static bool areAreasDifferent(android::Vector< android::sp > &, android::Vector< android::sp > &); + +protected: + static const ssize_t TOP = -1000; + static const ssize_t LEFT = -1000; + static const ssize_t BOTTOM = 1000; + static const ssize_t RIGHT = 1000; + static const ssize_t WEIGHT_MIN = 1; + static const ssize_t WEIGHT_MAX = 1000; + + ssize_t mTop; + ssize_t mLeft; + ssize_t mBottom; + ssize_t mRight; + size_t mWeight; +}; + +class CameraMetadataResult : public android::RefBase +{ +public: + +#ifdef OMAP_ENHANCEMENT_CPCAM + CameraMetadataResult(camera_memory_t * extMeta) : mExtendedMetadata(extMeta) { + mMetadata.faces = NULL; + mMetadata.number_of_faces = 0; +#ifdef OMAP_ENHANCEMENT + mMetadata.analog_gain = 0; + mMetadata.exposure_time = 0; +#endif + }; +#endif + + CameraMetadataResult() { + mMetadata.faces = NULL; + mMetadata.number_of_faces = 0; +#ifdef OMAP_ENHANCEMENT_CPCAM + mMetadata.analog_gain = 0; + mMetadata.exposure_time = 0; +#endif + +#ifdef OMAP_ENHANCEMENT_CPCAM + mExtendedMetadata = NULL; +#endif + } + + virtual ~CameraMetadataResult() { + if ( NULL != mMetadata.faces ) { + free(mMetadata.faces); + } +#ifdef OMAP_ENHANCEMENT_CPCAM + if ( NULL != mExtendedMetadata ) { + mExtendedMetadata->release(mExtendedMetadata); + } +#endif + } + + camera_frame_metadata_t *getMetadataResult() { return &mMetadata; }; + +#ifdef OMAP_ENHANCEMENT_CPCAM + camera_memory_t *getExtendedMetadata() { return mExtendedMetadata; }; +#endif + + static const ssize_t TOP = -1000; + static const ssize_t LEFT = -1000; + static const ssize_t BOTTOM = 1000; + static const ssize_t RIGHT = 1000; + static const ssize_t INVALID_DATA = -2000; + +private: + + camera_frame_metadata_t mMetadata; +#ifdef OMAP_ENHANCEMENT_CPCAM + camera_memory_t *mExtendedMetadata; +#endif +}; + +typedef enum { + CAMERA_BUFFER_NONE = 0, + CAMERA_BUFFER_GRALLOC, + CAMERA_BUFFER_ANW, + CAMERA_BUFFER_MEMORY, + CAMERA_BUFFER_ION +} CameraBufferType; + +typedef struct _CameraBuffer { + CameraBufferType type; + /* opaque is the generic drop-in replacement for the pointers + * that were used previously */ + void *opaque; + + /* opaque has different meanings depending on the buffer type: + * GRALLOC - gralloc_handle_t + * ANW - a pointer to the buffer_handle_t (which corresponds to + * the ANativeWindowBuffer *) + * MEMORY - address of allocated memory + * ION - address of mapped ion allocation + * + * FIXME opaque should be split into several fields: + * - handle/pointer we got from the allocator + * - handle/value we pass to OMX + * - pointer to mapped memory (if the buffer is mapped) + */ + + /* mapped holds ptr to mapped memory in userspace */ + void *mapped; + + /* These are specific to ION buffers */ + struct ion_handle * ion_handle; + int ion_fd; + int fd; + size_t size; + int index; + + /* These describe the camera buffer */ + int width; + int stride; + int height; + const char *format; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + struct timeval ppmStamp; + +#endif + + /* These are for buffers which include borders */ + int offset; // where valid data starts + int actual_size; // size of the entire buffer with borders + int privateData; +} CameraBuffer; + +void * camera_buffer_get_omx_ptr (CameraBuffer *buffer); + +class CameraFrame +{ + public: + + enum FrameType + { + PREVIEW_FRAME_SYNC = 0x1, ///SYNC implies that the frame needs to be explicitly returned after consuming in order to be filled by camera again + PREVIEW_FRAME = 0x2 , ///Preview frame includes viewfinder and snapshot frames + IMAGE_FRAME_SYNC = 0x4, ///Image Frame is the image capture output frame + IMAGE_FRAME = 0x8, + VIDEO_FRAME_SYNC = 0x10, ///Timestamp will be updated for these frames + VIDEO_FRAME = 0x20, + FRAME_DATA_SYNC = 0x40, ///Any extra data assosicated with the frame. Always synced with the frame + FRAME_DATA= 0x80, + RAW_FRAME = 0x100, + SNAPSHOT_FRAME = 0x200, + REPROCESS_INPUT_FRAME = 0x400, + ALL_FRAMES = 0xFFFF ///Maximum of 16 frame types supported + }; + + enum FrameQuirks + { + ENCODE_RAW_YUV422I_TO_JPEG = 0x1 << 0, + HAS_EXIF_DATA = 0x1 << 1, + FORMAT_YUV422I_YUYV = 0x1 << 2, + FORMAT_YUV422I_UYVY = 0x1 << 3, + }; + + //default contrustor + CameraFrame(): + mCookie(NULL), + mCookie2(NULL), + mBuffer(NULL), + mFrameType(0), + mTimestamp(0), + mWidth(0), + mHeight(0), + mOffset(0), + mAlignment(0), + mFd(0), + mLength(0), + mFrameMask(0), + mQuirks(0) + { + mYuv[0] = 0; // NULL is meant for pointers + mYuv[1] = 0; // NULL is meant for pointers + +#ifdef OMAP_ENHANCEMENT_CPCAM + mMetaData = 0; +#endif + } + + void *mCookie; + void *mCookie2; + CameraBuffer *mBuffer; + int mFrameType; + nsecs_t mTimestamp; + unsigned int mWidth, mHeight; + uint32_t mOffset; + unsigned int mAlignment; + int mFd; + size_t mLength; + unsigned mFrameMask; + unsigned int mQuirks; + unsigned int mYuv[2]; +#ifdef OMAP_ENHANCEMENT_CPCAM + android::sp mMetaData; +#endif + ///@todo add other member vars like stride etc +}; + +enum CameraHalError +{ + CAMERA_ERROR_FATAL = 0x1, //Fatal errors can only be recovered by restarting media server + CAMERA_ERROR_HARD = 0x2, // Hard errors are hardware hangs that may be recoverable by resetting the hardware internally within the adapter + CAMERA_ERROR_SOFT = 0x4, // Soft errors are non fatal errors that can be recovered from without needing to stop use-case +}; + +///Common Camera Hal Event class which is visible to CameraAdapter,DisplayAdapter and AppCallbackNotifier +///@todo Rename this class to CameraEvent +class CameraHalEvent +{ +public: + //Enums + enum CameraHalEventType { + NO_EVENTS = 0x0, + EVENT_FOCUS_LOCKED = 0x1, + EVENT_FOCUS_ERROR = 0x2, + EVENT_ZOOM_INDEX_REACHED = 0x4, + EVENT_SHUTTER = 0x8, + EVENT_METADATA = 0x10, + ///@remarks Future enum related to display, like frame displayed event, could be added here + ALL_EVENTS = 0xFFFF ///Maximum of 16 event types supported + }; + + enum FocusStatus { + FOCUS_STATUS_SUCCESS = 0x1, + FOCUS_STATUS_FAIL = 0x2, + FOCUS_STATUS_PENDING = 0x4, + FOCUS_STATUS_DONE = 0x8, + }; + + ///Class declarations + ///@remarks Add a new class for a new event type added above + + //Shutter event specific data + typedef struct ShutterEventData_t { + bool shutterClosed; + }ShutterEventData; + + ///Focus event specific data + typedef struct FocusEventData_t { + FocusStatus focusStatus; + int currentFocusValue; + } FocusEventData; + + ///Zoom specific event data + typedef struct ZoomEventData_t { + int currentZoomIndex; + bool targetZoomIndexReached; + } ZoomEventData; + + typedef struct FaceData_t { + ssize_t top; + ssize_t left; + ssize_t bottom; + ssize_t right; + size_t score; + } FaceData; + + typedef android::sp MetaEventData; + + class CameraHalEventData : public android::RefBase{ + + public: + + CameraHalEvent::FocusEventData focusEvent; + CameraHalEvent::ZoomEventData zoomEvent; + CameraHalEvent::ShutterEventData shutterEvent; + CameraHalEvent::MetaEventData metadataEvent; + }; + + //default contrustor + CameraHalEvent(): + mCookie(NULL), + mEventType(NO_EVENTS) {} + + //copy constructor + CameraHalEvent(const CameraHalEvent &event) : + mCookie(event.mCookie), + mEventType(event.mEventType), + mEventData(event.mEventData) {}; + + void* mCookie; + CameraHalEventType mEventType; + android::sp mEventData; + +}; + +/// Have a generic callback class based on template - to adapt CameraFrame and Event +typedef void (*frame_callback) (CameraFrame *cameraFrame); +typedef void (*event_callback) (CameraHalEvent *event); + +//signals CameraHAL to relase image buffers +typedef void (*release_image_buffers_callback) (void *userData); +typedef void (*end_image_capture_callback) (void *userData); + +/** + * Interface class implemented by classes that have some events to communicate to dependendent classes + * Dependent classes use this interface for registering for events + */ +class MessageNotifier +{ +public: + static const uint32_t EVENT_BIT_FIELD_POSITION; + static const uint32_t FRAME_BIT_FIELD_POSITION; + + ///@remarks Msg type comes from CameraFrame and CameraHalEvent classes + /// MSB 16 bits is for events and LSB 16 bits is for frame notifications + /// FrameProvider and EventProvider classes act as helpers to event/frame + /// consumers to call this api + virtual void enableMsgType(int32_t msgs, frame_callback frameCb=NULL, event_callback eventCb=NULL, void* cookie=NULL) = 0; + virtual void disableMsgType(int32_t msgs, void* cookie) = 0; + + virtual ~MessageNotifier() {}; +}; + +class ErrorNotifier : public virtual android::RefBase +{ +public: + virtual void errorNotify(int error) = 0; + + virtual ~ErrorNotifier() {}; +}; + + +/** + * Interace class abstraction for Camera Adapter to act as a frame provider + * This interface is fully implemented by Camera Adapter + */ +class FrameNotifier : public MessageNotifier +{ +public: + virtual void returnFrame(CameraBuffer* frameBuf, CameraFrame::FrameType frameType) = 0; + virtual void addFramePointers(CameraBuffer *frameBuf, void *buf) = 0; + virtual void removeFramePointers() = 0; + + virtual ~FrameNotifier() {}; +}; + +/** * Wrapper class around Frame Notifier, which is used by display and notification classes for interacting with Camera Adapter + */ +class FrameProvider +{ + FrameNotifier* mFrameNotifier; + void* mCookie; + frame_callback mFrameCallback; + +public: + FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback) + :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { } + + int enableFrameNotification(int32_t frameTypes); + int disableFrameNotification(int32_t frameTypes); + int returnFrame(CameraBuffer *frameBuf, CameraFrame::FrameType frameType); + void addFramePointers(CameraBuffer *frameBuf, void *buf); + void removeFramePointers(); +}; + +/** Wrapper class around MessageNotifier, which is used by display and notification classes for interacting with + * Camera Adapter + */ +class EventProvider +{ +public: + MessageNotifier* mEventNotifier; + void* mCookie; + event_callback mEventCallback; + +public: + EventProvider(MessageNotifier *mn, void* cookie, event_callback eventCallback) + :mEventNotifier(mn), mCookie(cookie), mEventCallback(eventCallback) {} + + int enableEventNotification(int32_t eventTypes); + int disableEventNotification(int32_t eventTypes); +}; + +/* + * Interface for providing buffers + */ +class BufferProvider +{ +public: + virtual CameraBuffer * allocateBufferList(int width, int height, const char* format, int &bytes, int numBufs) = 0; + + // gets a buffer list from BufferProvider when buffers are sent from external source and already pre-allocated + // only call this function for an input source into CameraHal. If buffers are not from a pre-allocated source + // this function will return NULL and numBufs of -1 + virtual CameraBuffer *getBufferList(int *numBufs) = 0; + + //additional methods used for memory mapping + virtual uint32_t * getOffsets() = 0; + virtual int getFd() = 0; + virtual CameraBuffer * getBuffers(bool reset = false) { return NULL; } + virtual unsigned int getSize() {return 0; } + virtual int getBufferCount() {return -1; } + + virtual int freeBufferList(CameraBuffer * buf) = 0; + + virtual ~BufferProvider() {} +}; + +/** + * Class for handling data and notify callbacks to application + */ +class AppCallbackNotifier: public ErrorNotifier , public virtual android::RefBase +{ + +public: + + ///Constants + static const int NOTIFIER_TIMEOUT; + static const int32_t MAX_BUFFERS = 8; + + enum NotifierCommands + { + NOTIFIER_CMD_PROCESS_EVENT, + NOTIFIER_CMD_PROCESS_FRAME, + NOTIFIER_CMD_PROCESS_ERROR + }; + + enum NotifierState + { + NOTIFIER_STOPPED, + NOTIFIER_STARTED, + NOTIFIER_EXITED + }; + +public: + + ~AppCallbackNotifier(); + + ///Initialzes the callback notifier, creates any resources required + status_t initialize(); + + ///Starts the callbacks to application + status_t start(); + + ///Stops the callbacks from going to application + status_t stop(); + + void setEventProvider(int32_t eventMask, MessageNotifier * eventProvider); + void setFrameProvider(FrameNotifier *frameProvider); + + //All sub-components of Camera HAL call this whenever any error happens + virtual void errorNotify(int error); + + status_t startPreviewCallbacks(android::CameraParameters ¶ms, CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count); + status_t stopPreviewCallbacks(); + + status_t enableMsgType(int32_t msgType); + status_t disableMsgType(int32_t msgType); + + //API for enabling/disabling measurement data + void setMeasurements(bool enable); + + //thread loops + bool notificationThread(); + + ///Notification callback functions + static void frameCallbackRelay(CameraFrame* caFrame); + static void eventCallbackRelay(CameraHalEvent* chEvt); + void frameCallback(CameraFrame* caFrame); + void eventCallback(CameraHalEvent* chEvt); + void flushAndReturnFrames(); + + void setCallbacks(CameraHal *cameraHal, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user); + + //Set Burst mode + void setBurst(bool burst); + + //Notifications from CameraHal for video recording case + status_t startRecording(); + status_t stopRecording(); + status_t initSharedVideoBuffers(CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count, CameraBuffer *vidBufs); + status_t releaseRecordingFrame(const void *opaque); + + status_t useMetaDataBufferMode(bool enable); + + void EncoderDoneCb(void*, void*, CameraFrame::FrameType type, void* cookie1, void* cookie2, void *cookie3); + + void useVideoBuffers(bool useVideoBuffers); + + bool getUesVideoBuffers(); + void setVideoRes(int width, int height); + + void flushEventQueue(); + void setExternalLocking(bool extBuffLocking); + + //Internal class definitions + class NotificationThread : public android::Thread { + AppCallbackNotifier* mAppCallbackNotifier; + Utils::MessageQueue mNotificationThreadQ; + public: + enum NotificationThreadCommands + { + NOTIFIER_START, + NOTIFIER_STOP, + NOTIFIER_EXIT, + }; + public: + NotificationThread(AppCallbackNotifier* nh) + : Thread(false), mAppCallbackNotifier(nh) { } + virtual bool threadLoop() { + return mAppCallbackNotifier->notificationThread(); + } + + Utils::MessageQueue &msgQ() { return mNotificationThreadQ;} + }; + + //Friend declarations + friend class NotificationThread; + +private: + void notifyEvent(); + void notifyFrame(); + bool processMessage(); + void releaseSharedVideoBuffers(); + status_t dummyRaw(); + void copyAndSendPictureFrame(CameraFrame* frame, int32_t msgType); + void copyAndSendPreviewFrame(CameraFrame* frame, int32_t msgType); + size_t calculateBufferSize(size_t width, size_t height, const char *pixelFormat); + const char* getContstantForPixelFormat(const char *pixelFormat); + void lockBufferAndUpdatePtrs(CameraFrame* frame); + void unlockBufferAndUpdatePtrs(CameraFrame* frame); + +private: + mutable android::Mutex mLock; + mutable android::Mutex mBurstLock; + CameraHal* mCameraHal; + camera_notify_callback mNotifyCb; + camera_data_callback mDataCb; + camera_data_timestamp_callback mDataCbTimestamp; + camera_request_memory mRequestMemory; + void *mCallbackCookie; + + //Keeps Video MemoryHeaps and Buffers within + //these objects + android::KeyedVector mVideoHeaps; + android::KeyedVector mVideoBuffers; + android::KeyedVector mVideoMap; + + //Keeps list of Gralloc handles and associated Video Metadata Buffers + android::KeyedVector mVideoMetadataBufferMemoryMap; + android::KeyedVector mVideoMetadataBufferReverseMap; + + bool mBufferReleased; + + android::sp< NotificationThread> mNotificationThread; + EventProvider *mEventProvider; + FrameProvider *mFrameProvider; + Utils::MessageQueue mEventQ; + Utils::MessageQueue mFrameQ; + NotifierState mNotifierState; + + bool mPreviewing; + camera_memory_t* mPreviewMemory; + CameraBuffer mPreviewBuffers[MAX_BUFFERS]; + int mPreviewBufCount; + int mPreviewWidth; + int mPreviewHeight; + int mPreviewStride; + const char *mPreviewPixelFormat; + android::KeyedVector > mSharedPreviewHeaps; + android::KeyedVector > mSharedPreviewBuffers; + + //Burst mode active + bool mBurst; + mutable android::Mutex mRecordingLock; + bool mRecording; + bool mMeasurementEnabled; + + bool mUseMetaDataBufferMode; + bool mRawAvailable; + + bool mUseVideoBuffers; + + int mVideoWidth; + int mVideoHeight; + + bool mExternalLocking; + +}; + + +/** + * Class used for allocating memory for JPEG bit stream buffers, output buffers of camera in no overlay case + */ +class MemoryManager : public BufferProvider, public virtual android::RefBase +{ +public: + MemoryManager(); + ~MemoryManager(); + + status_t initialize(); + + int setErrorHandler(ErrorNotifier *errorNotifier); + virtual CameraBuffer * allocateBufferList(int width, int height, const char* format, int &bytes, int numBufs); + virtual CameraBuffer *getBufferList(int *numBufs); + virtual uint32_t * getOffsets(); + virtual int getFd() ; + virtual int freeBufferList(CameraBuffer * buflist); + +private: + android::sp mErrorNotifier; + int mIonFd; +}; + + + + +/** + * CameraAdapter interface class + * Concrete classes derive from this class and provide implementations based on the specific camera h/w interface + */ + +class CameraAdapter: public FrameNotifier, public virtual android::RefBase +{ +protected: + enum AdapterActiveStates { + INTIALIZED_ACTIVE = 1 << 0, + LOADED_PREVIEW_ACTIVE = 1 << 1, + PREVIEW_ACTIVE = 1 << 2, + LOADED_CAPTURE_ACTIVE = 1 << 3, + CAPTURE_ACTIVE = 1 << 4, + BRACKETING_ACTIVE = 1 << 5, + AF_ACTIVE = 1 << 6, + ZOOM_ACTIVE = 1 << 7, + VIDEO_ACTIVE = 1 << 8, + LOADED_REPROCESS_ACTIVE = 1 << 9, + REPROCESS_ACTIVE = 1 << 10, + }; +public: + typedef struct + { + CameraBuffer *mBuffers; + uint32_t *mOffsets; + int mFd; + size_t mLength; + size_t mCount; + size_t mMaxQueueable; + } BuffersDescriptor; + + enum CameraCommands + { + CAMERA_START_PREVIEW = 0, + CAMERA_STOP_PREVIEW = 1, + CAMERA_START_VIDEO = 2, + CAMERA_STOP_VIDEO = 3, + CAMERA_START_IMAGE_CAPTURE = 4, + CAMERA_STOP_IMAGE_CAPTURE = 5, + CAMERA_PERFORM_AUTOFOCUS = 6, + CAMERA_CANCEL_AUTOFOCUS = 7, + CAMERA_PREVIEW_FLUSH_BUFFERS = 8, + CAMERA_START_SMOOTH_ZOOM = 9, + CAMERA_STOP_SMOOTH_ZOOM = 10, + CAMERA_USE_BUFFERS_PREVIEW = 11, + CAMERA_SET_TIMEOUT = 12, + CAMERA_CANCEL_TIMEOUT = 13, + CAMERA_START_BRACKET_CAPTURE = 14, + CAMERA_STOP_BRACKET_CAPTURE = 15, + CAMERA_QUERY_RESOLUTION_PREVIEW = 16, + CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE = 17, + CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA = 18, + CAMERA_USE_BUFFERS_IMAGE_CAPTURE = 19, + CAMERA_USE_BUFFERS_PREVIEW_DATA = 20, + CAMERA_TIMEOUT_EXPIRED = 21, + CAMERA_START_FD = 22, + CAMERA_STOP_FD = 23, + CAMERA_SWITCH_TO_EXECUTING = 24, + CAMERA_USE_BUFFERS_VIDEO_CAPTURE = 25, +#ifdef OMAP_ENHANCEMENT_CPCAM + CAMERA_USE_BUFFERS_REPROCESS = 26, + CAMERA_START_REPROCESS = 27, +#endif +#ifdef OMAP_ENHANCEMENT_VTC + CAMERA_SETUP_TUNNEL = 28, + CAMERA_DESTROY_TUNNEL = 29, +#endif + CAMERA_PREVIEW_INITIALIZATION = 30, + }; + + enum CameraMode + { + CAMERA_PREVIEW, + CAMERA_IMAGE_CAPTURE, + CAMERA_VIDEO, + CAMERA_MEASUREMENT, + CAMERA_REPROCESS, + }; + + enum AdapterState { + INTIALIZED_STATE = INTIALIZED_ACTIVE, + LOADED_PREVIEW_STATE = LOADED_PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + PREVIEW_STATE = PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + LOADED_CAPTURE_STATE = LOADED_CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + CAPTURE_STATE = CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + BRACKETING_STATE = BRACKETING_ACTIVE | CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE , + AF_STATE = AF_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + ZOOM_STATE = ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_STATE = VIDEO_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_AF_STATE = VIDEO_ACTIVE | AF_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_ZOOM_STATE = VIDEO_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_LOADED_CAPTURE_STATE = VIDEO_ACTIVE | LOADED_CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_CAPTURE_STATE = VIDEO_ACTIVE | CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + AF_ZOOM_STATE = AF_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + BRACKETING_ZOOM_STATE = BRACKETING_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + LOADED_REPROCESS_STATE = LOADED_REPROCESS_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + LOADED_REPROCESS_CAPTURE_STATE = LOADED_REPROCESS_ACTIVE | LOADED_CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + REPROCESS_STATE = REPROCESS_ACTIVE | CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + }; + + +public: + + ///Initialzes the camera adapter creates any resources required + virtual int initialize(CameraProperties::Properties*) = 0; + + virtual int setErrorHandler(ErrorNotifier *errorNotifier) = 0; + + //Message/Frame notification APIs + virtual void enableMsgType(int32_t msgs, + frame_callback callback = NULL, + event_callback eventCb = NULL, + void *cookie = NULL) = 0; + virtual void disableMsgType(int32_t msgs, void* cookie) = 0; + virtual void returnFrame(CameraBuffer* frameBuf, CameraFrame::FrameType frameType) = 0; + virtual void addFramePointers(CameraBuffer *frameBuf, void *buf) = 0; + virtual void removeFramePointers() = 0; + + //APIs to configure Camera adapter and get the current parameter set + virtual int setParameters(const android::CameraParameters& params) = 0; + virtual void getParameters(android::CameraParameters& params) = 0; + + //Registers callback for returning image buffers back to CameraHAL + virtual int registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data) = 0; + + //Registers callback, which signals a completed image capture + virtual int registerEndCaptureCallback(end_image_capture_callback callback, void *user_data) = 0; + + //API to send a command to the camera + virtual status_t sendCommand(CameraCommands operation, int value1=0, int value2=0, int value3=0, int value4=0) = 0; + + virtual ~CameraAdapter() {}; + + //Retrieves the current Adapter state + virtual AdapterState getState() = 0; + + //Retrieves the next Adapter state + virtual AdapterState getNextState() = 0; + + // Receive orientation events from CameraHal + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt) = 0; + + // Rolls the state machine back to INTIALIZED_STATE from the current state + virtual status_t rollbackToInitializedState() = 0; + + // Retrieves the current Adapter state - for internal use (not locked) + virtual status_t getState(AdapterState &state) = 0; + // Retrieves the next Adapter state - for internal use (not locked) + virtual status_t getNextState(AdapterState &state) = 0; + + virtual status_t setSharedAllocator(camera_request_memory shmem_alloc) = 0; + +protected: + //The first two methods will try to switch the adapter state. + //Every call to setState() should be followed by a corresponding + //call to commitState(). If the state switch fails, then it will + //get reset to the previous state via rollbackState(). + virtual status_t setState(CameraCommands operation) = 0; + virtual status_t commitState() = 0; + virtual status_t rollbackState() = 0; +}; + +class DisplayAdapter : public BufferProvider, public virtual android::RefBase +{ +public: + DisplayAdapter(); + +#ifdef OMAP_ENHANCEMENT_CPCAM + preview_stream_extended_ops_t * extendedOps() const { + return mExtendedOps; + } + + void setExtendedOps(preview_stream_extended_ops_t * extendedOps); +#endif + + ///Initializes the display adapter creates any resources required + virtual int initialize() = 0; + + virtual int setPreviewWindow(struct preview_stream_ops *window) = 0; + virtual int setFrameProvider(FrameNotifier *frameProvider) = 0; + virtual int setErrorHandler(ErrorNotifier *errorNotifier) = 0; + virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL) = 0; + virtual int disableDisplay(bool cancel_buffer = true) = 0; + //Used for Snapshot review temp. pause + virtual int pauseDisplay(bool pause) = 0; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + //Used for shot to snapshot measurement + virtual int setSnapshotTimeRef(struct timeval *refTime = NULL) = 0; +#endif + + virtual bool supportsExternalBuffering() = 0; + + // Get max queueable buffers display supports + // This function should only be called after + // allocateBufferList + virtual status_t maxQueueableBuffers(unsigned int& queueable) = 0; + + // Get min buffers display needs at any given time + virtual status_t minUndequeueableBuffers(int& unqueueable) = 0; + + // Given a vector of DisplayAdapters find the one corresponding to str + virtual bool match(const char * str) { return false; } + +private: +#ifdef OMAP_ENHANCEMENT_CPCAM + preview_stream_extended_ops_t * mExtendedOps; +#endif +}; + +static void releaseImageBuffers(void *userData); + +static void endImageCapture(void *userData); + + /** + Implementation of the Android Camera hardware abstraction layer + + This class implements the interface methods defined in CameraHardwareInterface + for the OMAP4 platform + +*/ +class CameraHal + +{ + +public: + enum SocFamily { + SocFamily_Undefined = -1, + SocFamily_Omap4430 = 0, + SocFamily_Omap4460, + SocFamily_Omap4470, + SocFamily_ElementCount // element count of SocFamily + }; + + ///Constants + static const int NO_BUFFERS_PREVIEW; + static const int NO_BUFFERS_IMAGE_CAPTURE; + static const int NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP; + static const uint32_t VFR_SCALE = 1000; + + + /*--------------------Interface Methods---------------------------------*/ + + //@{ +public: + +#ifdef MOTOROLA_CAMERA + bool SetFlashLedTorch(unsigned intensity); +#endif + + /** Set the notification and data callbacks */ + void setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user); + + /** Receives orientation events from SensorListener **/ + void onOrientationEvent(uint32_t orientation, uint32_t tilt); + + /** + * The following three functions all take a msgtype, + * which is a bitmask of the messages defined in + * include/ui/Camera.h + */ + + /** + * Enable a message, or set of messages. + */ + void enableMsgType(int32_t msgType); + + /** + * Disable a message, or a set of messages. + */ + void disableMsgType(int32_t msgType); + + /** + * Query whether a message, or a set of messages, is enabled. + * Note that this is operates as an AND, if any of the messages + * queried are off, this will return false. + */ + int msgTypeEnabled(int32_t msgType); + + /** + * Start preview mode. + */ + int startPreview(); + + /** + * Set preview mode related initialization. + * Only used when slice based processing is enabled. + */ + int cameraPreviewInitialization(); + + /** + * Only used if overlays are used for camera preview. + */ + int setPreviewWindow(struct preview_stream_ops *window); + +#ifdef OMAP_ENHANCEMENT_CPCAM + void setExtendedPreviewStreamOps(preview_stream_extended_ops_t *ops); + + /** + * Set a tap-in or tap-out point. + */ + int setBufferSource(struct preview_stream_ops *tapin, struct preview_stream_ops *tapout); +#endif + + /** + * Release a tap-in or tap-out point. + */ + int releaseBufferSource(struct preview_stream_ops *tapin, struct preview_stream_ops *tapout); + + /** + * Stop a previously started preview. + */ + void stopPreview(); + + /** + * Returns true if preview is enabled. + */ + bool previewEnabled(); + + /** + * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME + * message is sent with the corresponding frame. Every record frame must be released + * by calling releaseRecordingFrame(). + */ + int startRecording(); + + /** + * Stop a previously started recording. + */ + void stopRecording(); + + /** + * Returns true if recording is enabled. + */ + int recordingEnabled(); + + /** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + */ + void releaseRecordingFrame(const void *opaque); + + /** + * Start auto focus, the notification callback routine is called + * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() + * will be called again if another auto focus is needed. + */ + int autoFocus(); + + /** + * Cancels auto-focus function. If the auto-focus is still in progress, + * this function will cancel it. Whether the auto-focus is in progress + * or not, this function will return the focus position to the default. + * If the camera does not support auto-focus, this is a no-op. + */ + int cancelAutoFocus(); + + /** + * Take a picture. + */ + int takePicture(const char* params); + + /** + * Cancel a picture that was started with takePicture. Calling this + * method when no picture is being taken is a no-op. + */ + int cancelPicture(); + + /** Set the camera parameters. */ + int setParameters(const char* params); + int setParameters(const android::CameraParameters& params); + + /** Return the camera parameters. */ + char* getParameters(); + void putParameters(char *); + + /** + * Send command to camera driver. + */ + int sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); + + /** + * Release the hardware resources owned by this object. Note that this is + * *not* done in the destructor. + */ + void release(); + + /** + * Dump state of the camera hardware + */ + int dump(int fd) const; + +#ifdef OMAP_ENHANCEMENT_CPCAM + /** + * start a reprocessing operation. + */ + int reprocess(const char* params); + + /** + * cancels current reprocessing operation + */ + int cancel_reprocess(); +#endif + + status_t storeMetaDataInBuffers(bool enable); + + // Use external locking for graphic buffers + void setExternalLocking(bool extBuffLocking); + + //@} + +/*--------------------Internal Member functions - Public---------------------------------*/ + +public: + /** @name internalFunctionsPublic */ + //@{ + + /** Constructor of CameraHal */ + CameraHal(int cameraId); + + // Destructor of CameraHal + ~CameraHal(); + + /** Initialize CameraHal */ + status_t initialize(CameraProperties::Properties*); + + /** Deinitialize CameraHal */ + void deinitialize(); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Uses the constructor timestamp as a reference to calcluate the + // elapsed time + static void PPM(const char *); + //Uses a user provided timestamp as a reference to calcluate the + // elapsed time + static void PPM(const char *, struct timeval*, ...); + +#endif + + /** Free image bufs */ + status_t freeImageBufs(); + + //Signals the end of image capture + status_t signalEndImageCapture(); + + //Events + static void eventCallbackRelay(CameraHalEvent* event); + void eventCallback(CameraHalEvent* event); + void setEventProvider(int32_t eventMask, MessageNotifier * eventProvider); + + static const char* getPixelFormatConstant(const char* parameters_format); + static size_t calculateBufferSize(const char* parameters_format, int width, int height); + static void getXYFromOffset(unsigned int *x, unsigned int *y, + unsigned int offset, unsigned int stride, + const char* format); + static unsigned int getBPP(const char* format); + static bool parsePair(const char *str, int *first, int *second, char delim); + +/*--------------------Internal Member functions - Private---------------------------------*/ +private: + + /** @name internalFunctionsPrivate */ + //@{ + + /** Set the camera parameters specific to Video Recording. */ + bool setVideoModeParameters(const android::CameraParameters&); + + /** Reset the camera parameters specific to Video Recording. */ + bool resetVideoModeParameters(); + + /** Restart the preview with setParameter. */ + status_t restartPreview(); + + status_t parseResolution(const char *resStr, int &width, int &height); + + void insertSupportedParams(); + + /** Allocate preview data buffers */ + status_t allocPreviewDataBufs(size_t size, size_t bufferCount); + + /** Free preview data buffers */ + status_t freePreviewDataBufs(); + + /** Allocate preview buffers */ + status_t allocPreviewBufs(int width, int height, const char* previewFormat, unsigned int bufferCount, unsigned int &max_queueable); + + /** Allocate video buffers */ + status_t allocVideoBufs(uint32_t width, uint32_t height, uint32_t bufferCount); + + /** Allocate image capture buffers */ + status_t allocImageBufs(unsigned int width, unsigned int height, size_t length, + const char* previewFormat, unsigned int bufferCount); + + /** Allocate Raw buffers */ + status_t allocRawBufs(int width, int height, const char* previewFormat, int bufferCount); + + /** Free preview buffers */ + status_t freePreviewBufs(); + + /** Free video bufs */ + status_t freeVideoBufs(CameraBuffer *bufs); + + /** Free RAW bufs */ + status_t freeRawBufs(); + + //Check if a given resolution is supported by the current camera + //instance + bool isResolutionValid(unsigned int width, unsigned int height, const char *supportedResolutions); + + //Check if a given variable frame rate range is supported by the current camera + //instance + bool isFpsRangeValid(int fpsMin, int fpsMax, const char *supportedFpsRanges); + + //Check if a given parameter is supported by the current camera + // instance + bool isParameterValid(const char *param, const char *supportedParams); + bool isParameterValid(int param, const char *supportedParams); + status_t doesSetParameterNeedUpdate(const char *new_param, const char *old_params, bool &update); + + /** Initialize default parameters */ + void initDefaultParameters(); + + void dumpProperties(CameraProperties::Properties& cameraProps); + + status_t startImageBracketing(); + + status_t stopImageBracketing(); + + void setShutter(bool enable); + + void forceStopPreview(); + + void resetPreviewRes(android::CameraParameters *params); + + // Internal __takePicture function - used in public takePicture() and reprocess() + int __takePicture(const char* params, struct timeval *captureStart = NULL); + //@} + + status_t setTapoutLocked(struct preview_stream_ops *out); + status_t releaseTapoutLocked(struct preview_stream_ops *out); + status_t setTapinLocked(struct preview_stream_ops *in); + status_t releaseTapinLocked(struct preview_stream_ops *in); + + static SocFamily getSocFamily(); + +#ifdef MOTOROLA_CAMERA + // I2C read write utility to support factory test commands + bool i2cRW(int read_size, int write_size, unsigned char *read_data, unsigned char *write_data); + + // get best flash intensity level for the current battery level + unsigned int getFlashIntensity(void); +#endif +/*----------Member variables - Public ---------------------*/ +public: + int32_t mMsgEnabled; + bool mRecordEnabled; + nsecs_t mCurrentTime; + bool mFalsePreview; + bool mPreviewEnabled; + uint32_t mTakePictureQueue; + bool mBracketingEnabled; + bool mBracketingRunning; + //User shutter override + bool mShutterEnabled; + bool mMeasurementEnabled; + //Google's parameter delimiter + static const char PARAMS_DELIMITER[]; + + CameraAdapter *mCameraAdapter; + android::sp mAppCallbackNotifier; + android::sp mDisplayAdapter; + android::sp mMemoryManager; + + android::Vector< android::sp > mOutAdapters; + android::Vector< android::sp > mInAdapters; + + // TODO(XXX): Even though we support user setting multiple BufferSourceAdapters now + // only one tap in surface and one tap out surface is supported at a time. + android::sp mBufferSourceAdapter_In; + android::sp mBufferSourceAdapter_Out; + +#ifdef OMAP_ENHANCEMENT_CPCAM + preview_stream_extended_ops_t * mExtendedPreviewStreamOps; +#endif + + android::sp mPictureHeap; + + int* mGrallocHandles; + bool mFpsRangeChangedByApp; + + + int mRawWidth; + int mRawHeight; + bool mRawCapture; + + +///static member vars + + static const int SW_SCALING_FPS_LIMIT; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Timestamp from the CameraHal constructor + static struct timeval ppm_start; + //Timestamp of the autoFocus command + static struct timeval mStartFocus; + //Timestamp of the startPreview command + static struct timeval mStartPreview; + //Timestamp of the takePicture command + static struct timeval mStartCapture; + +#endif + +/*----------Member variables - Private ---------------------*/ +private: + bool mDynamicPreviewSwitch; + //keeps paused state of display + bool mDisplayPaused; + +#ifdef OMAP_ENHANCEMENT_VTC + bool mTunnelSetup; + bool mVTCUseCase; +#endif + + //Index of current camera adapter + int mCameraIndex; + + mutable android::Mutex mLock; + + android::sp mSensorListener; + + void* mCameraAdapterHandle; + + android::CameraParameters mParameters; + bool mPreviewRunning; + bool mPreviewStateOld; + bool mRecordingEnabled; + EventProvider *mEventProvider; + + CameraBuffer *mPreviewDataBuffers; + uint32_t *mPreviewDataOffsets; + int mPreviewDataFd; + int mPreviewDataLength; + CameraBuffer *mImageBuffers; + uint32_t *mImageOffsets; + int mImageFd; + int mImageLength; + unsigned int mImageCount; + CameraBuffer *mPreviewBuffers; + uint32_t *mPreviewOffsets; + int mPreviewLength; + int mPreviewFd; + CameraBuffer *mVideoBuffers; + uint32_t *mVideoOffsets; + int mVideoFd; + int mVideoLength; + + int mBracketRangePositive; + int mBracketRangeNegative; + + ///@todo Rename this as preview buffer provider + BufferProvider *mBufProvider; + BufferProvider *mVideoBufProvider; + + + CameraProperties::Properties* mCameraProperties; + + bool mPreviewStartInProgress; + bool mPreviewInitializationDone; + + bool mSetPreviewWindowCalled; + + uint32_t mPreviewWidth; + uint32_t mPreviewHeight; + int32_t mMaxZoomSupported; + + int mVideoWidth; + int mVideoHeight; + + android::String8 mCapModeBackup; + + bool mExternalLocking; + + const SocFamily mSocFamily; +}; + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/inc/CameraProperties.h b/camera/inc/CameraProperties.h new file mode 100644 index 0000000..0c003c3 --- /dev/null +++ b/camera/inc/CameraProperties.h @@ -0,0 +1,244 @@ +/* + * 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. + */ + + + + +#ifndef CAMERA_PROPERTIES_H +#define CAMERA_PROPERTIES_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cutils/properties.h" + +#include "Common.h" + +namespace Ti { +namespace Camera { + +#ifndef MAX_CAMERAS_SUPPORTED +#define MAX_CAMERAS_SUPPORTED 3 +#endif +#define MAX_SIMUL_CAMERAS_SUPPORTED 1 +#define MAX_PROP_NAME_LENGTH 50 +#define MAX_PROP_VALUE_LENGTH 2048 + +#define REMAINING_BYTES(buff) ((((int)sizeof(buff) - 1 - (int)strlen(buff)) < 0) ? 0 : (sizeof(buff) - 1 - strlen(buff))) + +enum OperatingMode { + MODE_HIGH_SPEED = 0, + MODE_HIGH_QUALITY, + MODE_ZEROSHUTTERLAG, + MODE_VIDEO, + MODE_STEREO, + MODE_CPCAM, + MODE_VIDEO_HIGH_QUALITY, + MODE_MAX +}; + +// Class that handles the Camera Properties +class CameraProperties +{ +public: + static const char INVALID[]; + static const char CAMERA_NAME[]; + static const char CAMERA_SENSOR_INDEX[]; + static const char CAMERA_SENSOR_ID[]; + static const char ORIENTATION_INDEX[]; + static const char FACING_INDEX[]; + static const char SUPPORTED_PREVIEW_SIZES[]; + static const char SUPPORTED_PREVIEW_SUBSAMPLED_SIZES[]; + static const char SUPPORTED_PREVIEW_TOPBOTTOM_SIZES[]; + static const char SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES[]; + static const char SUPPORTED_PREVIEW_FORMATS[]; + static const char SUPPORTED_PREVIEW_FRAME_RATES[]; + static const char SUPPORTED_PREVIEW_FRAME_RATES_EXT[]; + static const char SUPPORTED_PICTURE_SIZES[]; + static const char SUPPORTED_PICTURE_SUBSAMPLED_SIZES[]; + static const char SUPPORTED_PICTURE_TOPBOTTOM_SIZES[]; + static const char SUPPORTED_PICTURE_SIDEBYSIDE_SIZES[]; + static const char SUPPORTED_PICTURE_FORMATS[]; + static const char SUPPORTED_THUMBNAIL_SIZES[]; + static const char SUPPORTED_WHITE_BALANCE[]; + static const char SUPPORTED_EFFECTS[]; + static const char SUPPORTED_ANTIBANDING[]; + static const char SUPPORTED_EXPOSURE_MODES[]; + static const char SUPPORTED_MANUAL_EXPOSURE_MIN[]; + static const char SUPPORTED_MANUAL_EXPOSURE_MAX[]; + static const char SUPPORTED_MANUAL_EXPOSURE_STEP[]; + static const char SUPPORTED_MANUAL_GAIN_ISO_MIN[]; + static const char SUPPORTED_MANUAL_GAIN_ISO_MAX[]; + static const char SUPPORTED_MANUAL_GAIN_ISO_STEP[]; + static const char SUPPORTED_EV_MIN[]; + static const char SUPPORTED_EV_MAX[]; + static const char SUPPORTED_EV_STEP[]; + static const char SUPPORTED_ISO_VALUES[]; + static const char SUPPORTED_SCENE_MODES[]; + static const char SUPPORTED_FLASH_MODES[]; + static const char SUPPORTED_FOCUS_MODES[]; + static const char REQUIRED_PREVIEW_BUFS[]; + static const char REQUIRED_IMAGE_BUFS[]; + static const char SUPPORTED_ZOOM_RATIOS[]; + static const char SUPPORTED_ZOOM_STAGES[]; + static const char SUPPORTED_IPP_MODES[]; + static const char SMOOTH_ZOOM_SUPPORTED[]; + static const char ZOOM_SUPPORTED[]; + static const char PREVIEW_SIZE[]; + static const char PREVIEW_FORMAT[]; + static const char PREVIEW_FRAME_RATE[]; + static const char ZOOM[]; + static const char PICTURE_SIZE[]; + static const char PICTURE_FORMAT[]; + static const char JPEG_THUMBNAIL_SIZE[]; + static const char WHITEBALANCE[]; + static const char EFFECT[]; + static const char ANTIBANDING[]; + static const char EXPOSURE_MODE[]; + static const char EV_COMPENSATION[]; + static const char ISO_MODE[]; + static const char FOCUS_MODE[]; + static const char SCENE_MODE[]; + static const char FLASH_MODE[]; + static const char JPEG_QUALITY[]; + static const char BRIGHTNESS[]; + static const char SATURATION[]; + static const char SHARPNESS[]; + static const char CONTRAST[]; + static const char IPP[]; + static const char GBCE[]; + static const char SUPPORTED_GBCE[]; + static const char GLBCE[]; + static const char SUPPORTED_GLBCE[]; + static const char AUTOCONVERGENCE_MODE[]; + static const char AUTOCONVERGENCE_MODE_VALUES[]; + static const char MANUAL_CONVERGENCE[]; + static const char SUPPORTED_MANUAL_CONVERGENCE_MIN[]; + static const char SUPPORTED_MANUAL_CONVERGENCE_MAX[]; + static const char SUPPORTED_MANUAL_CONVERGENCE_STEP[]; + static const char SENSOR_ORIENTATION[]; + static const char SENSOR_ORIENTATION_VALUES[]; + static const char REVISION[]; + static const char FOCAL_LENGTH[]; + static const char HOR_ANGLE[]; + static const char VER_ANGLE[]; + static const char EXIF_MAKE[]; + static const char EXIF_MODEL[]; + static const char JPEG_THUMBNAIL_QUALITY[]; + static const char MAX_FOCUS_AREAS[]; + static const char MAX_FD_HW_FACES[]; + static const char MAX_FD_SW_FACES[]; + + static const char MAX_PICTURE_WIDTH[]; + static const char MAX_PICTURE_HEIGHT[]; + + static const char PARAMS_DELIMITER []; + + static const char S3D_PRV_FRAME_LAYOUT[]; + static const char S3D_PRV_FRAME_LAYOUT_VALUES[]; + static const char S3D_CAP_FRAME_LAYOUT[]; + static const char S3D_CAP_FRAME_LAYOUT_VALUES[]; + static const char VSTAB[]; + static const char VSTAB_SUPPORTED[]; + static const char VNF[]; + static const char VNF_SUPPORTED[]; + static const char FRAMERATE_RANGE[]; + static const char FRAMERATE_RANGE_SUPPORTED[]; + static const char FRAMERATE_RANGE_EXT_SUPPORTED[]; + + static const char DEFAULT_VALUE[]; + + static const char AUTO_EXPOSURE_LOCK[]; + static const char AUTO_EXPOSURE_LOCK_SUPPORTED[]; + static const char AUTO_WHITEBALANCE_LOCK[]; + static const char AUTO_WHITEBALANCE_LOCK_SUPPORTED[]; + static const char MAX_NUM_METERING_AREAS[]; + static const char METERING_AREAS[]; + static const char MAX_NUM_FOCUS_AREAS[]; + + static const char VIDEO_SNAPSHOT_SUPPORTED[]; + + static const char VIDEO_SIZE[]; + static const char SUPPORTED_VIDEO_SIZES[]; + + static const char MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED[]; + static const char MECHANICAL_MISALIGNMENT_CORRECTION[]; + + static const char RAW_WIDTH[]; + static const char RAW_HEIGHT[]; + + static const char CAP_MODE_VALUES[]; + + CameraProperties(); + ~CameraProperties(); + + // container class passed around for accessing properties + class Properties + { + public: + + Properties() + { + } + + ~Properties() + { + } + + void set(const char *prop, const char *value); + void set(const char *prop, int value); + const char* get(const char * prop) const; + int getInt(const char * prop) const; + void setSensorIndex(int idx); + void setMode(OperatingMode mode); + OperatingMode getMode() const; + void dump(); + + protected: + const char* keyAt(const unsigned int) const; + const char* valueAt(const unsigned int) const; + + private: + OperatingMode mCurrentMode; + android::DefaultKeyedVector mProperties[MODE_MAX]; + + }; + + ///Initializes the CameraProperties class + status_t initialize(); + status_t loadProperties(); + int camerasSupported(); + int getProperties(int cameraIndex, Properties** properties); + +private: + + int mCamerasSupported; + int mInitialized; + mutable android::Mutex mLock; + + Properties mCameraProps[MAX_CAMERAS_SUPPORTED]; + +}; + +} // namespace Camera +} // namespace Ti + +#endif //CAMERA_PROPERTIES_H diff --git a/camera/inc/Common.h b/camera/inc/Common.h new file mode 100644 index 0000000..b369e65 --- /dev/null +++ b/camera/inc/Common.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef CAMERAHAL_COMMON_H +#define CAMERAHAL_COMMON_H + +#include "UtilsCommon.h" +#include "DebugUtils.h" +#include "Status.h" + + + + +// logging functions +#ifdef CAMERAHAL_DEBUG +# define CAMHAL_LOGD DBGUTILS_LOGD +# define CAMHAL_LOGDA DBGUTILS_LOGDA +# define CAMHAL_LOGDB DBGUTILS_LOGDB +# ifdef CAMERAHAL_DEBUG_VERBOSE +# define CAMHAL_LOGV DBGUTILS_LOGV +# define CAMHAL_LOGVA DBGUTILS_LOGVA +# define CAMHAL_LOGVB DBGUTILS_LOGVB +# else +# define CAMHAL_LOGV(...) +# define CAMHAL_LOGVA(str) +# define CAMHAL_LOGVB(str, ...) +# endif +#else +# define CAMHAL_LOGD(...) +# define CAMHAL_LOGDA(str) +# define CAMHAL_LOGDB(str, ...) +# define CAMHAL_LOGV(...) +# define CAMHAL_LOGVA(str) +# define CAMHAL_LOGVB(str, ...) +#endif + +#define CAMHAL_LOGI DBGUTILS_LOGI +#define CAMHAL_LOGW DBGUTILS_LOGW +#define CAMHAL_LOGE DBGUTILS_LOGE +#define CAMHAL_LOGEA DBGUTILS_LOGEA +#define CAMHAL_LOGEB DBGUTILS_LOGEB +#define CAMHAL_LOGF DBGUTILS_LOGF + +#define CAMHAL_ASSERT DBGUTILS_ASSERT +#define CAMHAL_ASSERT_X DBGUTILS_ASSERT_X + +#define CAMHAL_UNUSED(x) (void)x + + + + +#endif // CAMERAHAL_COMMON_H diff --git a/camera/inc/DecoderFactory.h b/camera/inc/DecoderFactory.h new file mode 100644 index 0000000..d5e566f --- /dev/null +++ b/camera/inc/DecoderFactory.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef DECODERFACTORY_H_ +#define DECODERFACTORY_H_ + +#include "FrameDecoder.h" + +namespace Ti { +namespace Camera { + +class DecoderFactory { + DecoderFactory(); + ~DecoderFactory(); +public: + static FrameDecoder* createDecoderByType(DecoderType type, bool forceSwDecoder = false); +}; + +} // namespace Camera +} // namespace Ti + +#endif /* DECODERFACTORY_H_ */ diff --git a/camera/inc/Decoder_libjpeg.h b/camera/inc/Decoder_libjpeg.h new file mode 100644 index 0000000..425ebf1 --- /dev/null +++ b/camera/inc/Decoder_libjpeg.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_CAMERA_HARDWARE_DECODER_LIBJPEG_H +#define ANDROID_CAMERA_HARDWARE_DECODER_LIBJPEG_H + +#include "CameraHal.h" + +extern "C" { +#include "jhead.h" + +#undef TRUE +#undef FALSE + +} + + +namespace Ti { +namespace Camera { + +class Decoder_libjpeg +{ + +public: + Decoder_libjpeg(); + ~Decoder_libjpeg(); + static int readDHTSize(); + static bool isDhtExist(unsigned char *jpeg_src, int filled_len); + static int appendDHT(unsigned char *jpeg_src, int filled_len, unsigned char *jpeg_with_dht_buffer, int buff_size); + bool decode(unsigned char *jpeg_src, int filled_len, unsigned char *nv12_buffer, int stride); + +private: + void release(); + unsigned char **Y_Plane; + unsigned char **U_Plane; + unsigned char **V_Plane; + unsigned char *UV_Plane; + unsigned int mWidth, mHeight; +}; + +} // namespace Camera +} // namespace Ti + +#endif + diff --git a/camera/inc/Encoder_libjpeg.h b/camera/inc/Encoder_libjpeg.h new file mode 100644 index 0000000..72feb08 --- /dev/null +++ b/camera/inc/Encoder_libjpeg.h @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/** +* @file Encoder_libjpeg.h +* +* This defines API for camerahal to encode YUV using libjpeg +* +*/ + +#ifndef ANDROID_CAMERA_HARDWARE_ENCODER_LIBJPEG_H +#define ANDROID_CAMERA_HARDWARE_ENCODER_LIBJPEG_H + +#include +#include + +extern "C" { +#include "jhead.h" + +#undef TRUE +#undef FALSE + +} + +#include "CameraHal.h" + +#define CANCEL_TIMEOUT 5000000 // 5 seconds + +namespace Ti { +namespace Camera { + +/** + * libjpeg encoder class - uses libjpeg to encode yuv + */ + +#define MAX_EXIF_TAGS_SUPPORTED 30 +typedef void (*encoder_libjpeg_callback_t) (void* main_jpeg, + void* thumb_jpeg, + CameraFrame::FrameType type, + void* cookie1, + void* cookie2, + void* cookie3, + void* cookie4, + bool canceled); + +// these have to match strings defined in external/jhead/exif.c +static const char TAG_MODEL[] = "Model"; +static const char TAG_MAKE[] = "Make"; +static const char TAG_FOCALLENGTH[] = "FocalLength"; +static const char TAG_DATETIME[] = "DateTime"; +static const char TAG_IMAGE_WIDTH[] = "ImageWidth"; +static const char TAG_IMAGE_LENGTH[] = "ImageLength"; +static const char TAG_GPS_LAT[] = "GPSLatitude"; +static const char TAG_GPS_LAT_REF[] = "GPSLatitudeRef"; +static const char TAG_GPS_LONG[] = "GPSLongitude"; +static const char TAG_GPS_LONG_REF[] = "GPSLongitudeRef"; +static const char TAG_GPS_ALT[] = "GPSAltitude"; +static const char TAG_GPS_ALT_REF[] = "GPSAltitudeRef"; +static const char TAG_GPS_MAP_DATUM[] = "GPSMapDatum"; +static const char TAG_GPS_PROCESSING_METHOD[] = "GPSProcessingMethod"; +static const char TAG_GPS_VERSION_ID[] = "GPSVersionID"; +static const char TAG_GPS_TIMESTAMP[] = "GPSTimeStamp"; +static const char TAG_GPS_DATESTAMP[] = "GPSDateStamp"; +static const char TAG_ORIENTATION[] = "Orientation"; +static const char TAG_FLASH[] = "Flash"; +static const char TAG_DIGITALZOOMRATIO[] = "DigitalZoomRatio"; +static const char TAG_EXPOSURETIME[] = "ExposureTime"; +static const char TAG_APERTURE[] = "ApertureValue"; +static const char TAG_ISO_EQUIVALENT[] = "ISOSpeedRatings"; +static const char TAG_WHITEBALANCE[] = "WhiteBalance"; +static const char TAG_LIGHT_SOURCE[] = "LightSource"; +static const char TAG_METERING_MODE[] = "MeteringMode"; +static const char TAG_EXPOSURE_PROGRAM[] = "ExposureProgram"; +static const char TAG_COLOR_SPACE[] = "ColorSpace"; +static const char TAG_CPRS_BITS_PER_PIXEL[] = "CompressedBitsPerPixel"; +static const char TAG_FNUMBER[] = "FNumber"; +static const char TAG_SHUTTERSPEED[] = "ShutterSpeedValue"; +static const char TAG_SENSING_METHOD[] = "SensingMethod"; +static const char TAG_CUSTOM_RENDERED[] = "CustomRendered"; + +class ExifElementsTable { + public: + ExifElementsTable() : + gps_tag_count(0), exif_tag_count(0), position(0), + jpeg_opened(false) + { +#ifdef ANDROID_API_JB_OR_LATER + has_datetime_tag = false; +#endif + } + ~ExifElementsTable(); + + status_t insertElement(const char* tag, const char* value); + void insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size); + status_t insertExifThumbnailImage(const char*, int); + void saveJpeg(unsigned char* picture, size_t jpeg_size); + static const char* degreesToExifOrientation(unsigned int); + static void stringToRational(const char*, unsigned int*, unsigned int*); + static bool isAsciiTag(const char* tag); + private: + ExifElement_t table[MAX_EXIF_TAGS_SUPPORTED]; + unsigned int gps_tag_count; + unsigned int exif_tag_count; + unsigned int position; + bool jpeg_opened; +#ifdef ANDROID_API_JB_OR_LATER + bool has_datetime_tag; +#endif +}; + +class Encoder_libjpeg : public android::Thread { + /* public member types and variables */ + public: + struct params { + uint8_t* src; + int src_size; + uint8_t* dst; + int dst_size; + int quality; + int in_width; + int in_height; + int out_width; + int out_height; + int right_crop; + int start_offset; + const char* format; + size_t jpeg_size; + }; + /* public member functions */ + public: + Encoder_libjpeg(params* main_jpeg, + params* tn_jpeg, + encoder_libjpeg_callback_t cb, + CameraFrame::FrameType type, + void* cookie1, + void* cookie2, + void* cookie3, void *cookie4) + : android::Thread(false), mMainInput(main_jpeg), mThumbnailInput(tn_jpeg), mCb(cb), + mCancelEncoding(false), mCookie1(cookie1), mCookie2(cookie2), mCookie3(cookie3), mCookie4(cookie4), + mType(type), mThumb(NULL) { + this->incStrong(this); + mCancelSem.Create(0); + } + + ~Encoder_libjpeg() { + CAMHAL_LOGVB("~Encoder_libjpeg(%p)", this); + } + + virtual bool threadLoop() { + size_t size = 0; + if (mThumbnailInput) { + // start thread to encode thumbnail + mThumb = new Encoder_libjpeg(mThumbnailInput, NULL, NULL, mType, NULL, NULL, NULL, NULL); + mThumb->run(); + } + + // encode our main image + size = encode(mMainInput); + + // signal cancel semaphore incase somebody is waiting + mCancelSem.Signal(); + + // check if it is main jpeg thread + if(mThumb.get()) { + // wait until tn jpeg thread exits. + mThumb->join(); + mThumb.clear(); + mThumb = NULL; + } + + if(mCb) { + mCb(mMainInput, mThumbnailInput, mType, mCookie1, mCookie2, mCookie3, mCookie4, mCancelEncoding); + } + + // encoder thread runs, self-destructs, and then exits + this->decStrong(this); + return false; + } + + void cancel() { + mCancelEncoding = true; + if (mThumb.get()) { + mThumb->cancel(); + mCancelSem.WaitTimeout(CANCEL_TIMEOUT); + } + } + + void getCookies(void **cookie1, void **cookie2, void **cookie3) { + if (cookie1) *cookie1 = mCookie1; + if (cookie2) *cookie2 = mCookie2; + if (cookie3) *cookie3 = mCookie3; + } + + private: + params* mMainInput; + params* mThumbnailInput; + encoder_libjpeg_callback_t mCb; + bool mCancelEncoding; + void* mCookie1; + void* mCookie2; + void* mCookie3; + void* mCookie4; + CameraFrame::FrameType mType; + android::sp mThumb; + Utils::Semaphore mCancelSem; + + size_t encode(params*); +}; + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/inc/FrameDecoder.h b/camera/inc/FrameDecoder.h new file mode 100644 index 0000000..fab0544 --- /dev/null +++ b/camera/inc/FrameDecoder.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#ifndef FRAMEDECODER_H_ +#define FRAMEDECODER_H_ + +#include +#include +#include "CameraHal.h" + + +namespace Ti { +namespace Camera { + +enum DecoderType { + DecoderType_MJPEG, + DecoderType_H264 +}; + +enum BufferStatus { + BufferStatus_Unknown, + BufferStatus_InQueued, + BufferStatus_InWaitForEmpty, + BufferStatus_InDecoded, + BufferStatus_OutQueued, + BufferStatus_OutWaitForFill, + BufferStatus_OutFilled +}; + +enum DecoderState { + DecoderState_Uninitialized, + DecoderState_Initialized, + DecoderState_Running, + DecoderState_Requested_Stop, + DecoderState_Stoppped +}; + +class MediaBuffer: public virtual android::RefBase { + +public: + MediaBuffer() + : bufferId(-1), buffer(0), filledLen(0), size(0), + mOffset(0), mTimestamp(0), mStatus(BufferStatus_Unknown) { + } + + MediaBuffer(int id, void* buffer, size_t buffSize = 0) + : bufferId(id), buffer(buffer), filledLen(0), size(buffSize), + mOffset(0), mTimestamp(0), mStatus(BufferStatus_Unknown) { + } + + virtual ~MediaBuffer() { + } + + int bufferId; + void* buffer; + int filledLen; + size_t size; + + nsecs_t getTimestamp() const { + return mTimestamp; + } + void setTimestamp(nsecs_t ts) { + mTimestamp = ts; + } + + BufferStatus getStatus() const { + return mStatus; + } + + void setStatus(BufferStatus status) { + mStatus = status; + } + + android::Mutex& getLock() const { + return mLock; + } + + uint32_t getOffset() const { + return mOffset; + } + + void setOffset(uint32_t offset) { + mOffset = offset; + } + +private: + uint32_t mOffset; + nsecs_t mTimestamp; + BufferStatus mStatus; + mutable android::Mutex mLock; +}; + +struct DecoderParameters { + int width; + int height; + int inputBufferCount; + int outputBufferCount; +}; + +class FrameDecoder { +public: + FrameDecoder(); + virtual ~FrameDecoder(); + void configure(const DecoderParameters& config); + status_t start(); + void stop(); + void release(); + void flush(); + status_t queueInputBuffer(int id); + status_t dequeueInputBuffer(int &id); + status_t queueOutputBuffer(int id); + status_t dequeueOutputBuffer(int &id); + + void registerOutputBuffers(android::Vector< android::sp > *outBuffers) { + android::AutoMutex lock(mLock); + mOutQueue.clear(); + mOutBuffers = outBuffers; + } + + void registerInputBuffers(android::Vector< android::sp > *inBuffers) { + android::AutoMutex lock(mLock); + mInQueue.clear(); + mInBuffers = inBuffers; + } + + virtual bool getPaddedDimensions(size_t &width, size_t &height) { + return false; + } + + void setHal(CameraHal* hal) { + mCameraHal = hal; + } + +protected: + virtual void doConfigure(const DecoderParameters& config) = 0; + virtual void doProcessInputBuffer() = 0; + virtual status_t doStart() = 0; + virtual void doStop() = 0; + virtual void doFlush() = 0; + virtual void doRelease() = 0; + + DecoderParameters mParams; + + android::Vector mInQueue; + android::Vector mOutQueue; + + android::Vector< android::sp >* mInBuffers; + android::Vector< android::sp >* mOutBuffers; + + CameraHal* mCameraHal; + +private: + DecoderState mState; + android::Mutex mLock; +}; + +} // namespace Camera +} // namespace Ti + +#endif /* FRAMEDECODER_H_ */ diff --git a/camera/inc/General3A_Settings.h b/camera/inc/General3A_Settings.h new file mode 100644 index 0000000..c1e017c --- /dev/null +++ b/camera/inc/General3A_Settings.h @@ -0,0 +1,295 @@ +/* + * 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. + */ + +/** +* @file General3A_Settings.h +* +* This file maps the Camera Hardware Interface to OMX. +* +*/ + +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Common.h" +#include "OMX_TI_Index.h" +#include "TICameraParameters.h" + +#ifndef GENERAL_3A_SETTINGS_H +#define GENERAL_3A_SETTINGS_H + +namespace Ti { +namespace Camera { + +struct userToOMX_LUT{ + const char * userDefinition; + int omxDefinition; +}; + +struct LUTtype{ + int size; + const userToOMX_LUT *Table; +}; + +const userToOMX_LUT isoUserToOMX[] = { + { TICameraParameters::ISO_MODE_AUTO, 0 }, + { TICameraParameters::ISO_MODE_100, 100 }, + { TICameraParameters::ISO_MODE_200, 200 }, + { TICameraParameters::ISO_MODE_400, 400 }, + { TICameraParameters::ISO_MODE_800, 800 }, + { TICameraParameters::ISO_MODE_1000, 1000 }, + { TICameraParameters::ISO_MODE_1200, 1200 }, + { TICameraParameters::ISO_MODE_1600, 1600 }, +}; + +const userToOMX_LUT effects_UserToOMX [] = { + { android::CameraParameters::EFFECT_NONE, OMX_ImageFilterNone }, + { android::CameraParameters::EFFECT_NEGATIVE, OMX_ImageFilterNegative }, + { android::CameraParameters::EFFECT_SOLARIZE, OMX_ImageFilterSolarize }, + { android::CameraParameters::EFFECT_SEPIA, OMX_ImageFilterSepia }, + { android::CameraParameters::EFFECT_MONO, OMX_ImageFilterGrayScale }, + { android::CameraParameters::EFFECT_BLACKBOARD, OMX_TI_ImageFilterBlackBoard }, + { android::CameraParameters::EFFECT_WHITEBOARD, OMX_TI_ImageFilterWhiteBoard }, + { android::CameraParameters::EFFECT_AQUA, OMX_TI_ImageFilterAqua }, + { android::CameraParameters::EFFECT_POSTERIZE, OMX_TI_ImageFilterPosterize }, +#ifdef OMAP_ENHANCEMENT + { TICameraParameters::EFFECT_NATURAL, OMX_ImageFilterNatural }, + { TICameraParameters::EFFECT_VIVID, OMX_ImageFilterVivid }, + { TICameraParameters::EFFECT_COLOR_SWAP, OMX_ImageFilterColourSwap }, + { TICameraParameters::EFFECT_BLACKWHITE, OMX_TI_ImageFilterBlackWhite } +#endif +}; + +const userToOMX_LUT scene_UserToOMX [] = { + { android::CameraParameters::SCENE_MODE_AUTO, OMX_Manual }, + { android::CameraParameters::SCENE_MODE_LANDSCAPE, OMX_Landscape }, + { android::CameraParameters::SCENE_MODE_NIGHT_PORTRAIT, OMX_NightPortrait }, + { android::CameraParameters::SCENE_MODE_FIREWORKS, OMX_Fireworks }, + { android::CameraParameters::SCENE_MODE_ACTION, OMX_TI_Action }, + { android::CameraParameters::SCENE_MODE_BEACH, OMX_TI_Beach }, + { android::CameraParameters::SCENE_MODE_CANDLELIGHT, OMX_TI_Candlelight }, + { android::CameraParameters::SCENE_MODE_NIGHT, OMX_TI_Night }, + { android::CameraParameters::SCENE_MODE_PARTY, OMX_TI_Party }, + { android::CameraParameters::SCENE_MODE_PORTRAIT, OMX_TI_Portrait }, + { android::CameraParameters::SCENE_MODE_SNOW, OMX_TI_Snow }, + { android::CameraParameters::SCENE_MODE_STEADYPHOTO, OMX_TI_Steadyphoto }, + { android::CameraParameters::SCENE_MODE_SUNSET, OMX_TI_Sunset }, + { android::CameraParameters::SCENE_MODE_THEATRE, OMX_TI_Theatre }, + { android::CameraParameters::SCENE_MODE_SPORTS, OMX_Sport }, +#ifdef OMAP_ENHANCEMENT + { TICameraParameters::SCENE_MODE_CLOSEUP, OMX_Closeup }, + { TICameraParameters::SCENE_MODE_AQUA, OMX_Underwater }, + { TICameraParameters::SCENE_MODE_MOOD, OMX_Mood }, + { TICameraParameters::SCENE_MODE_NIGHT_INDOOR, OMX_NightIndoor }, + { TICameraParameters::SCENE_MODE_DOCUMENT, OMX_Document }, + { TICameraParameters::SCENE_MODE_BARCODE, OMX_Barcode }, + { TICameraParameters::SCENE_MODE_VIDEO_SUPER_NIGHT, OMX_SuperNight }, + { TICameraParameters::SCENE_MODE_VIDEO_CINE, OMX_Cine }, + { TICameraParameters::SCENE_MODE_VIDEO_OLD_FILM, OMX_OldFilm }, +#endif +}; + +const userToOMX_LUT whiteBal_UserToOMX [] = { + { android::CameraParameters::WHITE_BALANCE_AUTO, OMX_WhiteBalControlAuto }, + { android::CameraParameters::WHITE_BALANCE_DAYLIGHT, OMX_WhiteBalControlSunLight }, + { android::CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT, OMX_WhiteBalControlCloudy }, + { android::CameraParameters::WHITE_BALANCE_FLUORESCENT, OMX_WhiteBalControlFluorescent }, + { android::CameraParameters::WHITE_BALANCE_INCANDESCENT, OMX_WhiteBalControlIncandescent }, + { android::CameraParameters::WHITE_BALANCE_SHADE, OMX_TI_WhiteBalControlShade }, + { android::CameraParameters::WHITE_BALANCE_TWILIGHT, OMX_TI_WhiteBalControlTwilight }, + { android::CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT, OMX_TI_WhiteBalControlWarmFluorescent }, +#ifdef OMAP_ENHANCEMENT + { TICameraParameters::WHITE_BALANCE_TUNGSTEN, OMX_WhiteBalControlTungsten }, + { TICameraParameters::WHITE_BALANCE_HORIZON, OMX_WhiteBalControlHorizon }, + { TICameraParameters::WHITE_BALANCE_SUNSET, OMX_TI_WhiteBalControlSunset } +#endif +}; + +const userToOMX_LUT antibanding_UserToOMX [] = { + { android::CameraParameters::ANTIBANDING_OFF, OMX_FlickerCancelOff }, + { android::CameraParameters::ANTIBANDING_AUTO, OMX_FlickerCancelAuto }, + { android::CameraParameters::ANTIBANDING_50HZ, OMX_FlickerCancel50 }, + { android::CameraParameters::ANTIBANDING_60HZ, OMX_FlickerCancel60 } +}; + +const userToOMX_LUT focus_UserToOMX [] = { + { android::CameraParameters::FOCUS_MODE_AUTO, OMX_IMAGE_FocusControlAutoLock }, + { android::CameraParameters::FOCUS_MODE_INFINITY, OMX_IMAGE_FocusControlAutoInfinity }, + { android::CameraParameters::FOCUS_MODE_INFINITY, OMX_IMAGE_FocusControlHyperfocal }, + { android::CameraParameters::FOCUS_MODE_MACRO, OMX_IMAGE_FocusControlAutoMacro }, + { android::CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO, OMX_IMAGE_FocusControlAuto }, + { android::CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, OMX_IMAGE_FocusControlAuto }, +#ifdef OMAP_ENHANCEMENT + { TICameraParameters::FOCUS_MODE_FACE , OMX_IMAGE_FocusControlContinousFacePriority }, + { TICameraParameters::FOCUS_MODE_PORTRAIT, OMX_IMAGE_FocusControlPortrait }, + { TICameraParameters::FOCUS_MODE_EXTENDED, OMX_IMAGE_FocusControlExtended }, +#endif + { TICameraParameters::FOCUS_MODE_OFF , OMX_IMAGE_FocusControlOff } +}; + +const userToOMX_LUT exposure_UserToOMX [] = { + { TICameraParameters::EXPOSURE_MODE_MANUAL, OMX_ExposureControlOff }, + { TICameraParameters::EXPOSURE_MODE_AUTO, OMX_ExposureControlAuto }, + { TICameraParameters::EXPOSURE_MODE_NIGHT, OMX_ExposureControlNight }, + { TICameraParameters::EXPOSURE_MODE_BACKLIGHT, OMX_ExposureControlBackLight }, + { TICameraParameters::EXPOSURE_MODE_SPOTLIGHT, OMX_ExposureControlSpotLight}, + { TICameraParameters::EXPOSURE_MODE_SPORTS, OMX_ExposureControlSports }, + { TICameraParameters::EXPOSURE_MODE_SNOW, OMX_ExposureControlSnow }, + { TICameraParameters::EXPOSURE_MODE_BEACH, OMX_ExposureControlBeach }, + { TICameraParameters::EXPOSURE_MODE_APERTURE, OMX_ExposureControlLargeAperture }, + { TICameraParameters::EXPOSURE_MODE_SMALL_APERTURE, OMX_ExposureControlSmallApperture }, +}; + +const userToOMX_LUT flash_UserToOMX [] = { + { android::CameraParameters::FLASH_MODE_OFF ,OMX_IMAGE_FlashControlOff }, + { android::CameraParameters::FLASH_MODE_ON ,OMX_IMAGE_FlashControlOn }, + { android::CameraParameters::FLASH_MODE_AUTO ,OMX_IMAGE_FlashControlAuto }, + { android::CameraParameters::FLASH_MODE_TORCH ,OMX_IMAGE_FlashControlTorch }, + { android::CameraParameters::FLASH_MODE_RED_EYE ,OMX_IMAGE_FlashControlRedEyeReduction }, +#ifdef OMAP_ENHANCEMENT + { TICameraParameters::FLASH_MODE_FILL_IN ,OMX_IMAGE_FlashControlFillin } +#endif +}; + +const LUTtype ExpLUT = + { + sizeof(exposure_UserToOMX)/sizeof(exposure_UserToOMX[0]), + exposure_UserToOMX + }; + +const LUTtype WBalLUT = + { + sizeof(whiteBal_UserToOMX)/sizeof(whiteBal_UserToOMX[0]), + whiteBal_UserToOMX + }; + +const LUTtype FlickerLUT = + { + sizeof(antibanding_UserToOMX)/sizeof(antibanding_UserToOMX[0]), + antibanding_UserToOMX + }; + +const LUTtype SceneLUT = + { + sizeof(scene_UserToOMX)/sizeof(scene_UserToOMX[0]), + scene_UserToOMX + }; + +const LUTtype FlashLUT = + { + sizeof(flash_UserToOMX)/sizeof(flash_UserToOMX[0]), + flash_UserToOMX + }; + +const LUTtype EffLUT = + { + sizeof(effects_UserToOMX)/sizeof(effects_UserToOMX[0]), + effects_UserToOMX + }; + +const LUTtype FocusLUT = + { + sizeof(focus_UserToOMX)/sizeof(focus_UserToOMX[0]), + focus_UserToOMX + }; + +const LUTtype IsoLUT = + { + sizeof(isoUserToOMX)/sizeof(isoUserToOMX[0]), + isoUserToOMX + }; + +/* +* class Gen3A_settings +* stores the 3A settings +* also defines the look up tables +* for mapping settings from Hal to OMX +*/ +class Gen3A_settings{ + public: + + int Exposure; + int WhiteBallance; + int Flicker; + int SceneMode; + int Effect; + int Focus; + int EVCompensation; + int Contrast; + int Saturation; + int Sharpness; + int ISO; + int FlashMode; + int ManualExposure; + int ManualExposureRight; + int ManualGain; + int ManualGainRight; + + unsigned int Brightness; + OMX_BOOL ExposureLock; + OMX_BOOL FocusLock; + OMX_BOOL WhiteBalanceLock; + + OMX_BOOL AlgoExternalGamma; + OMX_BOOL AlgoNSF1; + OMX_BOOL AlgoNSF2; + OMX_BOOL AlgoSharpening; + OMX_BOOL AlgoThreeLinColorMap; + OMX_BOOL AlgoGIC; + + OMX_TI_CONFIG_GAMMATABLE_TYPE mGammaTable; + +}; + +/* +* Flags raised when a setting is changed +*/ +enum E3ASettingsFlags +{ + SetSceneMode = 1 << 0, + SetEVCompensation = 1 << 1, + SetWhiteBallance = 1 << 2, + SetFlicker = 1 << 3, + SetExposure = 1 << 4, + SetSharpness = 1 << 5, + SetBrightness = 1 << 6, + SetContrast = 1 << 7, + SetISO = 1 << 8, + SetSaturation = 1 << 9, + SetEffect = 1 << 10, + SetFocus = 1 << 11, + SetExpMode = 1 << 14, + SetFlash = 1 << 15, + SetExpLock = 1 << 16, + SetWBLock = 1 << 17, + SetMeteringAreas = 1 << 18, + SetManualExposure = 1 << 19, + + SetAlgoExternalGamma = 1 << 20, + SetAlgoNSF1 = 1 << 21, + SetAlgoNSF2 = 1 << 22, + SetAlgoSharpening = 1 << 23, + SetAlgoThreeLinColorMap = 1 << 24, + SetAlgoGIC = 1 << 25, + SetGammaTable = 1 << 26, + + + E3aSettingMax, + E3AsettingsAll = ( ((E3aSettingMax -1 ) << 1) -1 ) /// all possible flags raised +}; + +} // namespace Camera +} // namespace Ti + +#endif //GENERAL_3A_SETTINGS_H diff --git a/camera/inc/NV12_resize.h b/camera/inc/NV12_resize.h new file mode 100644 index 0000000..4b05a4f --- /dev/null +++ b/camera/inc/NV12_resize.h @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#ifndef NV12_RESIZE_H_ +#define NV12_RESIZE_H_ + +#include "Common.h" + +typedef unsigned char mmBool; +typedef unsigned char mmUchar; +typedef unsigned char mmUint8; +typedef unsigned char mmByte; +typedef unsigned short mmUint16; +typedef unsigned int mmUint32; +typedef unsigned long mmUint64; +typedef signed char mmInt8; +typedef char mmChar; +typedef signed short mmInt16; +typedef signed int mmInt32; +typedef signed long mmLong; +typedef signed int mmHandle; +typedef float mmFloat; +typedef double mmDouble; +typedef int HObj; +typedef HObj HFile; +typedef int HDir; +typedef void* mmMutexHandle; +typedef struct _fstat { + mmInt32 fileSize; +} VE_FileAttribute; + +typedef struct { + mmInt32 second; + mmInt32 millisecond; +} tsVE_Time; + +typedef struct { + mmInt32 year; + mmInt32 month; + mmInt32 day; + mmInt32 hour; + mmInt32 minute; + mmInt32 second; +} TmDateTime; + +const mmUint8 bWeights[8][8][4] = { + {{64, 0, 0, 0}, {56, 0, 0, 8}, {48, 0, 0,16}, {40, 0, 0,24}, + {32, 0, 0,32}, {24, 0, 0,40}, {16, 0, 0,48}, { 8, 0, 0,56}}, + + {{56, 8, 0, 0}, {49, 7, 1, 7}, {42, 6, 2,14}, {35, 5, 3,21}, + {28, 4, 4,28}, {21, 3, 5,35}, {14, 2, 6,42}, { 7, 1, 7,49}}, + + {{48,16, 0, 0}, {42,14, 2, 6}, {36,12,4 ,12}, {30,10,6 ,18}, + {24, 8, 8,24}, {18, 6,10,30}, {12,4 ,12,36}, { 6, 2,14,42}}, + + {{40,24,0 ,0 }, {35,21, 3, 5}, {30,18, 6,10}, {25,15, 9,15}, + {20,12,12,20}, {15, 9,15,25}, {10, 6,18,30}, { 5, 3,21,35}}, + + {{32,32, 0,0 }, {28,28, 4, 4}, {24,24, 8, 8}, {20,20,12,12}, + {16,16,16,16}, {12,12,20,20}, { 8, 8,24,24}, { 4, 4,28,28}}, + + {{24,40,0 ,0 }, {21,35, 5, 3}, {18,30,10, 6}, {15,25,15, 9}, + {12,20,20,12}, { 9,15,25,15}, { 6,10,30,18}, { 3, 5,35,21}}, + + {{16,48, 0,0 }, {14,42, 6, 2}, {12,36,12, 4}, {10,30,18, 6}, + {8 ,24,24,8 }, { 6,18,30,10}, { 4,12,36,12}, { 2, 6,42,14}}, + + {{ 8,56, 0,0 }, { 7,49, 7, 1}, { 6,42,14, 2}, { 5,35,21, 3}, + { 4,28,28,4 }, { 3,21,35, 5}, { 2,14,42, 6}, { 1,7 ,49, 7}} +}; + +typedef enum { + IC_FORMAT_NONE, + IC_FORMAT_RGB565, + IC_FORMAT_RGB888, + IC_FORMAT_YCbCr420_lp, + IC_FORMAT_YCbCr, + IC_FORMAT_YCbCr420_FRAME_PK, + IC_FORMAT_MAX +} enumImageFormat; + +/* This structure defines the format of an image */ +typedef struct { + mmInt32 uWidth; + mmInt32 uHeight; + mmInt32 uStride; + enumImageFormat eFormat; + mmByte *imgPtr; + mmByte *clrPtr; + mmInt32 uOffset; +} structConvImage; + +typedef struct IC_crop_struct { + mmUint32 x; /* x pos of rectangle */ + mmUint32 y; /* y pos of rectangle */ + mmUint32 uWidth; /* dx of rectangle */ + mmUint32 uHeight; /* dy of rectangle */ +} IC_rect_type; + +/*========================================================================== +* Function Name : VT_resizeFrame_Video_opt2_lp +* +* Description : Resize a yuv frame. +* +* Input(s) : input_img_ptr -> Input Image Structure +* : output_img_ptr -> Output Image Structure +* : cropout -> crop structure +* +* Value Returned : mmBool -> FALSE on error TRUE on success +* NOTE: +* Not tested for crop funtionallity. +* faster version. +============================================================================*/ +mmBool +VT_resizeFrame_Video_opt2_lp( + structConvImage* i_img_ptr, /* Points to the input image */ + structConvImage* o_img_ptr, /* Points to the output image */ + IC_rect_type* cropout, /* how much to resize to in final image */ + mmUint16 dummy /* Transparent pixel value */ + ); + +#endif //#define NV12_RESIZE_H_ diff --git a/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h b/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h new file mode 100644 index 0000000..10590df --- /dev/null +++ b/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h @@ -0,0 +1,1235 @@ +/* + * 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. + */ + + + +#ifndef OMX_CAMERA_ADAPTER_H +#define OMX_CAMERA_ADAPTER_H + +#include "CameraHal.h" +#include "OMX_Types.h" +#include "OMX_Core.h" +#include "OMX_CoreExt.h" +#include "OMX_IVCommon.h" +#include "OMX_Component.h" +#include "OMX_Index.h" +#include "OMX_IndexExt.h" +#include "OMX_TI_Index.h" +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Common.h" +#include "OMX_TI_Image.h" +#include "General3A_Settings.h" +#include "OMXSceneModeTables.h" + +#include "BaseCameraAdapter.h" +#include "Encoder_libjpeg.h" +#include "DebugUtils.h" + + +extern "C" +{ +#include "timm_osal_error.h" +#include "timm_osal_events.h" +#include "timm_osal_trace.h" +#include "timm_osal_semaphores.h" +} + + +namespace Ti { +namespace Camera { + +#define Q16_OFFSET 16 + +#define OMX_CMD_TIMEOUT 3000000 //3 sec. +#define OMX_CAPTURE_TIMEOUT 5000000 //5 sec. + +#define FOCUS_THRESHOLD 5 //[s.] + +#define MIN_JPEG_QUALITY 1 +#define MAX_JPEG_QUALITY 100 +#define EXP_BRACKET_RANGE 10 +#define ZOOM_BRACKET_RANGE 10 + +#define FOCUS_DIST_SIZE 100 +#define FOCUS_DIST_BUFFER_SIZE 500 + +#define TOUCH_DATA_SIZE 200 +#define DEFAULT_THUMB_WIDTH 160 +#define DEFAULT_THUMB_HEIGHT 120 +#define FRAME_RATE_FULL_HD 27 +#define FRAME_RATE_HIGH_HD 60 + +#define ZOOM_STAGES 61 + +#define FACE_DETECTION_BUFFER_SIZE 0x1000 +#define MAX_NUM_FACES_SUPPORTED 35 + +#define EXIF_MODEL_SIZE 100 +#define EXIF_MAKE_SIZE 100 +#define EXIF_DATE_TIME_SIZE 20 + +#define GPS_MIN_DIV 60 +#define GPS_SEC_DIV 60 +#define GPS_SEC_ACCURACY 1000 +#define GPS_TIMESTAMP_SIZE 6 +#define GPS_DATESTAMP_SIZE 11 +#define GPS_REF_SIZE 2 +#define GPS_MAPDATUM_SIZE 100 +#define GPS_PROCESSING_SIZE 100 +#define GPS_VERSION_SIZE 4 +#define GPS_NORTH_REF "N" +#define GPS_SOUTH_REF "S" +#define GPS_EAST_REF "E" +#define GPS_WEST_REF "W" + +/* Default portstartnumber of Camera component */ +#define OMX_CAMERA_DEFAULT_START_PORT_NUM 0 + +/* Define number of ports for differt domains */ +#define OMX_CAMERA_PORT_OTHER_NUM 1 +#define OMX_CAMERA_PORT_VIDEO_NUM 4 +#define OMX_CAMERA_PORT_IMAGE_NUM 1 +#define OMX_CAMERA_PORT_AUDIO_NUM 0 +#define OMX_CAMERA_NUM_PORTS (OMX_CAMERA_PORT_OTHER_NUM + OMX_CAMERA_PORT_VIDEO_NUM + OMX_CAMERA_PORT_IMAGE_NUM + OMX_CAMERA_PORT_AUDIO_NUM) + +/* Define start port number for differt domains */ +#define OMX_CAMERA_PORT_OTHER_START OMX_CAMERA_DEFAULT_START_PORT_NUM +#define OMX_CAMERA_PORT_VIDEO_START (OMX_CAMERA_PORT_OTHER_START + OMX_CAMERA_PORT_OTHER_NUM) +#define OMX_CAMERA_PORT_IMAGE_START (OMX_CAMERA_PORT_VIDEO_START + OMX_CAMERA_PORT_VIDEO_NUM) +#define OMX_CAMERA_PORT_AUDIO_START (OMX_CAMERA_PORT_IMAGE_START + OMX_CAMERA_PORT_IMAGE_NUM) + +/* Port index for camera component */ +#define OMX_CAMERA_PORT_OTHER_IN (OMX_CAMERA_PORT_OTHER_START + 0) +#define OMX_CAMERA_PORT_VIDEO_IN_VIDEO (OMX_CAMERA_PORT_VIDEO_START + 0) +#define OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW (OMX_CAMERA_PORT_VIDEO_START + 1) +#define OMX_CAMERA_PORT_VIDEO_OUT_VIDEO (OMX_CAMERA_PORT_VIDEO_START + 2) +#define OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT (OMX_CAMERA_PORT_VIDEO_START + 3) +#define OMX_CAMERA_PORT_IMAGE_OUT_IMAGE (OMX_CAMERA_PORT_IMAGE_START + 0) + + +#define OMX_INIT_STRUCT(_s_, _name_) \ + memset(&(_s_), 0x0, sizeof(_name_)); \ + (_s_).nSize = sizeof(_name_); \ + (_s_).nVersion.s.nVersionMajor = 0x1; \ + (_s_).nVersion.s.nVersionMinor = 0x1; \ + (_s_).nVersion.s.nRevision = 0x0; \ + (_s_).nVersion.s.nStep = 0x0 + +#define OMX_INIT_STRUCT_PTR(_s_, _name_) \ + memset((_s_), 0x0, sizeof(_name_)); \ + (_s_)->nSize = sizeof(_name_); \ + (_s_)->nVersion.s.nVersionMajor = 0x1; \ + (_s_)->nVersion.s.nVersionMinor = 0x1; \ + (_s_)->nVersion.s.nRevision = 0x0; \ + (_s_)->nVersion.s.nStep = 0x0 + +#define GOTO_EXIT_IF(_CONDITION,_ERROR) { \ + if ((_CONDITION)) { \ + eError = (_ERROR); \ + goto EXIT; \ + } \ +} + +const int64_t kCameraBufferLatencyNs = 250000000LL; // 250 ms + +///OMX Specific Functions +static OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + +static OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader); + +struct CapResolution { + size_t width, height; + const char *param; +}; + +struct CapPixelformat { + OMX_COLOR_FORMATTYPE pixelformat; + const char *param; +}; + +struct CapCodingFormat { + OMX_IMAGE_CODINGTYPE imageCodingFormat; + const char *param; +}; + +struct CapU32 { + OMX_U32 num; + const char *param; +}; + +struct CapS32 { + OMX_S32 num; + const char *param; +}; + +typedef CapU32 CapFramerate; +typedef CapU32 CapISO; +typedef CapU32 CapSensorName; +typedef CapS32 CapZoom; + +/** + * Class which completely abstracts the camera hardware interaction from camera hal + * TODO: Need to list down here, all the message types that will be supported by this class + Need to implement BufferProvider interface to use AllocateBuffer of OMX if needed + */ +class OMXCameraAdapter : public BaseCameraAdapter +{ +public: + + /*--------------------Constant declarations----------------------------------------*/ + static const int32_t MAX_NO_BUFFERS = 20; + + ///@remarks OMX Camera has six ports - buffer input, time input, preview, image, video, and meta data + static const int MAX_NO_PORTS = 6; + + ///Five second timeout + static const int CAMERA_ADAPTER_TIMEOUT = 5000*1000; + + enum CaptureMode + { + INITIAL_MODE = -1, + HIGH_SPEED = 1, + HIGH_QUALITY, + VIDEO_MODE, + HIGH_QUALITY_ZSL, + CP_CAM, + VIDEO_MODE_HQ, + }; + + enum IPPMode + { + IPP_NULL = -1, + IPP_NONE = 0, + IPP_NSF, + IPP_LDC, + IPP_LDCNSF, + }; + + enum CodingMode + { + CodingJPEG = 0, + CodingJPS, + CodingMPO, + }; + + enum Algorithm3A + { + WHITE_BALANCE_ALGO = 0x1, + EXPOSURE_ALGO = 0x2, + FOCUS_ALGO = 0x4, + }; + + enum AlgoPriority + { + FACE_PRIORITY = 0, + REGION_PRIORITY, + }; + + enum BrightnessMode + { + BRIGHTNESS_OFF = 0, + BRIGHTNESS_ON, + BRIGHTNESS_AUTO, + }; + + enum CaptureSettingsFlags { + SetFormat = 1 << 0, + SetThumb = 1 << 1, + SetBurstExpBracket = 1 << 2, + SetQuality = 1 << 3, + SetRotation = 1 << 4, + ECaptureSettingMax, + ECapturesettingsAll = ( ((ECaptureSettingMax -1 ) << 1) -1 ), /// all possible flags raised + ECaptureParamSettings = SetFormat | SetThumb | SetQuality | SetBurstExpBracket, // Settings set with SetParam + ECaptureConfigSettings = (ECapturesettingsAll & ~ECaptureParamSettings) + }; + + enum PreviewSettingsFlags { + SetLDC = 1 << 0, + SetNSF = 1 << 1, + SetCapMode = 1 << 2, + SetVNF = 1 << 3, + SetVSTAB = 1 << 4, + EPreviewSettingMax, + EPreviewSettingsAll = ( ((EPreviewSettingMax -1 ) << 1) -1 ) /// all possible flags raised + }; + + enum BracketingValueMode { + BracketingValueAbsolute, + BracketingValueRelative, + BracketingValueAbsoluteForced, + BracketingValueRelativeForced, + BracketingValueCompensation, + BracketingValueCompensationForced + }; + + class GPSData + { + public: + int mLongDeg, mLongMin, mLongSec, mLongSecDiv; + char mLongRef[GPS_REF_SIZE]; + bool mLongValid; + int mLatDeg, mLatMin, mLatSec, mLatSecDiv; + char mLatRef[GPS_REF_SIZE]; + bool mLatValid; + int mAltitude; + unsigned char mAltitudeRef; + bool mAltitudeValid; + char mMapDatum[GPS_MAPDATUM_SIZE]; + bool mMapDatumValid; + char mVersionId[GPS_VERSION_SIZE]; + bool mVersionIdValid; + char mProcMethod[GPS_PROCESSING_SIZE]; + bool mProcMethodValid; + char mDatestamp[GPS_DATESTAMP_SIZE]; + bool mDatestampValid; + uint32_t mTimeStampHour; + uint32_t mTimeStampMin; + uint32_t mTimeStampSec; + bool mTimeStampValid; + }; + + class EXIFData + { + public: + GPSData mGPSData; + char mMake[EXIF_MODEL_SIZE]; + char mModel[EXIF_MAKE_SIZE]; + unsigned int mFocalNum, mFocalDen; + bool mMakeValid; + bool mModelValid; + }; + + ///Parameters specific to any port of the OMX Camera component + class OMXCameraPortParameters + { + public: + //CameraBuffer * mHostBufaddr[MAX_NO_BUFFERS]; + OMX_BUFFERHEADERTYPE *mBufferHeader[MAX_NO_BUFFERS]; + OMX_U8 mStatus[MAX_NO_BUFFERS]; + OMX_U32 mWidth; + OMX_U32 mHeight; + OMX_U32 mStride; + OMX_U8 mNumBufs; + + // defines maximum number of buffers our of mNumBufs + // queueable at given moment + OMX_U8 mMaxQueueable; + + OMX_U32 mBufSize; + OMX_COLOR_FORMATTYPE mColorFormat; + OMX_PARAM_VIDEONOISEFILTERTYPE mVNFMode; + OMX_PARAM_VIDEOYUVRANGETYPE mYUVRange; + OMX_CONFIG_BOOLEANTYPE mVidStabParam; + OMX_CONFIG_FRAMESTABTYPE mVidStabConfig; + OMX_U32 mCapFrame; + OMX_U32 mFrameRate; + OMX_U32 mMinFrameRate; + OMX_U32 mMaxFrameRate; + CameraFrame::FrameType mImageType; + OMX_TI_STEREOFRAMELAYOUTTYPE mFrameLayoutType; + CameraBufferType mBufferType; + + CameraBuffer * lookup_omx_buffer (OMX_BUFFERHEADERTYPE *pBufHeader); + enum { + IDLE = 0, // buffer is neither with HAL or Ducati + FILL, // buffer is with Ducati + DONE, // buffer is filled and sent to HAL + }; + }; + + ///Context of the OMX Camera component + class OMXCameraAdapterComponentContext + { + public: + OMX_HANDLETYPE mHandleComp; + OMX_U32 mNumPorts; + OMX_STATETYPE mState ; + OMX_U32 mVideoPortIndex; + OMX_U32 mPrevPortIndex; + OMX_U32 mImagePortIndex; + OMX_U32 mMeasurementPortIndex; + OMX_U32 mVideoInPortIndex; + OMXCameraPortParameters mCameraPortParams[MAX_NO_PORTS]; + }; + + class CachedCaptureParameters + { + public: + unsigned int mPendingCaptureSettings; + unsigned int mPictureRotation; + int mExposureBracketingValues[EXP_BRACKET_RANGE]; + int mExposureGainBracketingValues[EXP_BRACKET_RANGE]; + int mExposureGainBracketingModes[EXP_BRACKET_RANGE]; + size_t mExposureBracketingValidEntries; + OMX_BRACKETMODETYPE mExposureBracketMode; + unsigned int mBurstFrames; + bool mFlushShotConfigQueue; + }; + +public: + + OMXCameraAdapter(size_t sensor_index); + ~OMXCameraAdapter(); + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const android::CameraParameters& params); + virtual void getParameters(android::CameraParameters& params); + + // API + status_t UseBuffersPreview(CameraBuffer *bufArr, int num); + + //API to flush the buffers + status_t flushBuffers(OMX_U32 port = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW); + + // API + virtual status_t setFormat(OMX_U32 port, OMXCameraPortParameters &cap); + + // Function to get and populate caps from handle + static status_t getCaps(int sensorId, CameraProperties::Properties* props, OMX_HANDLETYPE handle); + static const char* getLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT); + static int getMultipleLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT, char * supported); + static int getLUTvalue_HALtoOMX(const char * HalValue, LUTtype LUT); + + OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + + OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + + OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader); + + static OMX_ERRORTYPE OMXCameraGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData, + const OMX_CALLBACKTYPE & callbacks); + +protected: + + //Parent class method implementation + virtual status_t takePicture(); + virtual status_t stopImageCapture(); + virtual status_t startBracketing(int range); + virtual status_t stopBracketing(); + virtual status_t autoFocus(); + virtual status_t cancelAutoFocus(); + virtual status_t startSmoothZoom(int targetIdx); + virtual status_t stopSmoothZoom(); + virtual status_t startVideoCapture(); + virtual status_t stopVideoCapture(); + virtual status_t startPreview(); + virtual status_t stopPreview(); + virtual status_t useBuffers(CameraMode mode, CameraBuffer * bufArr, int num, size_t length, unsigned int queueable); + virtual status_t fillThisBuffer(CameraBuffer * frameBuf, CameraFrame::FrameType frameType); + virtual status_t getFrameSize(size_t &width, size_t &height); + virtual status_t getPictureBufferSize(CameraFrame &frame, size_t bufferCount); + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + virtual status_t startFaceDetection(); + virtual status_t stopFaceDetection(); + virtual status_t switchToExecuting(); + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); + +private: + + // Caches and returns current set of parameters + CachedCaptureParameters* cacheCaptureParameters(); + + status_t doSwitchToExecuting(); + + void performCleanupAfterError(); + + status_t switchToIdle(); + + status_t switchToLoaded(bool bPortEnableRequired = false); + status_t prevPortEnable(); + + OMXCameraPortParameters *getPortParams(CameraFrame::FrameType frameType); + + OMX_ERRORTYPE SignalEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + OMX_ERRORTYPE RemoveEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + + status_t RegisterForEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN Utils::Semaphore &semaphore); + + status_t setPictureRotation(unsigned int degree); + status_t setSensorOrientation(unsigned int degree); + status_t setImageQuality(unsigned int quality); + status_t setThumbnailParams(unsigned int width, unsigned int height, unsigned int quality); + status_t setSensorQuirks(int orientation, + OMXCameraPortParameters &portParams, + bool &portConfigured); + + status_t setupTunnel(uint32_t SliceHeight, uint32_t EncoderHandle, uint32_t width, uint32_t height); + status_t destroyTunnel(); + + //EXIF + status_t setParametersEXIF(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t convertGPSCoord(double coord, int °, int &min, int &sec, int &secDivisor); + status_t setupEXIF(); + status_t setupEXIF_libjpeg(ExifElementsTable*, OMX_TI_ANCILLARYDATATYPE*, + OMX_TI_WHITEBALANCERESULTTYPE*); + + //Focus functionality + status_t doAutoFocus(); + status_t stopAutoFocus(); + status_t checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus); + status_t returnFocusStatus(bool timeoutReached); + status_t getFocusMode(OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE &focusMode); + void handleFocusCallback(); + + + //Focus distances + status_t setParametersFocus(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t addFocusDistances(OMX_U32 &near, + OMX_U32 &optimal, + OMX_U32 &far, + android::CameraParameters& params); + status_t encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length); + status_t getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far); + + //VSTAB and VNF Functionality + status_t enableVideoNoiseFilter(bool enable); + status_t enableVideoStabilization(bool enable); + + //Digital zoom + status_t setParametersZoom(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t doZoom(int index); + status_t advanceZoom(); + + //3A related parameters + status_t setParameters3A(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + void declareParameter3ABool(const android::CameraParameters ¶ms, const char *key, + OMX_BOOL ¤t_setting, E3ASettingsFlags pending, + const char *msg); + + // scene modes + status_t setScene(Gen3A_settings& Gen3A); + // returns pointer to SceneModesEntry from the LUT for camera given 'name' and 'scene' + static const SceneModesEntry* getSceneModeEntry(const char* name, OMX_SCENEMODETYPE scene); + + + //Flash modes + status_t setFlashMode(Gen3A_settings& Gen3A); + status_t getFlashMode(Gen3A_settings& Gen3A); + + // Focus modes + status_t setFocusMode(Gen3A_settings& Gen3A); + status_t getFocusMode(Gen3A_settings& Gen3A); + + //Exposure Modes + status_t setExposureMode(Gen3A_settings& Gen3A); + status_t setManualExposureVal(Gen3A_settings& Gen3A); + status_t setEVCompensation(Gen3A_settings& Gen3A); + status_t setWBMode(Gen3A_settings& Gen3A); + status_t setFlicker(Gen3A_settings& Gen3A); + status_t setBrightness(Gen3A_settings& Gen3A); + status_t setContrast(Gen3A_settings& Gen3A); + status_t setSharpness(Gen3A_settings& Gen3A); + status_t setSaturation(Gen3A_settings& Gen3A); + status_t setISO(Gen3A_settings& Gen3A); + status_t setEffect(Gen3A_settings& Gen3A); + status_t setMeteringAreas(Gen3A_settings& Gen3A); + + //TI extensions for enable/disable algos + status_t setParameter3ABool(const OMX_INDEXTYPE omx_idx, + const OMX_BOOL data, const char *msg); + status_t setParameter3ABoolInvert(const OMX_INDEXTYPE omx_idx, + const OMX_BOOL data, const char *msg); + status_t setAlgoExternalGamma(Gen3A_settings& Gen3A); +#ifndef MOTOROLA_CAMERA + status_t setAlgoNSF1(Gen3A_settings& Gen3A); + status_t setAlgoNSF2(Gen3A_settings& Gen3A); + status_t setAlgoSharpening(Gen3A_settings& Gen3A); + status_t setAlgoThreeLinColorMap(Gen3A_settings& Gen3A); + status_t setAlgoGIC(Gen3A_settings& Gen3A); + + //Gamma table + void updateGammaTable(const char* gamma); + status_t setGammaTable(Gen3A_settings& Gen3A); +#endif + + status_t getEVCompensation(Gen3A_settings& Gen3A); + status_t getWBMode(Gen3A_settings& Gen3A); + status_t getSharpness(Gen3A_settings& Gen3A); + status_t getSaturation(Gen3A_settings& Gen3A); + status_t getISO(Gen3A_settings& Gen3A); + + // 3A locks + status_t setExposureLock(Gen3A_settings& Gen3A); + status_t setFocusLock(Gen3A_settings& Gen3A); + status_t setWhiteBalanceLock(Gen3A_settings& Gen3A); + status_t set3ALock(OMX_BOOL toggleExp, OMX_BOOL toggleWb, OMX_BOOL toggleFocus); + + //Stereo 3D + void setParamS3D(OMX_U32 port, const char *valstr); + status_t setS3DFrameLayout(OMX_U32 port) const; + + //API to set FrameRate using VFR interface + status_t setVFramerate(OMX_U32 minFrameRate,OMX_U32 maxFrameRate); + + status_t setParametersAlgo(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + + //Noise filtering + status_t setNSF(OMXCameraAdapter::IPPMode mode); + + //LDC + status_t setLDC(OMXCameraAdapter::IPPMode mode); + + //GLBCE + status_t setGLBCE(OMXCameraAdapter::BrightnessMode mode); + + //GBCE + status_t setGBCE(OMXCameraAdapter::BrightnessMode mode); + + status_t printComponentVersion(OMX_HANDLETYPE handle); + + //Touch AF + status_t setTouchFocus(); + + //Face detection + status_t setParametersFD(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t updateFocusDistances(android::CameraParameters ¶ms); + status_t setFaceDetectionOrientation(OMX_U32 orientation); + status_t setFaceDetection(bool enable, OMX_U32 orientation); + status_t createPreviewMetadata(OMX_BUFFERHEADERTYPE* pBuffHeader, + android::sp &result, + size_t previewWidth, + size_t previewHeight); + status_t encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData, + camera_frame_metadata_t *metadataResult, + size_t previewWidth, + size_t previewHeight); + status_t encodePreviewMetadata(camera_frame_metadata_t *meta, const OMX_PTR plat_pvt); + + void pauseFaceDetection(bool pause); + + //3A Algorithms priority configuration + status_t setAlgoPriority(AlgoPriority priority, Algorithm3A algo, bool enable); + + //Sensor overclocking + status_t setSensorOverclock(bool enable); + + // Utility methods for OMX Capabilities + static bool _checkOmxTiCap(const OMX_TI_CAPTYPE & caps); + static bool _dumpOmxTiCap(int sensorId, const OMX_TI_CAPTYPE & caps); + + static status_t insertCapabilities(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t encodeSizeCap(OMX_TI_CAPRESTYPE&, const CapResolution *, size_t, char *, size_t); + static status_t encodeISOCap(OMX_U32, const CapISO*, size_t, char*, size_t); + static size_t encodeZoomCap(OMX_S32, const CapZoom*, size_t, char*, size_t); + static void encodeFrameRates(int minFrameRate, int maxFrameRate, const OMX_TI_CAPTYPE & caps, + const CapFramerate * fixedFrameRates, int frameRateCount, android::Vector & fpsRanges); + static status_t encodeImageCodingFormatCap(OMX_IMAGE_CODINGTYPE, + const CapCodingFormat *, + size_t, + char *); + static status_t encodePixelformatCap(OMX_COLOR_FORMATTYPE, + const CapPixelformat*, + size_t, + char*, + size_t); + static status_t encodeSizeCap3D(OMX_TI_CAPRESTYPE&, + const CapResolution*, + size_t , + char * , + size_t); + static status_t insertImageSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertPreviewSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertThumbSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertZoomStages(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertImageFormats(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertPreviewFormats(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFramerates(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertEVs(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertISOModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertIPPModes(CameraProperties::Properties*, OMX_TI_CAPTYPE &); + static status_t insertWBModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertEffects(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertExpModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertManualExpRanges(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertSceneModes(CameraProperties::Properties*, OMX_TI_CAPTYPE &); + static status_t insertFocusModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFlickerModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFlashModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertSenMount(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertDefaults(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertLocks(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertAreas(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertMechanicalMisalignmentCorrection(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertCaptureModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertVideoSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFacing(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFocalLength(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertAutoConvergenceModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertManualConvergenceRange(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertLayout(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertVideoSnapshotSupported(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertVNFSupported(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps); + static status_t insertVSTABSupported(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps); + static status_t insertGBCESupported(CameraProperties::Properties* params, + const OMX_TI_CAPTYPE &caps); + static status_t insertGLBCESupported(CameraProperties::Properties* params, + const OMX_TI_CAPTYPE &caps); + static status_t insertRaw(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + + status_t setParametersCapture(const android::CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + + //Exposure Bracketing + status_t initVectorShot(); + status_t setVectorShot(int *evValues, int *evValues2, int *evModes2, + size_t evCount, size_t frameCount, + bool flush, OMX_BRACKETMODETYPE bracketMode); + status_t setVectorStop(bool toPreview = false); + status_t setExposureBracketing(int *evValues, int *evValues2, + size_t evCount, size_t frameCount, + OMX_BRACKETMODETYPE bracketMode); + status_t doExposureBracketing(int *evValues, int *evValues2, + int *evModes2, + size_t evCount, size_t frameCount, + bool flush, + OMX_BRACKETMODETYPE bracketMode); + int getBracketingValueMode(const char *a, const char *b) const; + status_t parseExpRange(const char *rangeStr, int *expRange, int *gainRange, + int *expGainModes, + size_t count, size_t &validEntries); + + //Temporal Bracketing + status_t doBracketing(OMX_BUFFERHEADERTYPE *pBuffHeader, CameraFrame::FrameType typeOfFrame); + status_t sendBracketFrames(size_t &framesSent); + + // Image Capture Service + status_t startImageCapture(bool bracketing, CachedCaptureParameters*); + status_t disableImagePort(); + + //Shutter callback notifications + status_t setShutterCallback(bool enabled); + + //Sets eithter HQ or HS mode and the frame count + status_t setCaptureMode(OMXCameraAdapter::CaptureMode mode); + status_t UseBuffersCapture(CameraBuffer *bufArr, int num); + status_t UseBuffersPreviewData(CameraBuffer *bufArr, int num); + status_t UseBuffersRawCapture(CameraBuffer *bufArr, int num); + + //Used for calculation of the average frame rate during preview + status_t recalculateFPS(); + + //Sends the incoming OMX buffer header to subscribers + status_t sendCallBacks(CameraFrame frame, OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, unsigned int mask, OMXCameraPortParameters *port); + + status_t apply3Asettings( Gen3A_settings& Gen3A ); + + // AutoConvergence + status_t setAutoConvergence(const char *valstr, const char *pValManualstr, const android::CameraParameters ¶ms); + + status_t setExtraData(bool enable, OMX_U32, OMX_EXT_EXTRADATATYPE); + OMX_OTHER_EXTRADATATYPE *getExtradata(const OMX_PTR ptrPrivate, OMX_EXTRADATATYPE type) const; + + // Meta data +#ifdef OMAP_ENHANCEMENT_CPCAM + camera_memory_t * getMetaData(const OMX_PTR plat_pvt, + camera_request_memory allocator) const; +#endif + + // Mechanical Misalignment Correction + status_t setMechanicalMisalignmentCorrection(bool enable); + + // DCC file data save + status_t initDccFileDataSave(OMX_HANDLETYPE* omxHandle, int portIndex); + status_t sniffDccFileDataSave(OMX_BUFFERHEADERTYPE* pBuffHeader); + status_t saveDccFileDataSave(); + status_t closeDccFileDataSave(); + status_t fseekDCCuseCasePos(FILE *pFile); + FILE * fopenCameraDCC(const char *dccFolderPath); + FILE * parseDCCsubDir(DIR *pDir, char *path); + +#ifdef CAMERAHAL_OMX_PROFILING + status_t storeProfilingData(OMX_BUFFERHEADERTYPE* pBuffHeader); +#endif + + // Internal buffers + status_t initInternalBuffers (OMX_U32); + status_t deinitInternalBuffers (OMX_U32); + + // Reprocess Methods -- implementation in OMXReprocess.cpp + status_t setParametersReprocess(const android::CameraParameters ¶ms, CameraBuffer* bufs, + BaseCameraAdapter::AdapterState state); + status_t startReprocess(); + status_t disableReprocess(); + status_t stopReprocess(); + status_t UseBuffersReprocess(CameraBuffer *bufArr, int num); + + class CommandHandler : public android::Thread { + public: + CommandHandler(OMXCameraAdapter* ca) + : android::Thread(false), mCameraAdapter(ca) { } + + virtual bool threadLoop() { + bool ret; + ret = Handler(); + return ret; + } + + status_t put(Utils::Message* msg){ + android::AutoMutex lock(mLock); + return mCommandMsgQ.put(msg); + } + + void clearCommandQ() + { + android::AutoMutex lock(mLock); + mCommandMsgQ.clear(); + } + + enum { + COMMAND_EXIT = -1, + CAMERA_START_IMAGE_CAPTURE = 0, + CAMERA_PERFORM_AUTOFOCUS, + CAMERA_SWITCH_TO_EXECUTING, + CAMERA_START_REPROCESS + }; + + private: + bool Handler(); + Utils::MessageQueue mCommandMsgQ; + OMXCameraAdapter* mCameraAdapter; + android::Mutex mLock; + }; + android::sp mCommandHandler; + +#ifdef MOTOROLA_CAMERA + status_t setLedFlash(int nLedFlashIntensP); + status_t setLedTorch(int nLedTorchIntensP); +#endif + +public: + +#ifdef MOTOROLA_CAMERA + status_t getOTPEeprom(unsigned char * pData, unsigned long nSize); +#endif + + class OMXCallbackHandler : public android::Thread { + public: + OMXCallbackHandler(OMXCameraAdapter* ca) + : Thread(false), mCameraAdapter(ca) + { + mIsProcessed = true; + } + + virtual bool threadLoop() { + bool ret; + ret = Handler(); + return ret; + } + + status_t put(Utils::Message* msg){ + android::AutoMutex lock(mLock); + mIsProcessed = false; + return mCommandMsgQ.put(msg); + } + + void clearCommandQ() + { + android::AutoMutex lock(mLock); + mCommandMsgQ.clear(); + } + + void flush(); + + enum { + COMMAND_EXIT = -1, + CAMERA_FILL_BUFFER_DONE, + CAMERA_FOCUS_STATUS + }; + + private: + bool Handler(); + Utils::MessageQueue mCommandMsgQ; + OMXCameraAdapter* mCameraAdapter; + android::Mutex mLock; + android::Condition mCondition; + bool mIsProcessed; + }; + + android::sp mOMXCallbackHandler; + +private: + + //AF callback + status_t setFocusCallback(bool enabled); + + //OMX Capabilities data + static const CapResolution mImageCapRes []; + static const CapResolution mImageCapResSS []; + static const CapResolution mImageCapResTB []; + static const CapResolution mPreviewRes []; + static const CapResolution mPreviewResSS []; + static const CapResolution mPreviewResTB []; + static const CapResolution mPreviewPortraitRes []; + static const CapResolution mThumbRes []; + static const CapPixelformat mPixelformats []; + static const userToOMX_LUT mFrameLayout []; + static const LUTtype mLayoutLUT; + static const CapCodingFormat mImageCodingFormat[]; + static const CapFramerate mFramerates []; + static const CapU32 mSensorNames[] ; + static const CapZoom mZoomStages []; + static const CapISO mISOStages []; + static const int SENSORID_IMX060; + static const int SENSORID_OV5650; + static const int SENSORID_OV5640; + static const int SENSORID_OV14825; + static const int SENSORID_S5K4E1GA; + static const int SENSORID_S5K6A1GX03; + static const int SENSORID_OV8830; + static const int SENSORID_OV2722; + static const int SENSORID_OV9726; +#ifdef MOTOROLA_CAMERA + static const int SENSORID_OV8820; + static const int SENSORID_MT9M114; +#endif + static const CapU32 mFacing []; + static const userToOMX_LUT mAutoConvergence []; + static const LUTtype mAutoConvergenceLUT; + static const userToOMX_LUT mBracketingModes[]; + static const LUTtype mBracketingModesLUT; + + static const int FPS_MIN; + static const int FPS_MAX; + static const int FPS_MAX_EXTENDED; + + // OMX Camera defaults + static const char DEFAULT_ANTIBANDING[]; + static const char DEFAULT_BRIGHTNESS[]; + static const char DEFAULT_CONTRAST[]; + static const char DEFAULT_EFFECT[]; + static const char DEFAULT_EV_COMPENSATION[]; + static const char DEFAULT_EV_STEP[]; + static const char DEFAULT_EXPOSURE_MODE[]; + static const char DEFAULT_FLASH_MODE[]; + static const char DEFAULT_FOCUS_MODE_PREFERRED[]; + static const char DEFAULT_FOCUS_MODE[]; + static const char DEFAULT_IPP[]; + static const char DEFAULT_ISO_MODE[]; + static const char DEFAULT_JPEG_QUALITY[]; + static const char DEFAULT_THUMBNAIL_QUALITY[]; + static const char DEFAULT_THUMBNAIL_SIZE[]; + static const char DEFAULT_PICTURE_FORMAT[]; + static const char DEFAULT_S3D_PICTURE_LAYOUT[]; + static const char DEFAULT_PICTURE_SIZE[]; + static const char DEFAULT_PICTURE_SS_SIZE[]; + static const char DEFAULT_PICTURE_TB_SIZE[]; + static const char DEFAULT_PREVIEW_FORMAT[]; + static const char DEFAULT_FRAMERATE[]; + static const char DEFAULT_S3D_PREVIEW_LAYOUT[]; + static const char DEFAULT_PREVIEW_SIZE[]; + static const char DEFAULT_PREVIEW_SS_SIZE[]; + static const char DEFAULT_PREVIEW_TB_SIZE[]; + static const char DEFAULT_NUM_PREV_BUFS[]; + static const char DEFAULT_NUM_PIC_BUFS[]; + static const char DEFAULT_SATURATION[]; + static const char DEFAULT_SCENE_MODE[]; + static const char DEFAULT_SHARPNESS[]; + static const char * DEFAULT_VSTAB; + static const char * DEFAULT_VNF; + static const char DEFAULT_WB[]; + static const char DEFAULT_ZOOM[]; + static const char DEFAULT_MAX_FD_HW_FACES[]; + static const char DEFAULT_MAX_FD_SW_FACES[]; + static const char * DEFAULT_AE_LOCK; + static const char * DEFAULT_AWB_LOCK; + static const char DEFAULT_HOR_ANGLE[]; + static const char DEFAULT_VER_ANGLE[]; + static const char DEFAULT_VIDEO_SIZE[]; + static const char DEFAULT_SENSOR_ORIENTATION[]; + static const char DEFAULT_AUTOCONVERGENCE_MODE[]; + static const char DEFAULT_MANUAL_CONVERGENCE[]; + static const char * DEFAULT_MECHANICAL_MISALIGNMENT_CORRECTION_MODE; + static const char DEFAULT_EXIF_MODEL[]; + static const char DEFAULT_EXIF_MAKE[]; + + static const size_t MAX_FOCUS_AREAS; + +#ifdef CAMERAHAL_OMX_PROFILING + + static const char DEFAULT_PROFILE_PATH[]; + int mDebugProfile; + +#endif + + OMX_VERSIONTYPE mCompRevision; + + //OMX Component UUID + OMX_UUIDTYPE mCompUUID; + + //Current Focus distances + char mFocusDistNear[FOCUS_DIST_SIZE]; + char mFocusDistOptimal[FOCUS_DIST_SIZE]; + char mFocusDistFar[FOCUS_DIST_SIZE]; + char mFocusDistBuffer[FOCUS_DIST_BUFFER_SIZE]; + + // Current Focus areas + android::Vector > mFocusAreas; + mutable android::Mutex mFocusAreasLock; + + // Current Touch convergence areas + android::Vector > mTouchAreas; + mutable android::Mutex mTouchAreasLock; + + // Current Metering areas + android::Vector > mMeteringAreas; + mutable android::Mutex mMeteringAreasLock; + + OperatingMode mCapabilitiesOpMode; + CaptureMode mCapMode; + // TODO(XXX): Do we really need this lock? Let's + // try to merge temporal bracketing and burst + // capture later + mutable android::Mutex mBurstLock; + size_t mBurstFrames; + size_t mBurstFramesAccum; + size_t mBurstFramesQueued; + size_t mCapturedFrames; + bool mFlushShotConfigQueue; + + bool mMeasurementEnabled; + + //Exposure Bracketing + int mExposureBracketingValues[EXP_BRACKET_RANGE]; + int mExposureGainBracketingValues[EXP_BRACKET_RANGE]; + int mExposureGainBracketingModes[EXP_BRACKET_RANGE]; + size_t mExposureBracketingValidEntries; + OMX_BRACKETMODETYPE mExposureBracketMode; + + //Zoom Bracketing + int mZoomBracketingValues[ZOOM_BRACKET_RANGE]; + size_t mZoomBracketingValidEntries; + + static const uint32_t FACE_DETECTION_THRESHOLD; + mutable android::Mutex mFaceDetectionLock; + //Face detection status + bool mFaceDetectionRunning; + bool mFaceDetectionPaused; + bool mFDSwitchAlgoPriority; + + camera_face_t faceDetectionLastOutput[MAX_NUM_FACES_SUPPORTED]; + int faceDetectionNumFacesLastOutput; + int metadataLastAnalogGain; + int metadataLastExposureTime; + + //Geo-tagging + EXIFData mEXIFData; + + //Image post-processing + IPPMode mIPP; + + //jpeg Picture Quality + unsigned int mPictureQuality; + + //thumbnail resolution + unsigned int mThumbWidth, mThumbHeight; + + //thumbnail quality + unsigned int mThumbQuality; + + //variables holding the estimated framerate + float mFPS, mLastFPS; + + //automatically disable AF after a given amount of frames + unsigned int mFocusThreshold; + + //This is needed for the CTS tests. They falsely assume, that during + //smooth zoom the current zoom stage will not change within the + //zoom callback scope, which in a real world situation is not always the + //case. This variable will "simulate" the expected behavior + unsigned int mZoomParameterIdx; + + //current zoom + android::Mutex mZoomLock; + unsigned int mCurrentZoomIdx, mTargetZoomIdx, mPreviousZoomIndx; + bool mZoomUpdating, mZoomUpdate; + int mZoomInc; + bool mReturnZoomStatus; + static const int32_t ZOOM_STEPS []; + + //local copy + OMX_VERSIONTYPE mLocalVersionParam; + + unsigned int mPending3Asettings; + android::Mutex m3ASettingsUpdateLock; + Gen3A_settings mParameters3A; + const char *mPictureFormatFromClient; + + BrightnessMode mGBCE; + BrightnessMode mGLBCE; + + OMX_TI_CONFIG_3A_FACE_PRIORITY mFacePriority; + OMX_TI_CONFIG_3A_REGION_PRIORITY mRegionPriority; + + android::CameraParameters mParams; + CameraProperties::Properties* mCapabilities; + unsigned int mPictureRotation; + bool mWaitingForSnapshot; + bool mCaptureConfigured; + unsigned int mPendingCaptureSettings; + unsigned int mPendingPreviewSettings; + unsigned int mPendingReprocessSettings; + OMX_TI_ANCILLARYDATATYPE* mCaptureAncillaryData; + OMX_TI_WHITEBALANCERESULTTYPE* mWhiteBalanceData; + bool mReprocConfigured; + + //Temporal bracketing management data + bool mBracketingSet; + mutable android::Mutex mBracketingLock; + bool *mBracketingBuffersQueued; + int mBracketingBuffersQueuedCount; + int mLastBracetingBufferIdx; + bool mBracketingEnabled; + bool mZoomBracketingEnabled; + size_t mBracketingRange; + int mCurrentZoomBracketing; + android::CameraParameters mParameters; + +#ifdef CAMERAHAL_TUNA + bool mIternalRecordingHint; +#endif + + bool mOmxInitialized; + OMXCameraAdapterComponentContext mCameraAdapterParameters; + bool mFirstTimeInit; + + ///Semaphores used internally + Utils::Semaphore mInitSem; + Utils::Semaphore mFlushSem; + Utils::Semaphore mUsePreviewDataSem; + Utils::Semaphore mUsePreviewSem; + Utils::Semaphore mUseCaptureSem; + Utils::Semaphore mStartPreviewSem; + Utils::Semaphore mStopPreviewSem; + Utils::Semaphore mStartCaptureSem; + Utils::Semaphore mStopCaptureSem; + Utils::Semaphore mSwitchToLoadedSem; + Utils::Semaphore mSwitchToExecSem; + Utils::Semaphore mStopReprocSem; + Utils::Semaphore mUseReprocessSem; + + mutable android::Mutex mStateSwitchLock; + mutable android::Mutex mIdleStateSwitchLock; + + android::Vector mEventSignalQ; + android::Mutex mEventLock; + + OMX_STATETYPE mComponentState; + + OMX_TI_AUTOCONVERGENCEMODETYPE mAutoConv; + OMX_S32 mManualConv; + bool mVnfEnabled; + bool mVstabEnabled; + + int mSensorOrientation; + int mDeviceOrientation; + int mFaceOrientation; + bool mSensorOverclock; + + //Indicates if we should leave + //OMX_Executing state during + //stop-/startPreview + bool mOMXStateSwitch; + + int mFrameCount; + int mLastFrameCount; + unsigned int mIter; + nsecs_t mLastFPSTime; + android::Mutex mFrameCountMutex; + android::Condition mFirstFrameCondition; + + static const nsecs_t CANCEL_AF_TIMEOUT; + android::Mutex mCancelAFMutex; + android::Condition mCancelAFCond; + + android::Mutex mDoAFMutex; + android::Condition mDoAFCond; + + size_t mSensorIndex; + CodingMode mCodingMode; + + // Time source delta of ducati & system time + OMX_TICKS mTimeSourceDelta; + bool onlyOnce; + + Utils::Semaphore mCaptureSem; + bool mCaptureSignalled; + + OMX_BOOL mUserSetExpLock; + OMX_BOOL mUserSetWbLock; + +#ifdef CAMERAHAL_USE_RAW_IMAGE_SAVING + bool mRawCapture; + bool mYuvCapture; +#endif + + bool mSetFormatDone; + + OMX_TI_DCCDATATYPE mDccData; + android::Mutex mDccDataLock; + + int mMaxZoomSupported; + android::Mutex mImageCaptureLock; + + bool mTunnelDestroyed; + bool mPreviewPortInitialized; + + // Used for allocations that need to be sent to Ducati + MemoryManager mMemMgr; +}; + +} // namespace Camera +} // namespace Ti + +#endif //OMX_CAMERA_ADAPTER_H diff --git a/camera/inc/OMXCameraAdapter/OMXDCC.h b/camera/inc/OMXCameraAdapter/OMXDCC.h new file mode 100644 index 0000000..c75a24d --- /dev/null +++ b/camera/inc/OMXCameraAdapter/OMXDCC.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef OMX_DCC_H +#define OMX_DCC_H + +namespace Ti { +namespace Camera { + +class DCCHandler +{ +public: + + status_t loadDCC(OMX_HANDLETYPE hComponent); + +private: + + OMX_ERRORTYPE initDCC(OMX_HANDLETYPE hComponent); + OMX_ERRORTYPE sendDCCBufPtr(OMX_HANDLETYPE hComponent, CameraBuffer *dccBuffer); + size_t readDCCdir(OMX_PTR buffer, const android::Vector &dirPaths); + +private: + + static android::String8 DCCPath; + static bool mDCCLoaded; +}; + +} // namespace Camera +} // namespace Ti + +#endif // OMX_DCC_H diff --git a/camera/inc/OMXCameraAdapter/OMXSceneModeTables.h b/camera/inc/OMXCameraAdapter/OMXSceneModeTables.h new file mode 100644 index 0000000..6ac9f2b --- /dev/null +++ b/camera/inc/OMXCameraAdapter/OMXSceneModeTables.h @@ -0,0 +1,759 @@ +/* + * 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. + */ + +/** +* @file OMXSceneModeTables.h +* +* This holds scene mode settings for different omx cameras. +* +*/ + +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Common.h" +#include "OMX_TI_Index.h" + +#ifndef OMXCAMERAADAPTER_SCENEMODES_H +#define OMXCAMERAADAPTER_SCENEMODES_H + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) +#endif + +namespace Ti { +namespace Camera { + +struct SceneModesEntry { + OMX_SCENEMODETYPE scene; + OMX_IMAGE_FLASHCONTROLTYPE flash; + int focus; + OMX_WHITEBALCONTROLTYPE wb; +}; + +struct CameraToSensorModesLUTEntry { + const char* name; + const SceneModesEntry* Table; + const unsigned int size; +}; + +static const SceneModesEntry S5K4E1GA_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Underwater, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlSunLight }, + { OMX_Sport, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlPortrait, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOn, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAuto, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAuto, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAuto, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlPortrait, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAuto, + OMX_WhiteBalControlSunLight }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry S5K6A1GX03_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Underwater, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Sport, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry IMX060_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Underwater, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Sport, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlPortrait, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOn, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoMacro, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoInfinity, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + ( OMX_WHITEBALCONTROLTYPE ) OMX_TI_WhiteBalControlSunset }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry OV5640_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Underwater, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Sport, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlAutoInfinity, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry OV5650_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Underwater, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Sport, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlPortrait, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOn, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoInfinity, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + ( OMX_WHITEBALCONTROLTYPE ) OMX_TI_WhiteBalControlSunset }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry OV8830_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Underwater, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Sport, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlPortrait, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOn, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoInfinity, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoLock, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + ( OMX_WHITEBALCONTROLTYPE ) OMX_TI_WhiteBalControlSunset }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const SceneModesEntry OV2722_SceneModesLUT [] = { + { OMX_Closeup, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Landscape, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlSunLight }, + { OMX_Underwater, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Sport, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SnowBeach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Mood, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightPortrait, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_NightIndoor, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Fireworks, + OMX_IMAGE_FlashControlOn, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Document, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_Barcode, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_SuperNight, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlAutoInfinity, + OMX_WhiteBalControlAuto }, + { OMX_Cine, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_OldFilm, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Action, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Beach, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Candlelight, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlIncandescent }, + { OMX_TI_Night, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Party, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Portrait, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Snow, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Steadyphoto, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, + { OMX_TI_Sunset, + OMX_IMAGE_FlashControlAuto, + OMX_IMAGE_FocusControlHyperfocal, + ( OMX_WHITEBALCONTROLTYPE ) OMX_TI_WhiteBalControlSunset }, + { OMX_TI_Theatre, + OMX_IMAGE_FlashControlOff, + OMX_IMAGE_FocusControlHyperfocal, + OMX_WhiteBalControlAuto }, +}; + +static const CameraToSensorModesLUTEntry CameraToSensorModesLUT [] = { + { "S5K4E1GA", S5K4E1GA_SceneModesLUT, ARRAY_SIZE(S5K4E1GA_SceneModesLUT)}, + { "S5K6A1GX03", S5K6A1GX03_SceneModesLUT, ARRAY_SIZE(S5K6A1GX03_SceneModesLUT)}, + { "IMX060", IMX060_SceneModesLUT, ARRAY_SIZE(IMX060_SceneModesLUT)}, + { "OV5640", OV5640_SceneModesLUT, ARRAY_SIZE(OV5640_SceneModesLUT)}, + { "OV5650", OV5650_SceneModesLUT, ARRAY_SIZE(OV5650_SceneModesLUT)}, + { "OV8830", OV8830_SceneModesLUT, ARRAY_SIZE(OV8830_SceneModesLUT)}, + { "OV9726", OV2722_SceneModesLUT, ARRAY_SIZE(OV2722_SceneModesLUT)}, + { "OV2722", OV2722_SceneModesLUT, ARRAY_SIZE(OV2722_SceneModesLUT)}, +#ifdef MOTOROLA_CAMERA + { "OV8820", OV8830_SceneModesLUT, ARRAY_SIZE(OV8830_SceneModesLUT)}, + { "OV7739", OV2722_SceneModesLUT, ARRAY_SIZE(OV2722_SceneModesLUT)}, + { "MT9M114", OV2722_SceneModesLUT, ARRAY_SIZE(OV2722_SceneModesLUT)}, +#endif +}; + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/inc/OmxFrameDecoder.h b/camera/inc/OmxFrameDecoder.h new file mode 100644 index 0000000..7cbbf2c --- /dev/null +++ b/camera/inc/OmxFrameDecoder.h @@ -0,0 +1,204 @@ +/* + * 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. + */ + +#ifndef OMXFRAMEDECODER_H_ +#define OMXFRAMEDECODER_H_ + + +#include +#include +#include "FrameDecoder.h" +#include "OMX_Types.h" +#include "OMX_Core.h" +#include "OMX_Component.h" +#include "Decoder_libjpeg.h" + +namespace Ti { +namespace Camera { + +enum OmxDecoderState { + OmxDecoderState_Unloaded = 0, + OmxDecoderState_Loaded, + OmxDecoderState_Idle, + OmxDecoderState_Executing, + OmxDecoderState_Error, + OmxDecoderState_Invalid, + OmxDecoderState_Reconfigure, + OmxDecoderState_Exit +}; + +enum PortType { + PortIndexInput = 0, + PortIndexOutput = 1 +}; + + +struct OmxMessage { + enum { + EVENT, + EMPTY_BUFFER_DONE, + FILL_BUFFER_DONE, + }type; + + union { + // if type == EVENT + struct { + OMX_PTR appData; + OMX_EVENTTYPE event; + OMX_U32 data1; + OMX_U32 data2; + OMX_PTR pEventData; + } eventData; + + // if type == (EMPTY_BUFFER_DONE || FILL_BUFFER_DONE) + struct { + OMX_PTR appData; + OMX_BUFFERHEADERTYPE* pBuffHead; + } bufferData; + } u; +}; + +class CallbackDispatcher; + +struct CallbackDispatcherThread : public android::Thread { + CallbackDispatcherThread(CallbackDispatcher *dispatcher) + : mDispatcher(dispatcher) { + } + +private: + CallbackDispatcher *mDispatcher; + + bool threadLoop(); + + CallbackDispatcherThread(const CallbackDispatcherThread &); + CallbackDispatcherThread &operator=(const CallbackDispatcherThread &); +}; + +class CallbackDispatcher +{ + +public: + CallbackDispatcher(); + ~CallbackDispatcher(); + + void post(const OmxMessage &msg); + bool loop(); + +private: + void dispatch(const OmxMessage &msg); + + CallbackDispatcher(const CallbackDispatcher &); + CallbackDispatcher &operator=(const CallbackDispatcher &); + + android::Mutex mLock; + android::Condition mQueueChanged; + android::List mQueue; + android::sp mThread; + bool mDone; +}; + +class OmxFrameDecoder : public FrameDecoder +{ + +public: + OmxFrameDecoder(DecoderType type = DecoderType_MJPEG); + virtual ~OmxFrameDecoder(); + + OMX_ERRORTYPE eventHandler(const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2, + const OMX_PTR pEventData); + OMX_ERRORTYPE fillBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead); + OMX_ERRORTYPE emptyBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead); + + static OMX_ERRORTYPE eventCallback(const OMX_HANDLETYPE component, + const OMX_PTR appData, const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2, + const OMX_PTR pEventData); + static OMX_ERRORTYPE emptyBufferDoneCallback(OMX_HANDLETYPE hComponent, OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead); + static OMX_ERRORTYPE fillBufferDoneCallback(OMX_HANDLETYPE hComponent, OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead); + + virtual bool getPaddedDimensions(size_t &width, size_t &height); + +protected: + virtual void doConfigure (const DecoderParameters& config); + virtual void doProcessInputBuffer(); + virtual status_t doStart(); + virtual void doStop(); + virtual void doFlush(); + virtual void doRelease(); + +private: + status_t setComponentRole(); + status_t enableGrallockHandles(); + status_t allocateBuffersOutput(); + void freeBuffersOnOutput(); + void freeBuffersOnInput(); + status_t doPortReconfigure(); + void dumpPortSettings(PortType port); + status_t getAndConfigureDecoder(); + status_t configureJpegPorts(int width, int height); + status_t switchToIdle(); + status_t allocateBuffersInput(); + status_t disablePortSync(int port); + status_t enablePortSync(int port); + void queueOutputBuffers(); + status_t setVideoOutputFormat(OMX_U32 width, OMX_U32 height); + + + status_t omxInit(); + status_t omxGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData, OMX_CALLBACKTYPE & callbacks); + OmxDecoderState getOmxState() { return mCurrentState; } + status_t commitState(OmxDecoderState state) { mPreviousState = mCurrentState; mCurrentState = state; return NO_ERROR; } + status_t setVideoPortFormatType( + OMX_U32 portIndex, + OMX_VIDEO_CODINGTYPE compressionFormat, + OMX_COLOR_FORMATTYPE colorFormat); + status_t omxGetParameter(OMX_INDEXTYPE index, OMX_PTR ptr); + status_t omxSetParameter(OMX_INDEXTYPE index, OMX_PTR ptr); + status_t omxSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param); + status_t omxGetConfig(OMX_INDEXTYPE index, OMX_PTR ptr); + status_t omxSetConfig(OMX_INDEXTYPE index, OMX_PTR ptr); + status_t omxFillThisBuffer(OMX_BUFFERHEADERTYPE *pOutBufHdr); + status_t omxEmptyThisBuffer(android::sp& inBuffer, OMX_BUFFERHEADERTYPE *pInBufHdr); + void omxDumpPortSettings(OMX_PARAM_PORTDEFINITIONTYPE& def); + void omxDumpBufferHeader (OMX_BUFFERHEADERTYPE* bh); + status_t omxSwitchToExecutingSync(); + + bool mOmxInialized; + + OMX_HANDLETYPE mHandleComp; + OmxDecoderState mCurrentState; + OmxDecoderState mPreviousState; + + // Condition and Mutex used during OpenMAX state transitions & command completion + android::Condition mStateCondition; + android::Mutex mHwLock; + + android::Vector mOutBufferHeaders; + android::Vector mInBufferHeaders; + + CallbackDispatcher mDispatcher; + + bool mStopping; + DecoderType mDecoderType; + + // If true we will search for DHT in JPEG buffer + bool mIsNeedCheckDHT; + // If true we always append DHT to JPEG buffer + bool mAlwaysAppendDHT; +}; + +} //namespace Camera +} //namespace Ti +#endif /* OMXFRAMEDECODER_H_ */ diff --git a/camera/inc/SensorListener.h b/camera/inc/SensorListener.h new file mode 100644 index 0000000..44037b7 --- /dev/null +++ b/camera/inc/SensorListener.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** +* @file SensorListener.h +* +* This defines API for camerahal to get sensor events +* +*/ + +#ifndef ANDROID_CAMERA_HARDWARE_SENSOR_LISTENER_H +#define ANDROID_CAMERA_HARDWARE_SENSOR_LISTENER_H + +#include +#include +#include +#include +#include + +#include "Common.h" + +namespace Ti { +namespace Camera { + +/** + * SensorListner class - Registers with sensor manager to get sensor events + */ + +typedef void (*orientation_callback_t) (uint32_t orientation, uint32_t tilt, void* cookie); + +class SensorLooperThread : public android::Thread { + public: + SensorLooperThread(android::Looper* looper) + : Thread(false) { + mLooper = android::sp(looper); + } + ~SensorLooperThread() { + mLooper.clear(); + } + + virtual bool threadLoop() { + int32_t ret = mLooper->pollOnce(-1); + return true; + } + + // force looper wake up + void wake() { + mLooper->wake(); + } + private: + android::sp mLooper; +}; + + +class SensorListener : public android::RefBase +{ +/* public - types */ +public: + typedef enum { + SENSOR_ACCELEROMETER = 1 << 0, + SENSOR_MAGNETIC_FIELD = 1 << 1, + SENSOR_GYROSCOPE = 1 << 2, + SENSOR_LIGHT = 1 << 3, + SENSOR_PROXIMITY = 1 << 4, + SENSOR_ORIENTATION = 1 << 5, + } sensor_type_t; +/* public - functions */ +public: + SensorListener(); + ~SensorListener(); + status_t initialize(); + void setCallbacks(orientation_callback_t orientation_cb, void *cookie); + void enableSensor(sensor_type_t type); + void disableSensor(sensor_type_t type); + void handleOrientation(uint32_t orientation, uint32_t tilt); +/* public - member variables */ +public: + android::sp mSensorEventQueue; +/* private - member variables */ +private: + int sensorsEnabled; + orientation_callback_t mOrientationCb; + void *mCbCookie; + android::sp mLooper; + android::sp mSensorLooperThread; + android::Mutex mLock; +}; + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/inc/SwFrameDecoder.h b/camera/inc/SwFrameDecoder.h new file mode 100644 index 0000000..f123940 --- /dev/null +++ b/camera/inc/SwFrameDecoder.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#ifndef SWFRAMEDECODER_H_ +#define SWFRAMEDECODER_H_ + +#include "FrameDecoder.h" +#include "Decoder_libjpeg.h" + +namespace Ti { +namespace Camera { + +class SwFrameDecoder: public FrameDecoder { +public: + SwFrameDecoder(); + virtual ~SwFrameDecoder(); + +protected: + virtual void doConfigure(const DecoderParameters& config); + virtual void doProcessInputBuffer(); + virtual status_t doStart() { return NO_ERROR; } + virtual void doStop() { } + virtual void doFlush() { } + virtual void doRelease() { } + +private: + int mjpegWithHdrSize; + Decoder_libjpeg mJpgdecoder; + unsigned char* mJpegWithHeaderBuffer; +}; + +} // namespace Camera +} // namespace Ti +#endif /* SWFRAMEDECODER_H_ */ diff --git a/camera/inc/TICameraParameters.h b/camera/inc/TICameraParameters.h new file mode 100644 index 0000000..8686456 --- /dev/null +++ b/camera/inc/TICameraParameters.h @@ -0,0 +1,270 @@ +/* + * 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. + */ + +#ifndef TI_CAMERA_PARAMETERS_H +#define TI_CAMERA_PARAMETERS_H + +#include +#include + +namespace Ti { +namespace Camera { + +///TI Specific Camera Parameters +class TICameraParameters +{ +public: + +// Supported Camera indexes +// Example value: "0,1,2,3", where 0-primary, 1-secondary1, 2-secondary2, 3-sterocamera +static const char KEY_SUPPORTED_CAMERAS[]; +// Select logical Camera index +static const char KEY_CAMERA[]; +static const char KEY_CAMERA_NAME[]; +static const char KEY_BURST[]; +static const char KEY_CAP_MODE[]; +static const char KEY_CAP_MODE_VALUES[]; +static const char KEY_VNF[]; +static const char KEY_VNF_SUPPORTED[]; +static const char KEY_SATURATION[]; +static const char KEY_BRIGHTNESS[]; +static const char KEY_SUPPORTED_EXPOSURE[]; +static const char KEY_EXPOSURE_MODE[]; +static const char KEY_SUPPORTED_MANUAL_EXPOSURE_MIN[]; +static const char KEY_SUPPORTED_MANUAL_EXPOSURE_MAX[]; +static const char KEY_SUPPORTED_MANUAL_EXPOSURE_STEP[]; +static const char KEY_SUPPORTED_MANUAL_GAIN_ISO_MIN[]; +static const char KEY_SUPPORTED_MANUAL_GAIN_ISO_MAX[]; +static const char KEY_SUPPORTED_MANUAL_GAIN_ISO_STEP[]; +static const char KEY_MANUAL_EXPOSURE[]; +static const char KEY_MANUAL_EXPOSURE_RIGHT[]; +static const char KEY_MANUAL_GAIN_ISO[]; +static const char KEY_MANUAL_GAIN_ISO_RIGHT[]; +static const char KEY_CONTRAST[]; +static const char KEY_SHARPNESS[]; +static const char KEY_ISO[]; +static const char KEY_SUPPORTED_ISO_VALUES[]; +static const char KEY_SUPPORTED_IPP[]; +static const char KEY_IPP[]; +static const char KEY_METERING_MODE[]; +static const char KEY_EXP_BRACKETING_RANGE[]; +static const char KEY_EXP_GAIN_BRACKETING_RANGE[]; +static const char KEY_ZOOM_BRACKETING_RANGE[]; +static const char KEY_TEMP_BRACKETING[]; +static const char KEY_TEMP_BRACKETING_RANGE_POS[]; +static const char KEY_TEMP_BRACKETING_RANGE_NEG[]; +static const char KEY_FLUSH_SHOT_CONFIG_QUEUE[]; +static const char KEY_SHUTTER_ENABLE[]; +static const char KEY_MEASUREMENT_ENABLE[]; +static const char KEY_INITIAL_VALUES[]; +static const char KEY_GBCE[]; +static const char KEY_GBCE_SUPPORTED[]; +static const char KEY_GLBCE[]; +static const char KEY_GLBCE_SUPPORTED[]; +static const char KEY_FRAMERATE_RANGES_EXT_SUPPORTED[]; +static const char KEY_FRAMERATES_EXT_SUPPORTED[]; + +// TI recording hint to notify camera adapters of possible recording +static const char KEY_RECORDING_HINT[]; +static const char KEY_AUTO_FOCUS_LOCK[]; +static const char KEY_CURRENT_ISO[]; + +static const char KEY_SENSOR_ORIENTATION[]; + +//TI extensions for camera capabilies +static const char INITIAL_VALUES_TRUE[]; +static const char INITIAL_VALUES_FALSE[]; + +// TI extensions to add values for ManualConvergence and AutoConvergence mode +static const char KEY_AUTOCONVERGENCE_MODE[]; +static const char KEY_AUTOCONVERGENCE_MODE_VALUES[]; +static const char KEY_MANUAL_CONVERGENCE[]; +static const char KEY_SUPPORTED_MANUAL_CONVERGENCE_MIN[]; +static const char KEY_SUPPORTED_MANUAL_CONVERGENCE_MAX[]; +static const char KEY_SUPPORTED_MANUAL_CONVERGENCE_STEP[]; + +// TI extensions to add Min frame rate Values +static const char VIDEO_MINFRAMERATE_5[]; +static const char VIDEO_MINFRAMERATE_10[]; +static const char VIDEO_MINFRAMERATE_15[]; +static const char VIDEO_MINFRAMERATE_20[]; +static const char VIDEO_MINFRAMERATE_24[]; +static const char VIDEO_MINFRAMERATE_25[]; +static const char VIDEO_MINFRAMERATE_30[]; +static const char VIDEO_MINFRAMERATE_33[]; + +//TI extensions for setting EXIF tags +static const char KEY_EXIF_MODEL[]; +static const char KEY_EXIF_MAKE[]; + +//TI extensions for additional GPS data +static const char KEY_GPS_MAPDATUM[]; +static const char KEY_GPS_VERSION[]; +static const char KEY_GPS_DATESTAMP[]; + +// TI extensions for VTC +static const char KEY_VTC_HINT[]; +static const char KEY_VIDEO_ENCODER_HANDLE[]; +static const char KEY_VIDEO_ENCODER_SLICE_HEIGHT[]; + +static const char RAW_WIDTH[]; +static const char RAW_HEIGHT[]; + +//TI extensions to Image post-processing +static const char IPP_LDCNSF[]; +static const char IPP_LDC[]; +static const char IPP_NSF[]; +static const char IPP_NONE[]; + +//TI extensions to camera mode +static const char HIGH_PERFORMANCE_MODE[]; +static const char HIGH_QUALITY_MODE[]; +static const char HIGH_QUALITY_ZSL_MODE[]; +static const char CP_CAM_MODE[]; +static const char VIDEO_MODE[]; +static const char VIDEO_MODE_HQ[]; +static const char EXPOSURE_BRACKETING[]; +static const char ZOOM_BRACKETING[]; +static const char TEMP_BRACKETING[]; + +// TI extensions to standard android pixel formats +static const char PIXEL_FORMAT_UNUSED[]; +static const char PIXEL_FORMAT_JPS[]; +static const char PIXEL_FORMAT_MPO[]; +static const char PIXEL_FORMAT_YUV422I_UYVY[]; + +// TI extensions to standard android scene mode settings +static const char SCENE_MODE_CLOSEUP[]; +static const char SCENE_MODE_AQUA[]; +static const char SCENE_MODE_SNOWBEACH[]; +static const char SCENE_MODE_MOOD[]; +static const char SCENE_MODE_NIGHT_INDOOR[]; +static const char SCENE_MODE_DOCUMENT[]; +static const char SCENE_MODE_BARCODE[]; +static const char SCENE_MODE_VIDEO_SUPER_NIGHT[]; +static const char SCENE_MODE_VIDEO_CINE[]; +static const char SCENE_MODE_VIDEO_OLD_FILM[]; + +// TI extensions to standard android white balance settings. +static const char WHITE_BALANCE_TUNGSTEN[]; +static const char WHITE_BALANCE_HORIZON[]; +static const char WHITE_BALANCE_SUNSET[]; +static const char WHITE_BALANCE_FACE[]; + +// TI extensions to add exposure preset modes to android api +static const char EXPOSURE_MODE_MANUAL[]; +static const char EXPOSURE_MODE_AUTO[]; +static const char EXPOSURE_MODE_NIGHT[]; +static const char EXPOSURE_MODE_BACKLIGHT[]; +static const char EXPOSURE_MODE_SPOTLIGHT[]; +static const char EXPOSURE_MODE_SPORTS[]; +static const char EXPOSURE_MODE_SNOW[]; +static const char EXPOSURE_MODE_BEACH[]; +static const char EXPOSURE_MODE_APERTURE[]; +static const char EXPOSURE_MODE_SMALL_APERTURE[]; +static const char EXPOSURE_MODE_FACE[]; + +// TI extensions to standard android focus presets. +static const char FOCUS_MODE_PORTRAIT[]; +static const char FOCUS_MODE_EXTENDED[]; +static const char FOCUS_MODE_FACE[]; +static const char FOCUS_MODE_OFF[]; + +// TI extensions to add iso values +static const char ISO_MODE_AUTO[]; +static const char ISO_MODE_100[]; +static const char ISO_MODE_200[]; +static const char ISO_MODE_400[]; +static const char ISO_MODE_800[]; +static const char ISO_MODE_1000[]; +static const char ISO_MODE_1200[]; +static const char ISO_MODE_1600[]; + +// TI extensions to add values for effect settings. +static const char EFFECT_NATURAL[]; +static const char EFFECT_VIVID[]; +static const char EFFECT_COLOR_SWAP[]; +static const char EFFECT_BLACKWHITE[]; + +//TI extensions for stereo frame layouts +static const char KEY_S3D_PRV_FRAME_LAYOUT[]; +static const char KEY_S3D_PRV_FRAME_LAYOUT_VALUES[]; +static const char KEY_S3D_CAP_FRAME_LAYOUT[]; +static const char KEY_S3D_CAP_FRAME_LAYOUT_VALUES[]; + +//TI extensions for stereo frame layouts +static const char S3D_NONE[]; +static const char S3D_TB_FULL[]; +static const char S3D_SS_FULL[]; +static const char S3D_TB_SUBSAMPLED[]; +static const char S3D_SS_SUBSAMPLED[]; + +//TI extentions fo 3D resolutions +static const char KEY_SUPPORTED_PICTURE_SUBSAMPLED_SIZES[]; +static const char KEY_SUPPORTED_PICTURE_TOPBOTTOM_SIZES[]; +static const char KEY_SUPPORTED_PICTURE_SIDEBYSIDE_SIZES[]; +static const char KEY_SUPPORTED_PREVIEW_SUBSAMPLED_SIZES[]; +static const char KEY_SUPPORTED_PREVIEW_TOPBOTTOM_SIZES[]; +static const char KEY_SUPPORTED_PREVIEW_SIDEBYSIDE_SIZES[]; + +// TI extensions to add values for AutoConvergence settings. +static const char AUTOCONVERGENCE_MODE_DISABLE[]; +static const char AUTOCONVERGENCE_MODE_FRAME[]; +static const char AUTOCONVERGENCE_MODE_CENTER[]; +static const char AUTOCONVERGENCE_MODE_TOUCH[]; +static const char AUTOCONVERGENCE_MODE_MANUAL[]; + +//TI extensions for flash mode settings +static const char FLASH_MODE_FILL_IN[]; + +//TI extensions to add sensor orientation parameters +static const char ORIENTATION_SENSOR_NONE[]; +static const char ORIENTATION_SENSOR_90[]; +static const char ORIENTATION_SENSOR_180[]; +static const char ORIENTATION_SENSOR_270[]; + + +//TI values for camera direction +static const char FACING_FRONT[]; +static const char FACING_BACK[]; + +static const char KEY_MECHANICAL_MISALIGNMENT_CORRECTION_SUPPORTED[]; +static const char KEY_MECHANICAL_MISALIGNMENT_CORRECTION[]; + +//TI extensions for enable/disable algos +static const char KEY_ALGO_EXTERNAL_GAMMA[]; +static const char KEY_ALGO_NSF1[]; +static const char KEY_ALGO_NSF2[]; +static const char KEY_ALGO_SHARPENING[]; +static const char KEY_ALGO_THREELINCOLORMAP[]; +static const char KEY_ALGO_GIC[]; + +//Gamma table +static const char KEY_GAMMA_TABLE[]; + +static const char KEY_PREVIEW_FRAME_RATE_RANGE[]; + +#ifdef MOTOROLA_CAMERA +static const char KEY_MOT_LEDFLASH[]; +static const char KEY_MOT_LEDTORCH[]; +#endif + +}; + +} // namespace Camera +} // namespace Ti + +#endif diff --git a/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h new file mode 100644 index 0000000..e1e7cad --- /dev/null +++ b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h @@ -0,0 +1,262 @@ +/* + * 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. + */ + + + +#ifndef V4L_CAMERA_ADAPTER_H +#define V4L_CAMERA_ADAPTER_H + +#include + +#include "CameraHal.h" +#include "BaseCameraAdapter.h" +#include "DebugUtils.h" +#include "Decoder_libjpeg.h" +#include "FrameDecoder.h" + + +namespace Ti { +namespace Camera { + +#ifndef V4L2_PIX_FMT_H264 +#define V4L2_PIX_FMT_H264 0 +#endif + +#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_YUYV +#define DEFAULT_CAPTURE_FORMAT V4L2_PIX_FMT_YUYV + +#define NB_BUFFER 10 +#define DEVICE "/dev/videoxx" +#define DEVICE_PATH "/dev/" +#define DEVICE_NAME "videoxx" + +typedef int V4L_HANDLETYPE; + +struct CapPixelformat { + uint32_t pixelformat; + const char *param; +}; + +struct CapResolution { + size_t width, height; + char param[10]; +}; + +struct CapU32 { + uint32_t num; + const char *param; +}; + +typedef CapU32 CapFramerate; + +struct VideoInfo { + struct v4l2_capability cap; + struct v4l2_format format; + struct v4l2_buffer buf; + struct v4l2_requestbuffers rb; + void *mem[NB_BUFFER]; + void *CaptureBuffers[NB_BUFFER]; + bool isStreaming; + int width; + int height; + int formatIn; + int framesizeIn; +}; + +typedef struct V4L_TI_CAPTYPE { + uint16_t ulPreviewFormatCount; // supported preview pixelformat count + uint32_t ePreviewFormats[32]; + uint16_t ulPreviewResCount; // supported preview resolution sizes + CapResolution tPreviewRes[32]; + uint16_t ulCaptureResCount; // supported capture resolution sizes + CapResolution tCaptureRes[32]; + uint16_t ulFrameRateCount; // supported frame rate + uint16_t ulFrameRates[32]; +}V4L_TI_CAPTYPE; + +/** + * Class which completely abstracts the camera hardware interaction from camera hal + * TODO: Need to list down here, all the message types that will be supported by this class + Need to implement BufferProvider interface to use AllocateBuffer of OMX if needed + */ +class V4LCameraAdapter : public BaseCameraAdapter +{ +public: + + /*--------------------Constant declarations----------------------------------------*/ + static const int32_t MAX_NO_BUFFERS = 20; + + ///@remarks OMX Camera has six ports - buffer input, time input, preview, image, video, and meta data + static const int MAX_NO_PORTS = 6; + + ///Five second timeout + static const int CAMERA_ADAPTER_TIMEOUT = 5000*1000; + +public: + + V4LCameraAdapter(size_t sensor_index, CameraHal* hal); + ~V4LCameraAdapter(); + + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const android::CameraParameters& params); + virtual void getParameters(android::CameraParameters& params); + + // API + virtual status_t UseBuffersPreview(CameraBuffer *bufArr, int num); + virtual status_t UseBuffersCapture(CameraBuffer *bufArr, int num); + + static status_t getCaps(const int sensorId, CameraProperties::Properties* params, V4L_HANDLETYPE handle); + + void setupWorkingMode(); + +protected: + +//----------Parent class method implementation------------------------------------ + virtual status_t startPreview(); + virtual status_t stopPreview(); + virtual status_t takePicture(); + virtual status_t stopImageCapture(); + virtual status_t autoFocus(); + virtual status_t useBuffers(CameraMode mode, CameraBuffer *bufArr, int num, size_t length, unsigned int queueable); + virtual status_t fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::FrameType frameType); + virtual status_t getFrameSize(size_t &width, size_t &height); + virtual status_t getPictureBufferSize(CameraFrame &frame, size_t bufferCount); + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); +//----------------------------------------------------------------------------- + + +private: + + class PreviewThread : public android::Thread { + V4LCameraAdapter* mAdapter; + public: + PreviewThread(V4LCameraAdapter* hw) : + Thread(false), mAdapter(hw) { } + virtual void onFirstRef() { + run("CameraPreviewThread", android::PRIORITY_URGENT_DISPLAY); + } + virtual bool threadLoop() { + mAdapter->previewThread(); + // loop until we need to quit + return true; + } + }; + + //Used for calculation of the average frame rate during preview + status_t recalculateFPS(); + + char * GetFrame(int &index, int &filledLen); + + int previewThread(); + +private: + //capabilities data + static const CapPixelformat mPixelformats []; + static const CapResolution mPreviewRes []; + static const CapFramerate mFramerates []; + static const CapResolution mImageCapRes []; + + //camera defaults + static const char DEFAULT_PREVIEW_FORMAT[]; + static const char DEFAULT_PREVIEW_SIZE[]; + static const char DEFAULT_FRAMERATE[]; + static const char DEFAULT_NUM_PREV_BUFS[]; + + static const char DEFAULT_PICTURE_FORMAT[]; + static const char DEFAULT_PICTURE_SIZE[]; + static const char DEFAULT_FOCUS_MODE[]; + static const char DEFAULT_FRAMERATE_RANGE[]; + static const char * DEFAULT_VSTAB; + static const char * DEFAULT_VNF; + + static status_t insertDefaults(CameraProperties::Properties*, V4L_TI_CAPTYPE&); + static status_t insertCapabilities(CameraProperties::Properties*, V4L_TI_CAPTYPE&); + static status_t insertPreviewFormats(CameraProperties::Properties* , V4L_TI_CAPTYPE&); + static status_t insertPreviewSizes(CameraProperties::Properties* , V4L_TI_CAPTYPE&); + static status_t insertImageSizes(CameraProperties::Properties* , V4L_TI_CAPTYPE&); + static status_t insertFrameRates(CameraProperties::Properties* , V4L_TI_CAPTYPE&); + static status_t sortAscend(V4L_TI_CAPTYPE&, uint16_t ) ; + + status_t v4lIoctl(int, int, void*); + status_t v4lInitMmap(int& count, int width, int height); + status_t v4lInitUsrPtr(int&); + status_t v4lStartStreaming(); + status_t v4lStopStreaming(int nBufferCount); + status_t v4lSetFormat(int, int, uint32_t); + status_t restartPreview(); + status_t applyFpsValue(); + status_t returnBufferToV4L(int id); + void returnOutputBuffer(int index); + bool isNeedToUseDecoder() const; + + int mPreviewBufferCount; + int mPreviewBufferCountQueueable; + int mCaptureBufferCount; + int mCaptureBufferCountQueueable; + CameraBuffer *mPreviewBufs[NB_BUFFER]; + android::KeyedVector mCaptureBufs; + + android::CameraParameters mParams; + + bool mPreviewing; + bool mCapturing; + mutable android::Mutex mLock; + + int mFrameCount; + int mLastFrameCount; + unsigned int mIter; + nsecs_t mLastFPSTime; + + //variables holding the estimated framerate + float mFPS, mLastFPS; + + int mSensorIndex; + + // protected by mLock + android::sp mPreviewThread; + + struct VideoInfo *mVideoInfo; + int mCameraHandle; + + int nQueued; + int nDequeued; + int mQueuedOutputBuffers; + + FrameDecoder* mDecoder; + android::Vector< android::sp > mInBuffers; + android::Vector< android::sp > mOutBuffers; + + android::Mutex mV4LLock; + + int mPixelFormat; + int mFrameRate; + + android::Mutex mStopLock; + android::Condition mStopCondition; + + CameraHal* mCameraHal; + int mSkipFramesCount; +}; + +} // namespace Camera +} // namespace Ti + +#endif //V4L_CAMERA_ADAPTER_H diff --git a/camera/inc/VideoMetadata.h b/camera/inc/VideoMetadata.h new file mode 100644 index 0000000..f05ee50 --- /dev/null +++ b/camera/inc/VideoMetadata.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef VIDEO_METADATA_H +#define VIDEO_METADATA_H + +/* This structure is used to pass buffer offset from Camera-Hal to Encoder component + * for specific algorithms like VSTAB & VNF + */ + +typedef struct +{ + int metadataBufferType; + void* handle; + int offset; +} +video_metadata_t; + +#endif -- cgit v1.1