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