From 46658da7a37c43075b66575e639872b5ecce3155 Mon Sep 17 00:00:00 2001 From: Ziyann Date: Mon, 24 Nov 2014 21:31:16 +0100 Subject: tuna: add open-source domx/camera stuff Camera is still half-broken. Credits to @MWisBest Change-Id: I87a802abfacaf36ab22676f5284f0cc1996f6b03 --- camera/OMXCameraAdapter/OMX3A.cpp | 1731 ++++++++++++ camera/OMXCameraAdapter/OMXAlgo.cpp | 1180 ++++++++ camera/OMXCameraAdapter/OMXCameraAdapter.cpp | 3713 ++++++++++++++++++++++++++ camera/OMXCameraAdapter/OMXCapabilities.cpp | 1279 +++++++++ camera/OMXCameraAdapter/OMXCapture.cpp | 1229 +++++++++ camera/OMXCameraAdapter/OMXDefaults.cpp | 83 + camera/OMXCameraAdapter/OMXExif.cpp | 839 ++++++ camera/OMXCameraAdapter/OMXFD.cpp | 490 ++++ camera/OMXCameraAdapter/OMXFocus.cpp | 840 ++++++ camera/OMXCameraAdapter/OMXZoom.cpp | 296 ++ 10 files changed, 11680 insertions(+) create mode 100644 camera/OMXCameraAdapter/OMX3A.cpp create mode 100644 camera/OMXCameraAdapter/OMXAlgo.cpp create mode 100755 camera/OMXCameraAdapter/OMXCameraAdapter.cpp create mode 100644 camera/OMXCameraAdapter/OMXCapabilities.cpp create mode 100644 camera/OMXCameraAdapter/OMXCapture.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/OMXZoom.cpp (limited to 'camera/OMXCameraAdapter') diff --git a/camera/OMXCameraAdapter/OMX3A.cpp b/camera/OMXCameraAdapter/OMX3A.cpp new file mode 100644 index 0000000..7ae50e4 --- /dev/null +++ b/camera/OMXCameraAdapter/OMX3A.cpp @@ -0,0 +1,1731 @@ +/* + * 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 "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +#include + +#undef TRUE +#undef FALSE +#define TRUE "true" +#define FALSE "false" + +#define METERING_AREAS_RANGE 0xFF + +namespace android { +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 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; + + Mutex::Autolock lock(m3ASettingsUpdateLock); + + str = params.get(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 + + str = params.get(TICameraParameters::KEY_EXPOSURE_MODE); + mode = getLUTvalue_HALtoOMX( str, ExpLUT); + if ( ( str != NULL ) && ( mParameters3A.Exposure != mode )) + { + mParameters3A.Exposure = mode; + CAMHAL_LOGDB("Exposure mode %d", mode); + if ( 0 <= mParameters3A.Exposure ) + { + mPending3Asettings |= SetExpMode; + } + } + +#endif + + str = params.get(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(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(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(CameraParameters::KEY_EXPOSURE_COMPENSATION); + varint = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + if ( mFirstTimeInit || + (( str != NULL ) && + (mParameters3A.EVCompensation != varint ))) + { + CAMHAL_LOGDB("Setting EV Compensation to %d", varint); + + mParameters3A.EVCompensation = varint; + mPending3Asettings |= SetEVCompensation; + } + + str = params.get(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(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(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, "true")) ) + { + OMX_BOOL lock = OMX_FALSE; + mUserSetExpLock = OMX_FALSE; + str = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK); + if (str && ((strcmp(str, "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(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, "true")) ) + { + OMX_BOOL lock = OMX_FALSE; + mUserSetWbLock = OMX_FALSE; + str = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); + if (str && ((strcmp(str, "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, TRUE) == 0) && (mParameters3A.FocusLock != OMX_TRUE)) { + CAMHAL_LOGVA("Locking Focus"); + mParameters3A.FocusLock = OMX_TRUE; + setFocusLock(mParameters3A); + } else if (str && (strcmp(str, FALSE) == 0) && (mParameters3A.FocusLock != OMX_FALSE)) { + CAMHAL_LOGVA("UnLocking Focus"); + mParameters3A.FocusLock = OMX_FALSE; + setFocusLock(mParameters3A); + } + + str = params.get(CameraParameters::KEY_METERING_AREAS); + if ( (str != NULL) ) { + size_t MAX_METERING_AREAS; + Vector< sp > tempAreas; + + MAX_METERING_AREAS = atoi(params.get(CameraParameters::KEY_MAX_NUM_METERING_AREAS)); + + Mutex::Autolock 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(CameraParameters::KEY_METERING_AREAS)); + + mPending3Asettings |= SetMeteringAreas; + } else { + CAMHAL_LOGEB("Metering areas supported %d, metering areas set %d", + MAX_METERING_AREAS, mMeteringAreas.size()); + ret = -EINVAL; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +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; +} + +status_t OMXCameraAdapter::init3AParams(Gen3A_settings &Gen3A) +{ + LOG_FUNCTION_NAME; + + Gen3A.Effect = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EFFECT, EffLUT); + Gen3A.FlashMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FLASH_MODE, FlashLUT); + Gen3A.SceneMode = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_SCENE_MODE, SceneLUT); + Gen3A.EVCompensation = atoi(OMXCameraAdapter::DEFAULT_EV_COMPENSATION); + Gen3A.Focus = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_FOCUS_MODE, FocusLUT); + Gen3A.ISO = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ISO_MODE, IsoLUT); + Gen3A.Flicker = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_ANTIBANDING, FlickerLUT); + Gen3A.Brightness = atoi(OMXCameraAdapter::DEFAULT_BRIGHTNESS); + Gen3A.Saturation = atoi(OMXCameraAdapter::DEFAULT_SATURATION) - SATURATION_OFFSET; + Gen3A.Sharpness = atoi(OMXCameraAdapter::DEFAULT_SHARPNESS) - SHARPNESS_OFFSET; + Gen3A.Contrast = atoi(OMXCameraAdapter::DEFAULT_CONTRAST) - CONTRAST_OFFSET; + Gen3A.WhiteBallance = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_WB, WBalLUT); + Gen3A.Exposure = getLUTvalue_HALtoOMX(OMXCameraAdapter::DEFAULT_EXPOSURE_MODE, ExpLUT); + Gen3A.ExposureLock = OMX_FALSE; + Gen3A.FocusLock = OMX_FALSE; + Gen3A.WhiteBalanceLock = OMX_FALSE; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +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 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, "true") || !strcasecmp(value, "1"))) { + ALOGW("flash is disabled for testing purpose"); + return true; + } + + return false; +} + +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 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 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 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 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 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 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 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; + + if ( WB_FACE_PRIORITY == Gen3A.WhiteBallance ) + { + //Disable Region priority and enable Face priority + setAlgoPriority(REGION_PRIORITY, WHITE_BALANCE_ALGO, false); + setAlgoPriority(FACE_PRIORITY, WHITE_BALANCE_ALGO, true); + + //Then set the mode to auto + wb.eWhiteBalControl = OMX_WhiteBalControlAuto; + } + else + { + //Disable Face and Region priority + 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 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 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 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 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 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 ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setISO(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( 0 == Gen3A.ISO ) + { + expValues.bAutoSensitivity = OMX_TRUE; + } + else + { + expValues.bAutoSensitivity = OMX_FALSE; + expValues.nSensitivity = Gen3A.ISO; + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + 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 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 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 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 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 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 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 + { + const char *lock_state_exp = toggleExp ? TRUE : FALSE; + CAMHAL_LOGDA("Exposure Lock GetConfig successfull"); + + /* Apply locks only when not applied already */ + if ( lock.bLock != toggleExp ) + { + setExposureLock(mParameters3A); + } + + mParams.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, lock_state_exp); + } + + 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 + { + const char *lock_state_wb = toggleWb ? TRUE : FALSE; + CAMHAL_LOGDA("WhiteBalance Lock GetConfig successfull"); + + /* Apply locks only when not applied already */ + if ( lock.bLock != toggleWb ) + { + setWhiteBalanceLock(mParameters3A); + } + + mParams.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, lock_state_wb); + } + EXIT: + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setMeteringAreas(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + OMX_ALGOAREASTYPE **meteringAreas; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + MemoryManager memMgr; + int areasSize = 0; + + LOG_FUNCTION_NAME + + Mutex::Autolock lock(mMeteringAreasLock); + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + areasSize = ((sizeof(OMX_ALGOAREASTYPE)+4095)/4096)*4096; + meteringAreas = (OMX_ALGOAREASTYPE**) memMgr.allocateBuffer(0, 0, NULL, areasSize, 1); + + 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[0], OMX_ALGOAREASTYPE); + + meteringAreas[0]->nPortIndex = OMX_ALL; + meteringAreas[0]->nNumAreas = mMeteringAreas.size(); + meteringAreas[0]->nAlgoAreaPurpose = OMX_AlgoAreaExposure; + + for ( unsigned int n = 0; n < mMeteringAreas.size(); n++) + { + // transform the coordinates to 3A-type coordinates + mMeteringAreas.itemAt(n)->transfrom(mPreviewData->mWidth, + mPreviewData->mHeight, + meteringAreas[0]->tAlgoAreas[n].nTop, + meteringAreas[0]->tAlgoAreas[n].nLeft, + meteringAreas[0]->tAlgoAreas[n].nWidth, + meteringAreas[0]->tAlgoAreas[n].nHeight); + + meteringAreas[0]->tAlgoAreas[n].nLeft = + ( meteringAreas[0]->tAlgoAreas[n].nLeft * METERING_AREAS_RANGE ) / mPreviewData->mWidth; + meteringAreas[0]->tAlgoAreas[n].nTop = + ( meteringAreas[0]->tAlgoAreas[n].nTop* METERING_AREAS_RANGE ) / mPreviewData->mHeight; + meteringAreas[0]->tAlgoAreas[n].nWidth = + ( meteringAreas[0]->tAlgoAreas[n].nWidth * METERING_AREAS_RANGE ) / mPreviewData->mWidth; + meteringAreas[0]->tAlgoAreas[n].nHeight = + ( meteringAreas[0]->tAlgoAreas[n].nHeight * METERING_AREAS_RANGE ) / mPreviewData->mHeight; + + meteringAreas[0]->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[0]->tAlgoAreas[n].nTop, (int)meteringAreas[0]->tAlgoAreas[n].nLeft, + (int)meteringAreas[0]->tAlgoAreas[n].nWidth, (int)meteringAreas[0]->tAlgoAreas[n].nHeight, + (int)meteringAreas[0]->tAlgoAreas[n].nPriority); + + } + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = areasSize; + sharedBuffer.pSharedBuff = (OMX_U8 *) meteringAreas[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 != meteringAreas) + { + memMgr.freeBuffer((void*) meteringAreas); + meteringAreas = NULL; + } + + return ret; +} + +status_t OMXCameraAdapter::apply3Asettings( Gen3A_settings& Gen3A ) +{ + status_t ret = NO_ERROR; + unsigned int currSett; // 32 bit + int portIndex; + + LOG_FUNCTION_NAME; + + Mutex::Autolock 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 SetFlash: + { + ret |= setFlashMode(Gen3A); + break; + } + + case SetExpLock: + { + ret |= setExposureLock(Gen3A); + break; + } + + case SetWBLock: + { + ret |= setWhiteBalanceLock(Gen3A); + break; + } + case SetMeteringAreas: + { + ret |= setMeteringAreas(Gen3A); + } + break; + default: + CAMHAL_LOGEB("this setting (0x%x) is still not supported in CameraAdapter ", + currSett); + break; + } + mPending3Asettings &= ~currSett; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXAlgo.cpp b/camera/OMXCameraAdapter/OMXAlgo.cpp new file mode 100644 index 0000000..12b9058 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXAlgo.cpp @@ -0,0 +1,1180 @@ +/* + * 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. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +#undef TRUE + +namespace android { + +status_t OMXCameraAdapter::setParametersAlgo(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + const char *oldstr = NULL; + + 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; + } + else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_MODE) == 0) + { + capMode = OMXCameraAdapter::HIGH_QUALITY; + } + else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_ZSL_MODE) == 0) + { + capMode = OMXCameraAdapter::HIGH_QUALITY_ZSL; + } + else if (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) == 0) + { + capMode = OMXCameraAdapter::VIDEO_MODE; + } + else + { + capMode = OMXCameraAdapter::HIGH_QUALITY; + } + } + else + { + capMode = OMXCameraAdapter::HIGH_QUALITY_ZSL; + + } + + if ( mCapMode != capMode ) + { + mCapMode = capMode; + mOMXStateSwitch = true; + } + + 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) ) + { + 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) ) + { + // Configure GBCE only if the setting has changed since last time + oldstr = mParams.get(TICameraParameters::KEY_GBCE); + bool cmpRes = true; + if ( NULL != oldstr ) + { + cmpRes = strcmp(valstr, oldstr) != 0; + } + else + { + cmpRes = true; + } + + + if( cmpRes ) + { + if (strcmp(valstr, ( const char * ) TICameraParameters::GBCE_ENABLE ) == 0) + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_ON); + } + else if (strcmp(valstr, ( const char * ) TICameraParameters::GBCE_DISABLE ) == 0) + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + else + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + } + else if(mParams.get(TICameraParameters::KEY_GBCE) || mFirstTimeInit) + { + //Disable GBCE by default + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + + if ( ( valstr = params.get(TICameraParameters::KEY_GLBCE) ) != NULL ) + { + // Configure GLBCE only if the setting has changed since last time + + oldstr = mParams.get(TICameraParameters::KEY_GLBCE); + bool cmpRes = true; + if ( NULL != oldstr ) + { + cmpRes = strcmp(valstr, oldstr) != 0; + } + else + { + cmpRes = true; + } + + + if( cmpRes ) + { + if (strcmp(valstr, ( const char * ) TICameraParameters::GLBCE_ENABLE ) == 0) + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_ON); + } + else if (strcmp(valstr, ( const char * ) TICameraParameters::GLBCE_DISABLE ) == 0) + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + else + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + } + else if(mParams.get(TICameraParameters::KEY_GLBCE) || mFirstTimeInit) + { + //Disable GLBCE by default + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + + if ( mIPP != ipp ) + { + mIPP = ipp; + mOMXStateSwitch = true; + } + + ///Set VNF Configuration + bool vnfEnabled = false; + if ( params.getInt(TICameraParameters::KEY_VNF) > 0 ) + { + CAMHAL_LOGDA("VNF Enabled"); + vnfEnabled = true; + } + else + { + CAMHAL_LOGDA("VNF Disabled"); + vnfEnabled = false; + } + + if ( mVnfEnabled != vnfEnabled ) + { + mVnfEnabled = vnfEnabled; + mOMXStateSwitch = true; + } + + ///Set VSTAB Configuration + bool vstabEnabled = false; + valstr = params.get(CameraParameters::KEY_VIDEO_STABILIZATION); + if (valstr && strcmp(valstr, CameraParameters::TRUE) == 0) { + CAMHAL_LOGDA("VSTAB Enabled"); + vstabEnabled = true; + } + else + { + CAMHAL_LOGDA("VSTAB Disabled"); + vstabEnabled = false; + } + + if ( mVstabEnabled != vstabEnabled ) + { + mVstabEnabled = vstabEnabled; + mOMXStateSwitch = true; + } + + //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); + if ( valstr != NULL ) + { + // Set ManualConvergence default value + OMX_S32 manualconvergence = -30; + if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_DISABLE) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeDisable, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_FRAME) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeFrame, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_CENTER) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeCenter, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_FFT) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeFocusFaceTouch, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_MANUAL) == 0 ) + { + manualconvergence = (OMX_S32)params.getInt(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES); + setAutoConvergence(OMX_TI_AutoConvergenceModeManual, manualconvergence); + } + CAMHAL_LOGVB("AutoConvergenceMode %s, value = %d", valstr, (int) manualconvergence); + } + +#endif + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Get AutoConvergence +status_t OMXCameraAdapter::getAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE *pACMode, + OMX_S32 *pManualConverence) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_CONVERGENCETYPE ACParams; + + ACParams.nSize = sizeof(OMX_TI_CONFIG_CONVERGENCETYPE); + ACParams.nVersion = mLocalVersionParam; + ACParams.nPortIndex = OMX_ALL; + + LOG_FUNCTION_NAME; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutoConvergence, + &ACParams); + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGEB("Error while getting AutoConvergence 0x%x", eError); + ret = -EINVAL; + } + else + { + *pManualConverence = ACParams.nManualConverence; + *pACMode = ACParams.eACMode; + CAMHAL_LOGDA("AutoConvergence got successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Set AutoConvergence +status_t OMXCameraAdapter::setAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE pACMode, + OMX_S32 pManualConverence) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_CONVERGENCETYPE ACParams; + + LOG_FUNCTION_NAME; + + ACParams.nSize = sizeof(OMX_TI_CONFIG_CONVERGENCETYPE); + ACParams.nVersion = mLocalVersionParam; + ACParams.nPortIndex = OMX_ALL; + ACParams.nManualConverence = pManualConverence; + ACParams.eACMode = pACMode; + 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 = -EINVAL; + } + 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_TI_PARAM_ZSLHISTORYLENTYPE zslHistoryLen; + OMX_CONFIG_BOOLEANTYPE bCAC; + + LOG_FUNCTION_NAME; + + //ZSL have 4 buffers history by default + OMX_INIT_STRUCT_PTR (&zslHistoryLen, OMX_TI_PARAM_ZSLHISTORYLENTYPE); + zslHistoryLen.nHistoryLen = 4; + + //CAC is disabled by default + OMX_INIT_STRUCT_PTR (&bCAC, OMX_CONFIG_BOOLEANTYPE); + bCAC.bEnabled = OMX_FALSE; + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&camMode, OMX_CONFIG_CAMOPERATINGMODETYPE); + if ( mSensorIndex == OMX_TI_StereoSensor ) + { + 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::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; + + if ( !mIternalRecordingHint ) { + zslHistoryLen.nHistoryLen = 5; + } + + } + else if( OMXCameraAdapter::VIDEO_MODE == mode ) + { + CAMHAL_LOGDA("Camera mode: VIDEO MODE"); + camMode.eCamOperatingMode = OMX_CaptureVideo; + } + else + { + CAMHAL_LOGEA("Camera mode: INVALID mode passed!"); + return BAD_VALUE; + } + + if( NO_ERROR == ret ) + { + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexParamZslHistoryLen, + &zslHistoryLen); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring ZSL History len 0x%x", eError); + // Don't return status for now + // as high history values might lead + // to errors on some platforms. + // ret = ErrorUtils::omxToAndroidError(eError); + } + else + { + CAMHAL_LOGDA("ZSL History len configured successfully"); + } + } + + 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 = ErrorUtils::omxToAndroidError(eError); + } + else + { + CAMHAL_LOGDA("Camera 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 = 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 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 > 1008,resolution cannot be set without configuring orientation. + * So we first set a temp resolution. We have used VGA + */ + tmpHeight = mPreviewData->mHeight; + tmpWidth = mPreviewData->mWidth; + mPreviewData->mWidth = 640; + mPreviewData->mHeight = 480; + ret = setFormat(OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, *mPreviewData); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("setFormat() failed %d", ret); + } + + /* Now set Required Orientation*/ + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(sensorOrientation, OMX_CONFIG_ROTATIONTYPE); + sensorOrientation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while Reading Sensor Orientation : 0x%x", eError); + } + CAMHAL_LOGVB(" Currently Sensor Orientation is set to : %d", + ( unsigned int ) sensorOrientation.nRotation); + 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_LOGVA(" Read the Parameters that are set"); + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while Reading Sensor Orientation : 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 */ + + mPreviewData->mWidth = tmpWidth; + mPreviewData->mHeight = tmpHeight; + if ( NO_ERROR == ret ) + { + ret = setFormat (mCameraAdapterParameters.mPrevPortIndex, + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setFormat() failed %d", ret); + } + } + + 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; + } + + // The port framerate should never be smaller + // than max framerate. + if ( mPreviewData->mFrameRate < maxFrameRate ) { + 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; + } + +}; diff --git a/camera/OMXCameraAdapter/OMXCameraAdapter.cpp b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp new file mode 100755 index 0000000..49f9f8c --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp @@ -0,0 +1,3713 @@ +/* + * 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" +#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; + +#undef TRUE +#undef FALSE + +#define HERE(Msg) {CAMHAL_LOGEB("--===line %d, %s===--\n", __LINE__, Msg);} + +namespace android { + +#undef LOG_TAG +///Maintain a separate tag for OMXCameraAdapter logs to isolate issues OMX specific +#define LOG_TAG "CameraHAL" + +//frames skipped before recalculating the framerate +#define FPS_PERIOD 30 + +Mutex gAdapterLock; +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +status_t OMXCameraAdapter::initialize(CameraProperties::Properties* caps) +{ + LOG_FUNCTION_NAME; + + char value[PROPERTY_VALUE_MAX]; + property_get("debug.camera.showfps", value, "0"); + mDebugFps = atoi(value); + property_get("debug.camera.framecounts", value, "0"); + mDebugFcs = atoi(value); + + 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; + + 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_PREVIEW; + + eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_Init() failed, error: 0x%x", eError); + return ErrorUtils::omxToAndroidError(eError); + } + mOmxInitialized = true; + + ///Get the handle to the OMX Component + eError = OMXCameraAdapter::OMXCameraGetHandle(&mCameraAdapterParameters.mHandleComp, (OMX_PTR)this); + 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); + 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); + } + + printComponentVersion(mCameraAdapterParameters.mHandleComp); + + mBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mBracketingRange = 1; + mLastBracetingBufferIdx = 0; + mOMXStateSwitch = false; + + mCaptureSignalled = false; + mCaptureConfigured = false; + mRecording = false; + mWaitingForSnapshot = false; + mSnapshotCount = 0; + + mCapMode = HIGH_QUALITY; + mIPP = IPP_NULL; + mVstabEnabled = false; + mVnfEnabled = false; + mBurstFrames = 1; + mCapturedFrames = 0; + mPictureQuality = 100; + mCurrentZoomIdx = 0; + mTargetZoomIdx = 0; + mPreviousZoomIndx = 0; + mReturnZoomStatus = false; + mZoomInc = 1; + mZoomParameterIdx = 0; + mExposureBracketingValidEntries = 0; + mSensorOverclock = false; + mIternalRecordingHint = false; + + mDeviceOrientation = 0; + mCapabilities = caps; + mZoomUpdating = false; + mZoomUpdate = 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; + + // 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", 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", 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; + } + } + + //Remove any unhandled events + if (!mEventSignalQ.isEmpty()) { + for (unsigned int i = 0 ;i < mEventSignalQ.size(); i++ ) { + TIUTILS::Message *msg = mEventSignalQ.itemAt(i); + //remove from queue and free msg + if ( NULL != msg ) { + free(msg); + } + } + mEventSignalQ.clear(); + } + + 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; + + memset(mExposureBracketingValues, 0, EXP_BRACKET_RANGE*sizeof(int)); + mMeasurementEnabled = false; + mFaceDetectionRunning = false; + mFaceDetectionPaused = false; + mFDSwitchAlgoPriority = false; + + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex], 0, sizeof(OMXCameraPortParameters)); + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex], 0, sizeof(OMXCameraPortParameters)); + + //Initialize 3A defaults + ret = init3AParams(mParameters3A); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEA("Couldn't init 3A params!"); + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + return ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGDB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return 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; +} + +OMXCameraAdapter::OMXCameraPortParameters *OMXCameraAdapter::getPortParams(CameraFrame::FrameType frameType) +{ + OMXCameraAdapter::OMXCameraPortParameters *ret = NULL; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + 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(void* frameBuf, CameraFrame::FrameType frameType) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters *port = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return NO_INIT; + } + + if ( NULL == frameBuf ) + { + return -EINVAL; + } + + if ( (NO_ERROR == ret) && + ((CameraFrame::IMAGE_FRAME == frameType) || (CameraFrame::RAW_FRAME == frameType)) && + (1 > mCapturedFrames) && + (!mBracketingEnabled)) { + // Signal end of image capture + if ( NULL != mEndImageCaptureCallback) { + mEndImageCaptureCallback(mEndCaptureData); + } + return NO_ERROR; + } + + 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 ( port->mBufferHeader[i]->pBuffer == frameBuf ) + { + 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 | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::setParameters(const CameraParameters ¶ms) +{ + LOG_FUNCTION_NAME; + + const char * str = NULL; + int mode = 0; + status_t ret = NO_ERROR; + bool updateImagePortParams = false; + int minFramerate, maxFramerate, frameRate; + const char *valstr = NULL; + const char *oldstr = 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, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV420P) == 0 || + strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else + { + CAMHAL_LOGDA("Invalid format, CbYCrY format selected as default"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + } + else + { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + params.getPreviewSize(&w, &h); + frameRate = params.getPreviewFrameRate(); + minFramerate = params.getInt(TICameraParameters::KEY_MINFRAMERATE); + maxFramerate = params.getInt(TICameraParameters::KEY_MAXFRAMERATE); + if ( ( 0 < minFramerate ) && + ( 0 < maxFramerate ) ) + { + if ( minFramerate > maxFramerate ) + { + CAMHAL_LOGEA(" Min FPS set higher than MAX. So setting MIN and MAX to the higher value"); + maxFramerate = minFramerate; + } + + if ( 0 >= frameRate ) + { + frameRate = maxFramerate; + } + + if( ( cap->mMinFrameRate != minFramerate ) || + ( cap->mMaxFrameRate != maxFramerate ) ) + { + cap->mMinFrameRate = minFramerate; + cap->mMaxFrameRate = maxFramerate; + setVFramerate(cap->mMinFrameRate, cap->mMaxFrameRate); + } + } + + // TODO(XXX): Limiting 1080p to (24,24) or (15,15) for now. Need to remove later. + if ((w >= 1920) && (h >= 1080)) { + cap->mMaxFrameRate = cap->mMinFrameRate; + setVFramerate(cap->mMinFrameRate, cap->mMaxFrameRate); + } + + if ( 0 < frameRate ) + { + 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); + + //TODO: Add an additional parameter for video resolution + //use preview resolution for now + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + cap->mColorFormat = pixFormat; + cap->mWidth = w; + cap->mHeight = h; + cap->mFrameRate = frameRate; + + CAMHAL_LOGVB("Video: cap.mColorFormat = %d", (int)cap->mColorFormat); + CAMHAL_LOGVB("Video: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Video: cap.mHeight = %d", (int)cap->mHeight); + CAMHAL_LOGVB("Video: 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; + } + + valstr = params.get(TICameraParameters::KEY_RECORDING_HINT); + if (!valstr || (valstr && (strcmp(valstr, CameraParameters::FALSE)))) { + mIternalRecordingHint = false; + } else { + mIternalRecordingHint = true; + } + +#ifdef OMAP_ENHANCEMENT + + if ( (valstr = params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)) != NULL ) + { + if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_ENABLE) == 0) + { + mMeasurementEnabled = true; + } + else if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_DISABLE) == 0) + { + mMeasurementEnabled = false; + } + else + { + mMeasurementEnabled = false; + } + } + else + { + //Disable measurement data by default + mMeasurementEnabled = false; + } + +#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); + + mParams = params; + mFirstTimeInit = false; + + 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) { + ALOGE("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(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(CameraParameters::KEY_WHITE_BALANCE , valstr); + + valstr = getLUTvalue_OMXtoHAL(mParameters3A.FlashMode, FlashLUT); + valstr_supported = mParams.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(CameraParameters::KEY_FLASH_MODE, valstr); + + if ((mParameters3A.Focus == OMX_IMAGE_FocusControlAuto) && + (mCapMode != OMXCameraAdapter::VIDEO_MODE)) { + valstr = CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE; + } else { + valstr = getLUTvalue_OMXtoHAL(mParameters3A.Focus, FocusLUT); + } + valstr_supported = mParams.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES); + if (valstr && valstr_supported && strstr(valstr_supported, valstr)) + params.set(CameraParameters::KEY_FOCUS_MODE, valstr); + } + + //Query focus distances only when focus is running + if ( ( AF_ACTIVE & state ) || + ( NULL == mParameters.get(CameraParameters::KEY_FOCUS_DISTANCES) ) ) + { + updateFocusDistances(params); + } + else + { + params.set(CameraParameters::KEY_FOCUS_DISTANCES, + mParameters.get(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 + + { + Mutex::Autolock lock(mZoomLock); + //Immediate zoom should not be avaialable while smooth zoom is running + if ( ZOOM_ACTIVE & state ) + { + if ( mZoomParameterIdx != mCurrentZoomIdx ) + { + mZoomParameterIdx += mZoomInc; + } + params.set( 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( CameraParameters::KEY_ZOOM, mCurrentZoomIdx); + } + } + + //Populate current lock status + if ( mParameters3A.ExposureLock ) { + params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, + CameraParameters::TRUE); + } else { + params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, + CameraParameters::FALSE); + } + + if ( mParameters3A.WhiteBalanceLock ) { + params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, + CameraParameters::TRUE); + } else { + params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, + CameraParameters::FALSE); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OMXCameraAdapter::setFormat(OMX_U32 port, OMXCameraPortParameters &portParams) +{ + size_t bufferCount; + + LOG_FUNCTION_NAME; + + 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; + if( ( portCheck.format.video.nFrameWidth >= 1920 ) && + ( portCheck.format.video.nFrameHeight >= 1080 ) && + ( portParams.mFrameRate >= FRAME_RATE_FULL_HD ) ) + { + setSensorOverclock(true); + } + else + { + setSensorOverclock(false); + } + + portCheck.format.video.xFramerate = portParams.mFrameRate<<16; + portCheck.nBufferSize = portParams.mStride * portParams.mHeight; + portCheck.nBufferCountActual = portParams.mNumBufs; + mFocusThreshold = FOCUS_THRESHOLD * portParams.mFrameRate; + } + 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 && mCodingMode == CodingNone ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingJPS ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingJPS; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingMPO ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingMPO; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingRAWJPEG ) + { + //TODO: OMX_IMAGE_CodingJPEG should be changed to OMX_IMAGE_CodingRAWJPEG when + // RAW format is supported + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingRAWMPO ) + { + //TODO: OMX_IMAGE_CodingJPEG should be changed to OMX_IMAGE_CodingRAWMPO when + // RAW format is supported + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else + { + portCheck.format.image.eColorFormat = portParams.mColorFormat; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + + //Stride for 1D tiler buffer is zero + portCheck.format.image.nStride = 0; + portCheck.nBufferSize = portParams.mStride * portParams.mWidth * portParams.mHeight; + portCheck.nBufferCountActual = portParams.mNumBufs; + } + else + { + CAMHAL_LOGEB("Unsupported port index 0x%x", (unsigned int)port); + } + + 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 + { + 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); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of eError=%x", __FUNCTION__, eError); + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::flushBuffers() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + TIMM_OSAL_ERRORTYPE err; + TIMM_OSAL_U32 uRequestedEvents = OMXCameraAdapter::CAMERA_PORT_FLUSH; + TIMM_OSAL_U32 pRetrievedEvents; + + if ( 0 != mFlushSem.Count() ) + { + CAMHAL_LOGEB("Error mFlushSem semaphore count %d", mFlushSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + LOG_FUNCTION_NAME; + + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + ///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, + OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, + 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, + mCameraAdapterParameters.mPrevPortIndex, + 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, + OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, + NULL); + CAMHAL_LOGDA("Flush event timeout expired"); + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + + return (ret | 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 | ErrorUtils::omxToAndroidError(eError)); +} + +///API to give the buffers to Adapter +status_t OMXCameraAdapter::useBuffers(CameraMode mode, void* 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].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mMaxQueueable = queueable; + ret = UseBuffersCapture(bufArr, num); + break; + + case CAMERA_VIDEO: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_MEASUREMENT: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreviewData(bufArr, num); + break; + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::UseBuffersPreviewData(void* bufArr, int num) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * measurementData = NULL; + uint32_t *buffers; + Mutex::Autolock 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 ; + buffers= (uint32_t*) bufArr; + } + + 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 | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::switchToExecuting() +{ + status_t ret = NO_ERROR; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + mStateSwitchLock.lock(); + msg.command = CommandHandler::CAMERA_SWITCH_TO_EXECUTING; + msg.arg1 = mErrorNotifier; + ret = mCommandHandler->put(&msg); + + LOG_FUNCTION_NAME; + + 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 | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::switchToLoaded() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mStateSwitchLock); + + if ( mComponentState == OMX_StateLoaded || mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGDA("Already in 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; + } + + ///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); + + 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; + + ///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; + } + + return (ret | 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 | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::UseBuffersPreview(void* 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 ; + uint32_t *buffers = (uint32_t*)bufArr; + + 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 ) + { + + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setLDC() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setNSF() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + CAMHAL_LOGDB("Camera Mode = %d", mCapMode); + + if( mCapMode == OMXCameraAdapter::VIDEO_MODE ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(mVnfEnabled); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + return ret; + } + + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(mVstabEnabled); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + return ret; + } + } + else + { + ret = enableVideoNoiseFilter(false); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + return ret; + } + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(false); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + return ret; + } + } + } + + ret = setSensorOrientation(mSensorOrientation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret); + mSensorOrientation = 0; + } + + ret = setVFramerate(mPreviewData->mMinFrameRate, mPreviewData->mMaxFrameRate); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("VFR configuration failed 0x%x", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + 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, + (OMX_U8*)buffers[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_UseBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + //pBufferHdr->pAppPrivate = (OMX_PTR)pBufferHdr; + 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; + eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp, + &pBufHdr, + mCameraAdapterParameters.mMeasurementPortIndex, + 0, + measurementData->mBufSize, + (OMX_U8*)(mPreviewDataBuffers[i])); + + if ( eError == OMX_ErrorNone ) + { + 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 | 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 | 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; + } + + 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(); + + apply3Asettings(mParameters3A); + //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); + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)mPreviewData->mBufferHeader[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError); + } + mFramesWithDucati++; +#ifdef DEGUG_LOG + mBuffersWithDucati.add((uint32_t)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); + 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); + } + + } + + // Enable Ancillary data. The nDCCStatus field is used to signify + // whether the preview frame is a snapshot + if ( OMX_ErrorNone == eError) + { + ret = setExtraData(true, OMX_ALL, OMX_AncillaryData); + } + + + if ( mPending3Asettings ) + apply3Asettings(mParameters3A); + + // enable focus callbacks just once here + // fixes an issue with slow callback registration in Ducati + if ( NO_ERROR == ret ) { + ret = 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(); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | 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 | ErrorUtils::omxToAndroidError(eError)); + +} + +status_t OMXCameraAdapter::stopPreview() +{ + 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 NO_ERROR; + } + + if ( mComponentState != OMX_StateExecuting ) + { + CAMHAL_LOGEA("Calling StopPreview() when not in EXECUTING state"); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + { + Mutex::Autolock 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(); + } + + ret = cancelAutoFocus(); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error canceling autofocus %d", ret); + // Error, but we probably still want to continue to stop preview + } + + 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; + } + + ///Register for Preview port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + mStopPreviewSem); + + ///Disable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + ///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); + } + + { + Mutex::Autolock lock(mPreviewDataBufferLock); + mPreviewDataBuffersAvailable.clear(); + } + + } + + CAMHAL_LOGDA("Disabling preview port"); + ret = mStopPreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + + //If somethiing bad happened while we wait + if (mComponentState == OMX_StateInvalid) + { + CAMHAL_LOGEA("Invalid State after Disabling preview port Exitting!!!"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview port disabled"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Timeout expired on preview port disable"); + goto EXIT; + } + + { + Mutex::Autolock lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + + switchToLoaded(); + + + mFirstTimeInit = true; + mPendingCaptureSettings = 0; + mFramesWithDucati = 0; + mFramesWithDisplay = 0; + mFramesWithEncoder = 0; + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + { + Mutex::Autolock lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | 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); + ret = BAD_VALUE; + } + else + { + mSensorOverclock = enable; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +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::autoFocus() +{ + status_t ret = NO_ERROR; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + { + Mutex::Autolock 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; + + return ret; +} + +status_t OMXCameraAdapter::takePicture() +{ + status_t ret = NO_ERROR; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + { + Mutex::Autolock 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_START_IMAGE_CAPTURE; + msg.arg1 = mErrorNotifier; + 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(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("switchToLoaded() failed 0x%x", ret); + goto exit; + } + + mOMXStateSwitch = false; + } + + if ( OMX_StateLoaded == mComponentState ) + { + + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setLDC() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setNSF() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + } + + if(mCapMode == OMXCameraAdapter::VIDEO_MODE) + { + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(mVnfEnabled); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(mVstabEnabled); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + } + } + else + { + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(false); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(false); + } + + 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; + int device_orientation = 0; + int mount_orientation = 0; + const char *facing_direction = NULL; + + // 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; + } + + if (mCapabilities) { + if (mCapabilities->get(CameraProperties::ORIENTATION_INDEX)) { + mount_orientation = atoi(mCapabilities->get(CameraProperties::ORIENTATION_INDEX)); + } + facing_direction = mCapabilities->get(CameraProperties::FACING_INDEX); + } + + // calculate device orientation relative to the sensor orientation + // front camera display is mirrored...needs to be accounted for when orientation + // is 90 or 270...since this will result in a flip on orientation otherwise + if (facing_direction && !strcmp(facing_direction, TICameraParameters::FACING_FRONT) && + (orientation == 90 || orientation == 270)) { + device_orientation = (orientation - mount_orientation + 360) % 360; + } else { // back-facing camera + device_orientation = (orientation + mount_orientation) % 360; + } + + if (device_orientation != mDeviceOrientation) { + mDeviceOrientation = device_orientation; + + mFaceDetectionLock.lock(); + if (mFaceDetectionRunning) { + // restart face detection with new rotation + setFaceDetection(true, mDeviceOrientation); + } + mFaceDetectionLock.unlock(); + } + 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 + TIUTILS::Message *msg = mEventSignalQ.itemAt(i); + if ( NULL != msg ) + { + Semaphore *sem = (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) +{ + Mutex::Autolock lock(mEventLock); + TIUTILS::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) + { + Semaphore *sem = (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)) { + TIUTILS::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) +{ + Mutex::Autolock lock(mEventLock); + TIUTILS::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) + { + Semaphore *sem = (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 Semaphore &semaphore) +{ + status_t ret = NO_ERROR; + ssize_t res; + Mutex::Autolock lock(mEventLock); + + LOG_FUNCTION_NAME; + TIUTILS::Message * msg = ( struct TIUTILS::Message * ) malloc(sizeof(struct TIUTILS::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; + + 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; + ALOGD("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) +{ + TIUTILS::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; +} + +/*========================================================*/ +/* @ 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); + sp fdResult = NULL; + unsigned int mask = 0xFFFF; + CameraFrame cameraFrame; + OMX_TI_PLATFORMPRIVATE *platformPrivate; + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_TI_ANCILLARYDATATYPE *ancillaryData = NULL; + bool snapshotFrame = false; + + res1 = res2 = NO_ERROR; + pPortParam = &(mCameraAdapterParameters.mCameraPortParams[pBuffHeader->nOutputPortIndex]); + + if ( !pBuffHeader || !pBuffHeader->pBuffer ) { + CAMHAL_LOGEA("NULL Buffer from OMX"); + return OMX_ErrorNone; + } + + if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW) + { + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return OMX_ErrorNone; + } + + if ( mWaitingForSnapshot ) + { + platformPrivate = (OMX_TI_PLATFORMPRIVATE*) pBuffHeader->pPlatformPrivate; + extraData = getExtradata((OMX_OTHER_EXTRADATATYPE*) platformPrivate->pMetaDataBuffer, + platformPrivate->nMetaDataSize, (OMX_EXTRADATATYPE) OMX_AncillaryData); + + if ( NULL != extraData ) + { + ancillaryData = (OMX_TI_ANCILLARYDATATYPE*) extraData->data; + snapshotFrame = ancillaryData->nDCCStatus; + mPending3Asettings |= SetFocus; + } + } + + recalculateFPS(); + { + Mutex::Autolock lock(mFaceDetectionLock); + if ( mFaceDetectionRunning && !mFaceDetectionPaused ) { + detectFaces(pBuffHeader, fdResult, pPortParam->mWidth, pPortParam->mHeight); + if ( NULL != fdResult.get() ) { + notifyFaceSubscribers(fdResult); + fdResult.clear(); + } + 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; + } + } + } + + ///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))) + { + 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((OMX_OTHER_EXTRADATATYPE*) platformPrivate->pMetaDataBuffer, + platformPrivate->nMetaDataSize, (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++; + } + + //ALOGV("FBD pBuffer = 0x%x", pBuffHeader->pBuffer); + + if( mWaitingForSnapshot ) + { + mSnapshotCount++; + + if ( (mSnapshotCount == 1) && + ((HIGH_SPEED == mCapMode) || (VIDEO_MODE == mCapMode)) ) + { + notifyShutterSubscribers(); + } + } + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + mFramesWithDisplay++; + + mFramesWithDucati--; + +#ifdef DEBUG_LOG + if(mBuffersWithDucati.indexOfKey((int)pBuffHeader->pBuffer)<0) + { + ALOGE("Buffer was never with Ducati!! 0x%x", pBuffHeader->pBuffer); + for(int i=0;ipBuffer); +#endif + + if(mDebugFcs) + CAMHAL_LOGEB("C[%d] D[%d] E[%d]", mFramesWithDucati, mFramesWithDisplay, mFramesWithEncoder); + + 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 = mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].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, 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; + + // 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; + } + + { + Mutex::Autolock lock(mBracketingLock); + if ( mBracketingEnabled ) + { + doBracketing(pBuffHeader, typeOfFrame); + return eError; + } + } + + if ( 1 > mCapturedFrames ) + { + goto EXIT; + } + + CAMHAL_LOGDB("Captured Frames: %d", mCapturedFrames); + + mCapturedFrames--; + + stat = sendCallBacks(cameraFrame, pBuffHeader, mask, pPortParam); + + } + else + { + CAMHAL_LOGEA("Frame received for non-(preview/capture/measure) port. This is yet to be supported"); + goto EXIT; + } + + if ( NO_ERROR != stat ) + { + CAMHAL_LOGDB("sendFrameToSubscribers error: %d", stat); + returnFrame(pBuffHeader->pBuffer, 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; + + { + Mutex::Autolock 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::sendFrame(CameraFrame &frame) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + + if ( NO_ERROR == ret ) + { + ret = sendFrameToSubscribers(&frame); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +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; + } + + Mutex::Autolock lock(mSubscriberLock); + + //frame.mFrameType = typeOfFrame; + frame.mFrameMask = mask; + frame.mBuffer = pBuffHeader->pBuffer; + 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; +} + +status_t OMXCameraAdapter::initCameraFrame( CameraFrame &frame, + OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, + int typeOfFrame, + 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; + } + + frame.mFrameType = typeOfFrame; + frame.mBuffer = pBuffHeader->pBuffer; + frame.mLength = pBuffHeader->nFilledLen; + frame.mAlignment = port->mStride; + frame.mOffset = pBuffHeader->nOffset; + frame.mWidth = port->mWidth; + frame.mHeight = port->mHeight; + + // Timestamp in pBuffHeader->nTimeStamp is derived on DUCATI side, which is + // is not same time value as derived using systemTime. It would be ideal to use + // exactly same time source across Android and Ducati, which is limited by + // system now. So, workaround for now is to find the time offset between the two + // time sources and compensate the difference, along with the latency involved + // in camera buffer reaching CameraHal. Also, Do timeset offset calculation only + // when recording is in progress, when nTimestamp will be populated by Camera + if ( onlyOnce && mRecording ) + { + mTimeSourceDelta = (pBuffHeader->nTimeStamp * 1000) - systemTime(SYSTEM_TIME_MONOTONIC); + mTimeSourceDelta += kCameraBufferLatencyNs; + onlyOnce = false; + } + + // Calculating the new video timestamp based on offset from ducati source. + frame.mTimestamp = (pBuffHeader->nTimeStamp * 1000) - mTimeSourceDelta; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool OMXCameraAdapter::CommandHandler::Handler() +{ + TIUTILS::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..."); + TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + { + Mutex::Autolock lock(mLock); + mCommandMsgQ.get(&msg); + } + CAMHAL_LOGDB("msg.command = %d", msg.command); + switch ( msg.command ) { + case CommandHandler::CAMERA_START_IMAGE_CAPTURE: + { + stat = mCameraAdapter->startImageCapture(); + 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; + } + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return false; +} + +bool OMXCameraAdapter::OMXCallbackHandler::Handler() +{ + TIUTILS::Message msg; + volatile int forever = 1; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + while(forever){ + TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + { + Mutex::Autolock lock(mLock); + mCommandMsgQ.get(&msg); + } + + 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; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + return false; +} + +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; + extraDataControl.eCameraView = OMX_2D; + + 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 | ErrorUtils::omxToAndroidError(eError)); +} + + +OMX_OTHER_EXTRADATATYPE *OMXCameraAdapter::getExtradata(OMX_OTHER_EXTRADATATYPE *extraData, OMX_U32 extraDataSize, OMX_EXTRADATATYPE type) { + OMX_U32 remainingSize = extraDataSize; + + if ( NULL != extraData ) { + while ( extraData->eType && extraData->nDataSize && extraData->data && + (remainingSize >= extraData->nSize)) { + if ( type == extraData->eType ) { + return extraData; + } + extraData = (OMX_OTHER_EXTRADATATYPE*) ((char*)extraData + extraData->nSize); + remainingSize -= extraData->nSize; + } + } + + // Required extradata type wasn't found + return NULL; +} + +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; + + mInitSem.Create(0); + mFlushSem.Create(0); + mUsePreviewDataSem.Create(0); + mUsePreviewSem.Create(0); + mUseCaptureSem.Create(0); + mStartPreviewSem.Create(0); + mStopPreviewSem.Create(0); + mStartCaptureSem.Create(0); + mStopCaptureSem.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; + + LOG_FUNCTION_NAME_EXIT; +} + +OMXCameraAdapter::~OMXCameraAdapter() +{ + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(gAdapterLock); + + if ( mOmxInitialized ) { + // return to OMX Loaded state + switchToLoaded(); + + // 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++ ) + { + TIUTILS::Message *msg = mEventSignalQ.itemAt(i); + //remove from queue and free msg + if ( NULL != msg ) + { + Semaphore *sem = (Semaphore*) msg->arg3; + sem->Signal(); + free(msg); + + } + } + mEventSignalQ.clear(); + } + + //Exit and free ref to command handling thread + if ( NULL != mCommandHandler.get() ) + { + TIUTILS::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() ) + { + TIUTILS::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* CameraAdapter_Factory(size_t sensor_index) +{ + CameraAdapter *adapter = NULL; + Mutex::Autolock 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("Camera adapter create failed!"); + } + + LOG_FUNCTION_NAME_EXIT; + + return adapter; +} + +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData ) +{ + 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; + + // initialize the callback handles + oCallbacks.EventHandler = android::OMXCameraAdapterEventHandler; + oCallbacks.EmptyBufferDone = android::OMXCameraAdapterEmptyBufferDone; + oCallbacks.FillBufferDone = android::OMXCameraAdapterFillBufferDone; + + // 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; +} + +extern "C" int CameraAdapter_Capabilities(CameraProperties::Properties* properties_array, + const unsigned int starting_camera, + const unsigned int max_camera) { + int num_cameras_supported = 0; + CameraProperties::Properties* properties = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_HANDLETYPE handle = NULL; + OMX_TI_CAPTYPE caps; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(gAdapterLock); + + if (!properties_array) { + CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("Error OMX_Init -0x%x", eError); + return eError; + } + + eError = OMXCameraAdapter::OMXCameraGetHandle(&handle); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError); + goto EXIT; + } + + // 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) { + // sensor select + OMX_CONFIG_SENSORSELECTTYPE sensorSelect; + OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE); + sensorSelect.eSensor = (OMX_SENSORSELECT) num_cameras_supported; + eError = OMX_SetConfig(handle, ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSensorSelect, &sensorSelect); + + if ( OMX_ErrorNone != eError ) { + break; + } + + // get and fill capabilities + properties = properties_array + starting_camera + num_cameras_supported; + OMXCameraAdapter::getCaps(properties, handle); + + // need to fill facing information + // assume that only sensor 0 is back facing + if (num_cameras_supported == 0) { + properties->set(CameraProperties::FACING_INDEX, TICameraParameters::FACING_BACK); + } else { + properties->set(CameraProperties::FACING_INDEX, TICameraParameters::FACING_FRONT); + } + + num_cameras_supported++; + } + + EXIT: + // clean up + if(handle) { + OMX_FreeHandle(handle); + handle=NULL; + } + OMX_Deinit(); + + LOG_FUNCTION_NAME_EXIT; + + return num_cameras_supported; +} + +}; + + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ diff --git a/camera/OMXCameraAdapter/OMXCapabilities.cpp b/camera/OMXCameraAdapter/OMXCapabilities.cpp new file mode 100644 index 0000000..e1323ee --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapabilities.cpp @@ -0,0 +1,1279 @@ +/* + * 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 android { + +#undef LOG_TAG + +// Maintain a separate tag for OMXCameraAdapter logs to isolate issues OMX specific +#define LOG_TAG "CameraHAL" + +/************************************ + * global constants and variables + *************************************/ + +#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) +#define FPS_MIN 5 +#define FPS_STEP 5 +#define FPS_RANGE_STEP 5 + +static const char PARAM_SEP[] = ","; +static const int PARAM_SEP_CHAR = ','; +static const uint32_t VFR_OFFSET = 8; +static const char VFR_BACKET_START[] = "("; +static const char VFR_BRACKET_END[] = ")"; +static const char FRAMERATE_COUNT = 10; + +/**** look up tables to translate OMX Caps to Parameter ****/ + +const CapResolution OMXCameraAdapter::mImageCapRes [] = { + { 4032, 3024, "4032x3024" }, + { 4000, 3000, "4000x3000" }, + { 3648, 2736, "3648x2736" }, + { 3264, 2448, "3264x2448" }, + { 2592, 1944, "2592x1944" }, + { 2592, 1728, "2592x1728" }, + { 2592, 1458, "2592x1458" }, + { 2048, 1536, "2048x1536" }, + { 1600, 1200, "1600x1200" }, + { 1280, 1024, "1280x1024" }, + { 1152, 864, "1152x864" }, + { 1280, 960, "1280x960" }, + { 640, 480, "640x480" }, + { 320, 240, "320x240" }, +}; + +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" }, + { 128, 96, "128x96" }, +}; + +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, CameraParameters::PIXEL_FORMAT_YUV422I }, + { OMX_COLOR_FormatYUV420SemiPlanar, CameraParameters::PIXEL_FORMAT_YUV420SP }, + { OMX_COLOR_Format16bitRGB565, CameraParameters::PIXEL_FORMAT_RGB565 }, + { OMX_COLOR_FormatRawBayer10bit, TICameraParameters::PIXEL_FORMAT_RAW }, + { OMX_COLOR_FormatYUV420SemiPlanar, CameraParameters::PIXEL_FORMAT_YUV420P }, +}; + +const CapFramerate OMXCameraAdapter::mFramerates [] = { + { 30, "30" }, + { 15, "15" }, +}; + +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 [] = { + { 300, "IMX060" }, + { 301, "OV5650" }, + { 305, "S5K4E1GA"}, + { 306, "S5K6A1GX03" } + // TODO(XXX): need to account for S3D camera later +}; + +// values for supported variable framerates sorted in ascending order +// CapU32Pair = (max fps, min fps, string representation) +const CapU32Pair OMXCameraAdapter::mVarFramerates [] = { + { 15, 15, "(15000,15000)"}, + { 30, 15, "(15000,30000)" }, + { 30, 24, "(24000,30000)" }, +// TODO(XXX): Removing 30,30 range to limit 1080p at 24fps. Will put back soon. +#if 0 + { 30, 30, "(30000,30000)" }, +#endif +}; +/************************************ + * static helper functions + *************************************/ + +// utility function to remove last seperator +void remove_last_sep(char* buffer) { + char* last_sep = NULL; + last_sep = strrchr(buffer, PARAM_SEP_CHAR); + if (last_sep != NULL) { + last_sep[0] = '\0'; + } +} + + +/***************************************** + * internal static function declarations + *****************************************/ + +/**** Utility functions to help translate OMX Caps to Parameter ****/ + +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 ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFramerateCap(OMX_U32 framerateMax, + OMX_U32 framerateMin, + const CapFramerate *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t ret = NO_ERROR; + bool minInserted = false; + bool maxInserted = false; + char tmpBuffer[FRAMERATE_COUNT]; + + LOG_FUNCTION_NAME; + + if ( ( NULL == buffer ) || ( NULL == cap ) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( (framerateMax >= cap[i].num) && (framerateMin <= cap[i].num) ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + + if ( cap[i].num == framerateMin ) { + minInserted = true; + } + } + if ( cap[i].num == framerateMax ) { + maxInserted = true; + } + } + + if ( !maxInserted ) { + memset(tmpBuffer, 0, FRAMERATE_COUNT); + snprintf(tmpBuffer, FRAMERATE_COUNT - 1, "%u,", ( unsigned int ) framerateMax); + strncat(buffer, tmpBuffer, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + + if ( !minInserted ) { + memset(tmpBuffer, 0, FRAMERATE_COUNT); + snprintf(tmpBuffer, FRAMERATE_COUNT - 1, "%u,", ( unsigned int ) framerateMin); + strncat(buffer, tmpBuffer, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + + remove_last_sep(buffer); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeVFramerateCap(OMX_TI_CAPTYPE &caps, + const CapU32Pair *cap, + size_t capCount, + char *buffer, + char *defaultRange, + size_t bufferSize) { + status_t ret = NO_ERROR; + uint32_t minVFR, maxVFR; + int default_index = -1; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + if(caps.ulPrvVarFPSModesCount < 1) { + return NO_ERROR; + } + + // Assumption: last range in tPrvVarFPSModes will be for S30FPSHD mode + minVFR = caps.tPrvVarFPSModes[caps.ulPrvVarFPSModesCount-1].nVarFPSMin >> VFR_OFFSET; + maxVFR = caps.tPrvVarFPSModes[caps.ulPrvVarFPSModesCount-1].nVarFPSMax >> VFR_OFFSET; + + if (minVFR < FPS_MIN) { + minVFR = FPS_MIN; + } + + for (unsigned int i = 0; i < capCount; i++) { + // add cap[i] if it is in range and maxVFR != minVFR + if ((maxVFR >= cap[i].num1) && (minVFR <= cap[i].num2)) { + if (buffer[0] != '\0') { + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + strncat(buffer, cap[i].param, bufferSize - 1); + + // choose the max variable framerate as default + if (cap[i].num1 != cap[i].num2) { + default_index = i; + } + } + } + + // if we haven't found any caps in the list to populate + // just use the min and max + if (buffer[0] == '\0') { + snprintf(buffer, bufferSize - 1, + "(%u,%u)", + minVFR * CameraHal::VFR_SCALE, + maxVFR * CameraHal::VFR_SCALE); + } + + if (default_index != -1) { + snprintf(defaultRange, (MAX_PROP_VALUE_LENGTH - 1), "%lu,%lu", + cap[default_index].num2 * CameraHal::VFR_SCALE, + cap[default_index].num1 * CameraHal::VFR_SCALE); + } else { + snprintf(defaultRange, (MAX_PROP_VALUE_LENGTH - 1), "%u,%u", + minVFR * CameraHal::VFR_SCALE, maxVFR * CameraHal::VFR_SCALE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +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 ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + ret++; + } + } + remove_last_sep(buffer); + + 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) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + remove_last_sep(buffer); + + 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) ) { + strncat(buffer, cap[i].param, bufferSize -1); + strncat(buffer, PARAM_SEP, 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]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + 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 { + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertPreviewSizes(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 preview sizes 0x%x", ret); + } else { + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + 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 { + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_VIDEO_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + 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 + strncat(supported, "0x0", MAX_PROP_NAME_LENGTH); + params->set(CameraProperties::SUPPORTED_THUMBNAIL_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + 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, TICameraParameters::ZOOM_UNSUPPORTED); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, TICameraParameters::ZOOM_UNSUPPORTED); + } else { + params->set(CameraProperties::ZOOM_SUPPORTED, TICameraParameters::ZOOM_SUPPORTED); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, TICameraParameters::ZOOM_SUPPORTED); + } + + LOG_FUNCTION_NAME; + + 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', MAX_PROP_VALUE_LENGTH); + + 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; + } + } + + if ( NO_ERROR == ret ) { + //jpeg is not supported in OMX capabilies yet + strncat(supported, CameraParameters::PIXEL_FORMAT_JPEG, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PICTURE_FORMATS, supported); + } + + LOG_FUNCTION_NAME; + + 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 + strncat(supported, CameraParameters::PIXEL_FORMAT_YUV420P, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PREVIEW_FORMATS, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFramerates(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 = encodeFramerateCap(caps.xFramerateMax >> VFR_OFFSET, + caps.xFramerateMin >> VFR_OFFSET, + mFramerates, + ARRAY_SIZE(mFramerates), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview framerates 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertVFramerates(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + char defaultRange[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeVFramerateCap(caps, + mVarFramerates, + ARRAY_SIZE(mVarFramerates), + supported, + defaultRange, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview framerate ranges 0x%x", ret); + } else { + params->set(CameraProperties::FRAMERATE_RANGE_SUPPORTED, supported); + CAMHAL_LOGDB("framerate ranges %s", supported); + params->set(CameraProperties::FRAMERATE_RANGE, DEFAULT_FRAMERATE_RANGE_IMAGE); + params->set(CameraProperties::FRAMERATE_RANGE_VIDEO, DEFAULT_FRAMERATE_RANGE_VIDEO); + params->set(CameraProperties::FRAMERATE_RANGE_IMAGE, DEFAULT_FRAMERATE_RANGE_IMAGE); + CAMHAL_LOGDB("Default framerate range: [%s]", DEFAULT_FRAMERATE_RANGE_IMAGE); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +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; + + 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; + + 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); + strncat(supported, PARAM_SEP, 1); + + if ( caps.bLensDistortionCorrectionSupported ) { + strncat(supported, TICameraParameters::IPP_LDC, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + if ( caps.bISONoiseFilterSupported ) { + strncat(supported, TICameraParameters::IPP_NSF, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + if ( caps.bISONoiseFilterSupported && caps.bLensDistortionCorrectionSupported ) { + strncat(supported, TICameraParameters::IPP_LDCNSF, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_IPP_MODES, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + params->set(CameraProperties::SUPPORTED_WHITE_BALANCE, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_EFFECTS, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + params->set(CameraProperties::SUPPORTED_EXPOSURE_MODES, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_FLASH_MODES, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_SCENE_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFocusModes(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.ulFocusModeCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFocusModes[i], FocusLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + // 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 + strncat(supported, CameraParameters::FOCUS_MODE_INFINITY, MAX_PROP_NAME_LENGTH); + } else { + // Focus is supported but these modes are not supported by the + // capability feature. Apply manually + strncat(supported, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, MAX_PROP_NAME_LENGTH); + } + + params->set(CameraProperties::SUPPORTED_FOCUS_MODES, supported); + + LOG_FUNCTION_NAME; + + 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 ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_ANTIBANDING, supported); + + LOG_FUNCTION_NAME; + + 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; + + return ret; +} + +status_t OMXCameraAdapter::insertLocks(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME + + params->set(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED, DEFAULT_LOCK_SUPPORTED); + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED, DEFAULT_LOCK_SUPPORTED); + + LOG_FUNCTION_NAME + + return ret; +} + +status_t OMXCameraAdapter::insertDefaults(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + 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); + char *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, DEFAULT_GBCE); + 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); + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_SIZE); + params->set(CameraProperties::PREVIEW_FORMAT, DEFAULT_PREVIEW_FORMAT); + params->set(CameraProperties::PREVIEW_FRAME_RATE, DEFAULT_FRAMERATE); + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_SIZE); + 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::VSTAB_SUPPORTED, DEFAULT_VSTAB_SUPPORTED); + 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); + if(caps.tSenMounting.nSenId == 305) { + params->set(CameraProperties::FOCAL_LENGTH, DEFAULT_FOCAL_LENGTH_PRIMARY); + } else { + params->set(CameraProperties::FOCAL_LENGTH, DEFAULT_FOCAL_LENGTH_SECONDARY); + } + params->set(CameraProperties::HOR_ANGLE, DEFAULT_HOR_ANGLE); + params->set(CameraProperties::VER_ANGLE, DEFAULT_VER_ANGLE); + params->set(CameraProperties::VIDEO_SNAPSHOT_SUPPORTED, DEFAULT_VIDEO_SNAPSHOT_SUPPORTED); + params->set(CameraProperties::VIDEO_SIZE, DEFAULT_VIDEO_SIZE); + params->set(CameraProperties::PREFERRED_PREVIEW_SIZE_FOR_VIDEO, DEFAULT_PREFERRED_PREVIEW_SIZE_FOR_VIDEO); + + LOG_FUNCTION_NAME; + + 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', MAX_PROP_VALUE_LENGTH); + + // 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, MAX_PROP_NAME_LENGTH); + params->set(CameraProperties::CAMERA_NAME, supported); + + // 2) Assign mounting rotation + params->set(CameraProperties::ORIENTATION_INDEX, caps.tSenMounting.nRotation); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertCapabilities(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + 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 = insertVFramerates(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 = 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); + + } + + //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 = insertDefaults(params, caps); + } + + + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/***************************************** + * public exposed function declarations + *****************************************/ + +status_t OMXCameraAdapter::getCaps(CameraProperties::Properties* params, OMX_HANDLETYPE handle) { + status_t ret = NO_ERROR; + int caps_size = 0; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CAPTYPE** caps = NULL;; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + MemoryManager memMgr; + + LOG_FUNCTION_NAME; + + // allocate tiler (or ion) buffer for caps (size is always a multiple of 4K) + caps_size = ((sizeof(OMX_TI_CAPTYPE)+4095)/4096)*4096; + caps = (OMX_TI_CAPTYPE**) memMgr.allocateBuffer(0, 0, NULL, caps_size, 1); + + 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[0], OMX_TI_CAPTYPE); + caps[0]->nPortIndex = OMX_ALL; + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = caps_size; + sharedBuffer.pSharedBuff = (OMX_U8 *) caps[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"); + } + + // Translate and insert Ducati capabilities to CameraProperties + if ( NO_ERROR == ret ) { + ret = insertCapabilities(params, *caps[0]); + } + + CAMHAL_LOGDB("sen mount id=%u", (unsigned int)caps[0]->tSenMounting.nSenId); + + + EXIT: + if (caps) { + memMgr.freeBuffer((void*) caps); + caps = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +}; + diff --git a/camera/OMXCameraAdapter/OMXCapture.cpp b/camera/OMXCameraAdapter/OMXCapture.cpp new file mode 100644 index 0000000..0a622cc --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapture.cpp @@ -0,0 +1,1229 @@ +/* + * 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. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + + +namespace android { + +status_t OMXCameraAdapter::setParametersCapture(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + int w, h; + OMX_COLOR_FORMATTYPE pixFormat; + const char *valstr = NULL; + int varint = 0; + + LOG_FUNCTION_NAME; + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + 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, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + mPictureFormatFromClient = CameraParameters::PIXEL_FORMAT_YUV422I; + } else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + mPictureFormatFromClient = CameraParameters::PIXEL_FORMAT_YUV420SP; + } else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + mPictureFormatFromClient = CameraParameters::PIXEL_FORMAT_RGB565; + } else if (strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_JPEG) == 0) { + CAMHAL_LOGDA("JPEG format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingNone; + mPictureFormatFromClient = CameraParameters::PIXEL_FORMAT_JPEG; + } else if (strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_JPS) == 0) { + CAMHAL_LOGDA("JPS format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingJPS; + mPictureFormatFromClient = TICameraParameters::PIXEL_FORMAT_JPS; + } else if (strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_MPO) == 0) { + CAMHAL_LOGDA("MPO format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingMPO; + mPictureFormatFromClient = TICameraParameters::PIXEL_FORMAT_MPO; + } else if (strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_RAW) == 0) { + CAMHAL_LOGDA("RAW Picture format selected"); + pixFormat = OMX_COLOR_FormatRawBayer10bit; + mPictureFormatFromClient = TICameraParameters::PIXEL_FORMAT_RAW; + } else { + CAMHAL_LOGEA("Invalid format, JPEG format selected as default"); + pixFormat = OMX_COLOR_FormatUnused; + mPictureFormatFromClient = NULL; + } + } else { + CAMHAL_LOGEA("Picture format is NULL, defaulting to JPEG"); + pixFormat = OMX_COLOR_FormatUnused; + mPictureFormatFromClient = NULL; + } + + // 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)) && + (pixFormat == OMX_COLOR_FormatUnused) ) { + CAMHAL_LOGDA("Capturing in video mode...selecting yuv422i"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + if ( pixFormat != cap->mColorFormat ) + { + mPendingCaptureSettings |= SetFormat; + cap->mColorFormat = pixFormat; + } + +#ifdef OMAP_ENHANCEMENT + + str = params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + if ( NULL != str ) { + parseExpRange(str, mExposureBracketingValues, EXP_BRACKET_RANGE, mExposureBracketingValidEntries); + } else { + // if bracketing was previously set...we set again before capturing to clear + if (mExposureBracketingValidEntries) mPendingCaptureSettings |= SetExpBracket; + mExposureBracketingValidEntries = 0; + } + +#endif + + varint = params.getInt(CameraParameters::KEY_ROTATION); + if ( varint != -1 ) + { + if ( ( unsigned int ) varint != mPictureRotation) { + mPendingCaptureSettings |= SetRotation; + } + mPictureRotation = varint; + } + 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 ) && (mCapMode == OMXCameraAdapter::VIDEO_MODE)) + { + 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); + + varint = params.getInt(TICameraParameters::KEY_BURST); + if ( varint >= 1 ) + { + if (varint != mBurstFrames) { + mPendingCaptureSettings |= SetExpBracket; + } + mBurstFrames = varint; + } + else + { + if (mBurstFrames != 1) mPendingCaptureSettings |= SetExpBracket; + mBurstFrames = 1; + } + + CAMHAL_LOGVB("Burst Frames set %d", mBurstFrames); + +#endif + + varint = params.getInt(CameraParameters::KEY_JPEG_QUALITY); + if ( ( varint >= MIN_JPEG_QUALITY ) && + ( varint <= MAX_JPEG_QUALITY ) ) + { + if ( ( unsigned int ) 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(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + if ( varint >= 0 ) + { + if ( ( unsigned int ) 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(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + if ( varint >= 0 ) + { + if ( ( unsigned int ) 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(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + if ( ( varint >= MIN_JPEG_QUALITY ) && + ( varint <= MAX_JPEG_QUALITY ) ) + { + if ( ( unsigned int ) 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; + } + + if (mPendingCaptureSettings) { + disableImagePort(); + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getPictureBufferSize(size_t &length, 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]; + + imgCaptureData->mNumBufs = bufferCount; + + // check if image port is already configured... + // if it already configured then we don't have to query again + if (!mCaptureConfigured) { + ret = setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *imgCaptureData); + } + + if ( ret == NO_ERROR ) + { + length = imgCaptureData->mBufSize; + } + else + { + CAMHAL_LOGEB("setFormat() failed 0x%x", ret); + length = 0; + } + } + + CAMHAL_LOGDB("getPictureBufferSize %d", length); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::parseExpRange(const char *rangeStr, + int * expRange, + size_t count, + size_t &validEntries) +{ + status_t ret = NO_ERROR; + char *ctx, *expVal; + char *tmp = NULL; + size_t i = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == rangeStr ) + { + return -EINVAL; + } + + if ( NULL == expRange ) + { + return -EINVAL; + } + + if ( NO_ERROR == ret ) + { + tmp = ( char * ) malloc( strlen(rangeStr) + 1 ); + + if ( NULL == tmp ) + { + CAMHAL_LOGEA("No resources for temporary buffer"); + return -1; + } + memset(tmp, '\0', strlen(rangeStr) + 1); + + } + + if ( NO_ERROR == ret ) + { + strncpy(tmp, rangeStr, strlen(rangeStr) ); + expVal = strtok_r( (char *) tmp, CameraHal::PARAMS_DELIMITER, &ctx); + + i = 0; + while ( ( NULL != expVal ) && ( i < count ) ) + { + expRange[i] = atoi(expVal); + expVal = strtok_r(NULL, CameraHal::PARAMS_DELIMITER, &ctx); + i++; + } + validEntries = i; + } + + if ( NULL != tmp ) + { + free(tmp); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setExposureBracketing(int *evValues, + size_t evCount, + size_t frameCount) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAPTUREMODETYPE expCapMode; + OMX_CONFIG_EXTCAPTUREMODETYPE extExpCapMode; + + 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 ) + { + 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 = OMX_BracketExposureRelativeInEV; + extExpCapMode.tBracketConfigType.nNbrBracketingValues = evCount - 1; + } + + for ( unsigned int i = 0 ; i < evCount ; i++ ) + { + 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 ) + { + currentBufferIdx = ( unsigned int ) pBuffHeader->pAppPrivate; + + 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; + setFrameRefCount(imgCaptureData->mBufferHeader[nextBufferIdx]->pBuffer, typeOfFrame, 1); + returnFrame(imgCaptureData->mBufferHeader[nextBufferIdx]->pBuffer, typeOfFrame); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::sendBracketFrames() +{ + status_t ret = NO_ERROR; + int currentBufferIdx; + 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 ) + { + + currentBufferIdx = mLastBracetingBufferIdx; + do + { + currentBufferIdx++; + currentBufferIdx %= imgCaptureData->mNumBufs; + if (!mBracketingBuffersQueued[currentBufferIdx] ) + { + CameraFrame cameraFrame; + sendCallBacks(cameraFrame, + imgCaptureData->mBufferHeader[currentBufferIdx], + imgCaptureData->mImageType, + imgCaptureData); + } + } 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; + } + + { + Mutex::Autolock 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 ) + { + Mutex::Autolock 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; + mLastBracetingBufferIdx = mBracketingBuffersQueuedCount - 1; + + for ( int i = 0 ; i < imgCaptureData->mNumBufs ; i++ ) + { + mBracketingBuffersQueued[i] = true; + } + + } + } + + if ( NO_ERROR == ret ) + { + + ret = startImageCapture(); + { + Mutex::Autolock 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; + + Mutex::Autolock lock(mBracketingLock); + + if ( NULL != mBracketingBuffersQueued ) + { + delete [] mBracketingBuffersQueued; + } + + ret = stopImageCapture(); + + mBracketingBuffersQueued = NULL; + mBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mLastBracetingBufferIdx = 0; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startImageCapture() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * capData = NULL; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + Mutex::Autolock 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 ((getNextState() & (CAPTURE_ACTIVE|BRACKETING_ACTIVE)) == 0) { + CAMHAL_LOGDA("trying starting capture when already canceled"); + return NO_ERROR; + } + + // Camera framework doesn't expect face callbacks once capture is triggered + pauseFaceDetection(true); + + //During bracketing image capture is already active + { + Mutex::Autolock lock(mBracketingLock); + if ( mBracketingEnabled ) + { + //Stop bracketing, activate normal burst for the remaining images + mBracketingEnabled = false; + mCapturedFrames = mBracketingRange; + ret = sendBracketFrames(); + if(ret != NO_ERROR) + goto EXIT; + else + return ret; + } + } + + if ( NO_ERROR == ret ) { + if (mPendingCaptureSettings & SetRotation) { + mPendingCaptureSettings &= ~SetRotation; + ret = setPictureRotation(mPictureRotation); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error configuring image rotation %x", ret); + } + } + } + + // need to enable wb data for video snapshot to fill in exif data + if ((ret == NO_ERROR) && (mCapMode == VIDEO_MODE)) { + // video snapshot uses wb data from snapshot frame + ret = setExtraData(true, mCameraAdapterParameters.mPrevPortIndex, OMX_WhiteBalance); + } + + //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 ( NO_ERROR == ret ) { + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + ///Queue all the buffers on capture port + for ( int index = 0 ; index < capData->mNumBufs ; index++ ) { + CAMHAL_LOGDB("Queuing buffer on Capture port - 0x%x", + ( unsigned int ) capData->mBufferHeader[index]->pBuffer); + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)capData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + 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) { + 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); + } + } + + //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; + } + + } + + return (ret | ErrorUtils::omxToAndroidError(eError)); + +EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + setExtraData(false, mCameraAdapterParameters.mPrevPortIndex, OMX_WhiteBalance); + mWaitingForSnapshot = false; + mCaptureSignalled = false; + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | 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; + + Mutex::Autolock 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; + } + + //Disable the callback first + mWaitingForSnapshot = false; + mSnapshotCount = 0; + + // 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); + } + } + + // After capture, face detection should be disabled + // and application needs to restart face detection + stopFaceDetection(); + + //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) { + 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; + } + } + + // had to enable wb data for video snapshot to fill in exif data + // now that we are done...disable + if ((ret == NO_ERROR) && (mCapMode == VIDEO_MODE)) { + ret = setExtraData(false, mCameraAdapterParameters.mPrevPortIndex, OMX_WhiteBalance); + } + + CAMHAL_LOGDB("Capture set - 0x%x", eError); + + mCaptureSignalled = true; //set this to true if we exited because of timeout + + { + Mutex::Autolock lock(mFrameCountMutex); + mFrameCount = 0; + mFirstFrameCondition.broadcast(); + } + + return (ret | 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); + } + + { + Mutex::Autolock lock(mFrameCountMutex); + mFrameCount = 0; + mFirstFrameCondition.broadcast(); + } + + performCleanupAfterError(); + LOG_FUNCTION_NAME_EXIT; + return (ret | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::disableImagePort(){ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *imgCaptureData = NULL; + + if (!mCaptureConfigured) { + return NO_ERROR; + } + + mCaptureConfigured = false; + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + ///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; + } + + EXIT: + return (ret | ErrorUtils::omxToAndroidError(eError)); +} + + +status_t OMXCameraAdapter::UseBuffersCapture(void* bufArr, int num) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * imgCaptureData = NULL; + uint32_t *buffers = (uint32_t*)bufArr; + OMXCameraPortParameters cap; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( 0 != mUseCaptureSem.Count() ) + { + CAMHAL_LOGEB("Error mUseCaptureSem semaphore count %d", mUseCaptureSem.Count()); + return BAD_VALUE; + } + + // capture is already configured...we can skip this step + if (mCaptureConfigured) { + + if ( NO_ERROR == ret ) + { + ret = setupEXIF(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring EXIF Buffer %x", ret); + } + } + + mCapturedFrames = mBurstFrames; + return NO_ERROR; + } + + imgCaptureData->mNumBufs = num; + + //TODO: Support more pixelformats + + CAMHAL_LOGDB("Params Width = %d", (int)imgCaptureData->mWidth); + CAMHAL_LOGDB("Params Height = %d", (int)imgCaptureData->mWidth); + + 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 & SetExpBracket) { + mPendingCaptureSettings &= ~SetExpBracket; + ret = setExposureBracketing( mExposureBracketingValues, + mExposureBracketingValidEntries, mBurstFrames); + if ( ret != NO_ERROR ) { + CAMHAL_LOGEB("setExposureBracketing() failed %d", ret); + goto EXIT; + } + } + + if (mPendingCaptureSettings & SetQuality) { + mPendingCaptureSettings &= ~SetQuality; + ret = setImageQuality(mPictureQuality); + if ( NO_ERROR != ret) { + CAMHAL_LOGEB("Error configuring image quality %x", ret); + goto EXIT; + } + } + + ///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)buffers[index], + (int)imgCaptureData->mBufSize); + + eError = OMX_UseBuffer(mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mImagePortIndex, + 0, + mCaptureBuffersLength, + (OMX_U8*)buffers[index]); + + CAMHAL_LOGDB("OMX_UseBuffer = 0x%x", eError); + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR) 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; + } + + //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 ) + { + CAMHAL_LOGDA("Port enabled"); + } + else + { + ret |= RemoveEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port enable"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + ret = setupEXIF(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring EXIF Buffer %x", ret); + } + } + + mCapturedFrames = mBurstFrames; + mCaptureConfigured = true; + + return (ret | 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 | ErrorUtils::omxToAndroidError(eError)); + +} + +}; diff --git a/camera/OMXCameraAdapter/OMXDefaults.cpp b/camera/OMXCameraAdapter/OMXDefaults.cpp new file mode 100644 index 0000000..aff38d1 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXDefaults.cpp @@ -0,0 +1,83 @@ +/* + * 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 android { + +#undef LOG_TAG +#define LOG_TAG "CameraHAL" + +#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"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE_RANGE_IMAGE[] = "15000,30000"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE_RANGE_VIDEO[]="24000,30000"; +const char OMXCameraAdapter::DEFAULT_IPP[] = "ldc-nsf"; +const char OMXCameraAdapter::DEFAULT_GBCE[] = "disable"; +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_PICTURE_SIZE[] = "320x240"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_FORMAT[] = "yuv420sp"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE[] = "30"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_SIZE[] = "640x480"; +const char OMXCameraAdapter::DEFAULT_NUM_PREV_BUFS[] = "6"; +const char OMXCameraAdapter::DEFAULT_NUM_PIC_BUFS[] = "1"; +const char OMXCameraAdapter::DEFAULT_MAX_FOCUS_AREAS[] = "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[] = "false"; +const char OMXCameraAdapter::DEFAULT_VSTAB_SUPPORTED[] = "true"; +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_FOCAL_LENGTH_PRIMARY[] = "3.43"; +const char OMXCameraAdapter::DEFAULT_FOCAL_LENGTH_SECONDARY[] = "1.95"; +const char OMXCameraAdapter::DEFAULT_HOR_ANGLE[] = "54.8"; +const char OMXCameraAdapter::DEFAULT_VER_ANGLE[] = "42.5"; +const char OMXCameraAdapter::DEFAULT_AE_LOCK[] = "false"; +const char OMXCameraAdapter::DEFAULT_AWB_LOCK[] = "false"; +const char OMXCameraAdapter::DEFAULT_MAX_NUM_METERING_AREAS[] = "0"; +const char OMXCameraAdapter::DEFAULT_LOCK_SUPPORTED[] = "true"; +const char OMXCameraAdapter::DEFAULT_LOCK_UNSUPPORTED[] = "false"; +const char OMXCameraAdapter::DEFAULT_VIDEO_SNAPSHOT_SUPPORTED[] = "true"; +const char OMXCameraAdapter::DEFAULT_VIDEO_SIZE[] = "1920x1080"; +const char OMXCameraAdapter::DEFAULT_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "1920x1080"; +}; + diff --git a/camera/OMXCameraAdapter/OMXExif.cpp b/camera/OMXCameraAdapter/OMXExif.cpp new file mode 100644 index 0000000..76d94bd --- /dev/null +++ b/camera/OMXCameraAdapter/OMXExif.cpp @@ -0,0 +1,839 @@ +/* + * 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. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include + +namespace android { + +status_t OMXCameraAdapter::setParametersEXIF(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + double gpsPos; + + LOG_FUNCTION_NAME; + + if( ( valstr = params.get(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(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(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(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(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(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(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 *sharedPtr = NULL; + struct timeval sTv; + struct tm *pTime; + OMXCameraPortParameters * capData = NULL; + MemoryManager memMgr; + OMX_U8** memmgr_buf_array = NULL; + 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 = (OMX_U8 **)memMgr.allocateBuffer(0, 0, NULL, buf_size, 1); + sharedBuffer.pSharedBuff = ( OMX_U8 * ) memmgr_buf_array[0]; + + if ( NULL == sharedBuffer.pSharedBuff ) + { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = -1; + } + + //Extra data begins right after the EXIF configuration structure. + sharedPtr = sharedBuffer.pSharedBuff + sizeof(OMX_TI_CONFIG_EXIF_TAGS); + } + + if ( NO_ERROR == ret ) + { + exifTags = ( OMX_TI_CONFIG_EXIF_TAGS * ) sharedBuffer.pSharedBuff; + 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 - sharedBuffer.pSharedBuff ); + 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 - sharedBuffer.pSharedBuff ); + 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 - sharedBuffer.pSharedBuff ); + 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 - sharedBuffer.pSharedBuff ); + 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 - sharedBuffer.pSharedBuff ); + 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 ) + { + memMgr.freeBuffer(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 ) { + + ALOGE("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; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXFD.cpp b/camera/OMXCameraAdapter/OMXFD.cpp new file mode 100644 index 0000000..15f8d05 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFD.cpp @@ -0,0 +1,490 @@ +/* + * 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. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +#define FACE_DETECTION_THRESHOLD 80 + +// constants used for face smooth filtering +static const int HorizontalFilterThreshold = 40; +static const int VerticalFilterThreshold = 40; +static const int HorizontalFaceSizeThreshold = 30; +static const int VerticalFaceSizeThreshold = 30; + + +namespace android { + +status_t OMXCameraAdapter::setParametersFD(const 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; + + Mutex::Autolock lock(mFaceDetectionLock); + + ret = setFaceDetection(true, mDeviceOrientation); + 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); + + Mutex::Autolock lock(mFaceDetectionLock); + + ret = setFaceDetection(false, mDeviceOrientation); + if (ret != NO_ERROR) { + goto out; + } + + // Reset 3A settings + ret = setParameters3A(mParams, state); + if (ret != NO_ERROR) { + goto out; + } + + if (mPending3Asettings) { + apply3Asettings(mParameters3A); + } + + faceDetectionNumFacesLastOutput = 0; + out: + return ret; +} + +void OMXCameraAdapter::pauseFaceDetection(bool pause) +{ + Mutex::Autolock lock(mFaceDetectionLock); + // pausing will only take affect if fd is already running + if (mFaceDetectionRunning) { + mFaceDetectionPaused = pause; + faceDetectionNumFacesLastOutput = 0; + } +} + +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 ) + { + ret = setExtraData(enable, mCameraAdapterParameters.mPrevPortIndex, 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::detectFaces(OMX_BUFFERHEADERTYPE* pBuffHeader, + sp &result, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_FACERESULT *faceResult; + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_FACEDETECTIONTYPE *faceData; + OMX_TI_PLATFORMPRIVATE *platformPrivate; + camera_frame_metadata_t *faces; + + 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; + } + + platformPrivate = (OMX_TI_PLATFORMPRIVATE *) (pBuffHeader->pPlatformPrivate); + if ( NULL != platformPrivate ) { + if ( sizeof(OMX_TI_PLATFORMPRIVATE) == platformPrivate->nSize ) { + 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); + } else { + CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE size mismatch: expected = %d, received = %d", + ( unsigned int ) sizeof(OMX_TI_PLATFORMPRIVATE), + ( unsigned int ) platformPrivate->nSize); + return -EINVAL; + } + } else { + CAMHAL_LOGDA("Invalid OMX_TI_PLATFORMPRIVATE"); + return-EINVAL; + } + + + if ( 0 >= platformPrivate->nMetaDataSize ) { + CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE nMetaDataSize is size is %d", + ( unsigned int ) platformPrivate->nMetaDataSize); + return -EINVAL; + } + + extraData = getExtradata((OMX_OTHER_EXTRADATATYPE *) (platformPrivate->pMetaDataBuffer), + platformPrivate->nMetaDataSize, (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_LOGDA("Invalid OMX_OTHER_EXTRADATATYPE"); + 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_LOGDB("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; + } + + ret = encodeFaceCoordinates(faceData, &faces, previewWidth, previewHeight); + + if ( NO_ERROR == ret ) { + result = new CameraFDResult(faces); + } else { + result.clear(); + result = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData, + camera_frame_metadata_t **pFaces, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + camera_face_t *faces; + camera_frame_metadata_t *faceResult; + size_t hRange, vRange; + double tmp; + + LOG_FUNCTION_NAME; + + if ( NULL == faceData ) { + CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE parameter"); + return EINVAL; + } + + LOG_FUNCTION_NAME + + hRange = CameraFDResult::RIGHT - CameraFDResult::LEFT; + vRange = CameraFDResult::BOTTOM - CameraFDResult::TOP; + + faceResult = ( camera_frame_metadata_t * ) malloc(sizeof(camera_frame_metadata_t)); + if ( NULL == faceResult ) { + return -ENOMEM; + } + + if ( 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 ) { + return -ENOMEM; + } + + /** + / * 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 (mDeviceOrientation == 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 (mDeviceOrientation == 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] = CameraFDResult::INVALID_DATA; + faces[i].left_eye[1] = CameraFDResult::INVALID_DATA; + faces[i].right_eye[0] = CameraFDResult::INVALID_DATA; + faces[i].right_eye[1] = CameraFDResult::INVALID_DATA; + faces[i].mouth[0] = CameraFDResult::INVALID_DATA; + faces[i].mouth[1] = CameraFDResult::INVALID_DATA; + i++; + } + + faceResult->number_of_faces = i; + faceResult->faces = faces; + + for (int i = 0; i < faceResult->number_of_faces; i++) + { + 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 ( (abs(tempCenterX - centerX) < HorizontalFilterThreshold) && + (abs(tempCenterY - centerY) < VerticalFilterThreshold) ) + { + // Found Face. It did not move too far. + // Now check size of rectangle compare to last output + if ( (abs (tempSizeX -sizeX) < HorizontalFaceSizeThreshold) && + (abs (tempSizeY -sizeY) < VerticalFaceSizeThreshold) ) + { + // Rectangle is almost same as last time + // Output exactly what was done for this face last time. + faces[i] = faceDetectionLastOutput[j]; + } + else + { + // TODO(XXX): Rectangle size changed but position is same. + // Possibly we can apply just positional correctness. + } + } + } + } + + // Save this output for next iteration + for (int i = 0; i < faceResult->number_of_faces; i++) + { + faceDetectionLastOutput[i] = faces[i]; + } + faceDetectionNumFacesLastOutput = faceResult->number_of_faces; + } else { + faceResult->number_of_faces = 0; + faceResult->faces = NULL; + } + + *pFaces = faceResult; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXFocus.cpp b/camera/OMXCameraAdapter/OMXFocus.cpp new file mode 100644 index 0000000..32478af --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFocus.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 OMXFocus.cpp +* +* This file contains functionality for handling focus configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#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 android { + +status_t OMXCameraAdapter::setParametersFocus(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + Vector< sp > tempAreas; + size_t MAX_FOCUS_AREAS; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mFocusAreasLock); + + str = params.get(CameraParameters::KEY_FOCUS_AREAS); + + MAX_FOCUS_AREAS = atoi(params.get(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; + + 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; + 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; + } + + 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); + + // 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_FocusStatusUnableToReach || + focusStatus.eFocusStatus == OMX_FocusStatusLost ) ) { + focusControl.eFocusControl = OMX_IMAGE_FocusControlAutoLock; + } + + if ( focusControl.eFocusControl != OMX_IMAGE_FocusControlAuto ) + { + 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"); + } + + // configure focus timeout based on capture mode + timeout = (mCapMode == VIDEO_MODE) ? + ( ( nsecs_t ) AF_VIDEO_CALLBACK_TIMEOUT * 1000 ) : + ( ( nsecs_t ) AF_IMAGE_CALLBACK_TIMEOUT * 1000 ); + + { + Mutex::Autolock lock(mDoAFMutex); + 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 { + 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 ErrorUtils::omxToAndroidError(eError); + } 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()'. + Mutex::Autolock lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + + + 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 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 or Inifinity + if ( ( focusMode.eFocusControl != OMX_IMAGE_FocusControlAuto ) && + ( focusMode.eFocusControl != ( OMX_IMAGE_FOCUSCONTROLTYPE ) + OMX_IMAGE_FocusControlAutoInfinity ) ) { + stopAutoFocus(); + } 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; + } + // 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"); + ret = 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(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, 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, + 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(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; + MemoryManager memMgr; + 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; + focusAreas = (OMX_ALGOAREASTYPE**) memMgr.allocateBuffer(0, 0, NULL, areasSize, 1); + + 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[0], OMX_ALGOAREASTYPE); + + focusAreas[0]->nPortIndex = OMX_ALL; + focusAreas[0]->nNumAreas = mFocusAreas.size(); + focusAreas[0]->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[0]->nNumAreas = 0; + } + + for ( unsigned int n = 0; n < mFocusAreas.size(); n++) + { + // transform the coordinates to 3A-type coordinates + mFocusAreas.itemAt(n)->transfrom(mPreviewData->mWidth, + mPreviewData->mHeight, + focusAreas[0]->tAlgoAreas[n].nTop, + focusAreas[0]->tAlgoAreas[n].nLeft, + focusAreas[0]->tAlgoAreas[n].nWidth, + focusAreas[0]->tAlgoAreas[n].nHeight); + + focusAreas[0]->tAlgoAreas[n].nLeft = + ( focusAreas[0]->tAlgoAreas[n].nLeft * TOUCH_FOCUS_RANGE ) / mPreviewData->mWidth; + focusAreas[0]->tAlgoAreas[n].nTop = + ( focusAreas[0]->tAlgoAreas[n].nTop* TOUCH_FOCUS_RANGE ) / mPreviewData->mHeight; + focusAreas[0]->tAlgoAreas[n].nWidth = + ( focusAreas[0]->tAlgoAreas[n].nWidth * TOUCH_FOCUS_RANGE ) / mPreviewData->mWidth; + focusAreas[0]->tAlgoAreas[n].nHeight = + ( focusAreas[0]->tAlgoAreas[n].nHeight * TOUCH_FOCUS_RANGE ) / mPreviewData->mHeight; + focusAreas[0]->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[0]->tAlgoAreas[n].nTop, (int)focusAreas[0]->tAlgoAreas[n].nLeft, + (int)focusAreas[0]->tAlgoAreas[n].nWidth, (int)focusAreas[0]->tAlgoAreas[n].nHeight, + (int)focusAreas[0]->tAlgoAreas[n].nPriority); + } + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = areasSize; + sharedBuffer.pSharedBuff = (OMX_U8 *) focusAreas[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 != focusAreas) + { + memMgr.freeBuffer((void*) focusAreas); + focusAreas = NULL; + } + } + + 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; + BaseCameraAdapter::getNextState(nextState); + + 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) { + Mutex::Autolock lock(mDoAFMutex); + mDoAFCond.broadcast(); + } + return; + } + + if ( ( eFocusStatus.eFocusStatus != OMX_FocusStatusRequest ) && + ( eFocusStatus.eFocusStatus != OMX_FocusStatusOff ) ) { + // signal doAutoFocus when a end of scan message comes + // ignore start of scan + Mutex::Autolock 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); +} + +}; diff --git a/camera/OMXCameraAdapter/OMXZoom.cpp b/camera/OMXCameraAdapter/OMXZoom.cpp new file mode 100644 index 0000000..eec7691 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXZoom.cpp @@ -0,0 +1,296 @@ +/* + * 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. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +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 CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + Mutex::Autolock 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(CameraParameters::KEY_ZOOM); + if( ( zoom >= 0 ) && ( zoom < ZOOM_STAGES ) ) + { + 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) || ( ( ZOOM_STAGES - 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; + Mutex::Autolock 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; + + Mutex::Autolock lock(mZoomLock); + + CAMHAL_LOGDB("Start smooth zoom target = %d, mCurrentIdx = %d", + targetIdx, + mCurrentZoomIdx); + + if ( ( targetIdx >= 0 ) && ( targetIdx < ZOOM_STAGES ) ) + { + 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; + Mutex::Autolock 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; +} + +}; -- cgit v1.2.3