839 lines
30 KiB
C++
839 lines
30 KiB
C++
/*
|
|
* 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 <math.h>
|
|
|
|
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;
|
|
}
|
|
|
|
};
|