/*
* 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;
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;
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));
}
};