1 /*
2  * Copyright (C) Texas Instruments - http://www.ti.com/
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18 * @file OMXExif.cpp
19 *
20 * This file contains functionality for handling EXIF insertion.
21 *
22 */
23 
24 #include "CameraHal.h"
25 #include "OMXCameraAdapter.h"
26 #include <math.h>
27 
28 namespace Ti {
29 namespace Camera {
30 
setParametersEXIF(const android::CameraParameters & params,BaseCameraAdapter::AdapterState state)31 status_t OMXCameraAdapter::setParametersEXIF(const android::CameraParameters &params,
32                                              BaseCameraAdapter::AdapterState state)
33 {
34     status_t ret = NO_ERROR;
35     const char *valstr = NULL;
36     double gpsPos;
37 
38     LOG_FUNCTION_NAME;
39 
40     if( ( valstr = params.get(android::CameraParameters::KEY_GPS_LATITUDE) ) != NULL )
41         {
42         gpsPos = strtod(valstr, NULL);
43 
44         if ( convertGPSCoord(gpsPos,
45                              mEXIFData.mGPSData.mLatDeg,
46                              mEXIFData.mGPSData.mLatMin,
47                              mEXIFData.mGPSData.mLatSec,
48                              mEXIFData.mGPSData.mLatSecDiv ) == NO_ERROR )
49             {
50 
51             if ( 0 < gpsPos )
52                 {
53                 strncpy(mEXIFData.mGPSData.mLatRef, GPS_NORTH_REF, GPS_REF_SIZE);
54                 }
55             else
56                 {
57                 strncpy(mEXIFData.mGPSData.mLatRef, GPS_SOUTH_REF, GPS_REF_SIZE);
58                 }
59 
60             mEXIFData.mGPSData.mLatValid = true;
61             }
62         else
63             {
64             mEXIFData.mGPSData.mLatValid = false;
65             }
66         }
67     else
68         {
69         mEXIFData.mGPSData.mLatValid = false;
70         }
71 
72     if( ( valstr = params.get(android::CameraParameters::KEY_GPS_LONGITUDE) ) != NULL )
73         {
74         gpsPos = strtod(valstr, NULL);
75 
76         if ( convertGPSCoord(gpsPos,
77                              mEXIFData.mGPSData.mLongDeg,
78                              mEXIFData.mGPSData.mLongMin,
79                              mEXIFData.mGPSData.mLongSec,
80                              mEXIFData.mGPSData.mLongSecDiv) == NO_ERROR )
81             {
82 
83             if ( 0 < gpsPos )
84                 {
85                 strncpy(mEXIFData.mGPSData.mLongRef, GPS_EAST_REF, GPS_REF_SIZE);
86                 }
87             else
88                 {
89                 strncpy(mEXIFData.mGPSData.mLongRef, GPS_WEST_REF, GPS_REF_SIZE);
90                 }
91 
92             mEXIFData.mGPSData.mLongValid= true;
93             }
94         else
95             {
96             mEXIFData.mGPSData.mLongValid = false;
97             }
98         }
99     else
100         {
101         mEXIFData.mGPSData.mLongValid = false;
102         }
103 
104     if( ( valstr = params.get(android::CameraParameters::KEY_GPS_ALTITUDE) ) != NULL )
105         {
106         gpsPos = strtod(valstr, NULL);
107         mEXIFData.mGPSData.mAltitude = floor(fabs(gpsPos));
108         if (gpsPos < 0) {
109             mEXIFData.mGPSData.mAltitudeRef = 1;
110         } else {
111             mEXIFData.mGPSData.mAltitudeRef = 0;
112         }
113         mEXIFData.mGPSData.mAltitudeValid = true;
114         }
115     else
116         {
117         mEXIFData.mGPSData.mAltitudeValid= false;
118         }
119 
120     if( (valstr = params.get(android::CameraParameters::KEY_GPS_TIMESTAMP)) != NULL )
121         {
122         long gpsTimestamp = strtol(valstr, NULL, 10);
123         struct tm *timeinfo = gmtime( ( time_t * ) & (gpsTimestamp) );
124         if ( NULL != timeinfo )
125             {
126             mEXIFData.mGPSData.mTimeStampHour = timeinfo->tm_hour;
127             mEXIFData.mGPSData.mTimeStampMin = timeinfo->tm_min;
128             mEXIFData.mGPSData.mTimeStampSec = timeinfo->tm_sec;
129             mEXIFData.mGPSData.mTimeStampValid = true;
130             }
131         else
132             {
133             mEXIFData.mGPSData.mTimeStampValid = false;
134             }
135         }
136     else
137         {
138         mEXIFData.mGPSData.mTimeStampValid = false;
139         }
140 
141     if( ( valstr = params.get(android::CameraParameters::KEY_GPS_TIMESTAMP) ) != NULL )
142         {
143         long gpsDatestamp = strtol(valstr, NULL, 10);
144         struct tm *timeinfo = gmtime( ( time_t * ) & (gpsDatestamp) );
145         if ( NULL != timeinfo )
146             {
147             strftime(mEXIFData.mGPSData.mDatestamp, GPS_DATESTAMP_SIZE, "%Y:%m:%d", timeinfo);
148             mEXIFData.mGPSData.mDatestampValid = true;
149             }
150         else
151             {
152             mEXIFData.mGPSData.mDatestampValid = false;
153             }
154         }
155     else
156         {
157         mEXIFData.mGPSData.mDatestampValid = false;
158         }
159 
160     if( ( valstr = params.get(android::CameraParameters::KEY_GPS_PROCESSING_METHOD) ) != NULL )
161         {
162         strncpy(mEXIFData.mGPSData.mProcMethod, valstr, GPS_PROCESSING_SIZE-1);
163         mEXIFData.mGPSData.mProcMethodValid = true;
164         }
165     else
166         {
167         mEXIFData.mGPSData.mProcMethodValid = false;
168         }
169 
170     if( ( valstr = params.get(TICameraParameters::KEY_GPS_MAPDATUM) ) != NULL )
171         {
172         strncpy(mEXIFData.mGPSData.mMapDatum, valstr, GPS_MAPDATUM_SIZE-1);
173         mEXIFData.mGPSData.mMapDatumValid = true;
174         }
175     else
176         {
177         mEXIFData.mGPSData.mMapDatumValid = false;
178         }
179 
180     if( ( valstr = params.get(TICameraParameters::KEY_GPS_VERSION) ) != NULL )
181         {
182         strncpy(mEXIFData.mGPSData.mVersionId, valstr, GPS_VERSION_SIZE-1);
183         mEXIFData.mGPSData.mVersionIdValid = true;
184         }
185     else
186         {
187         mEXIFData.mGPSData.mVersionIdValid = false;
188         }
189 
190     if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MODEL ) ) != NULL )
191         {
192         CAMHAL_LOGVB("EXIF Model: %s", valstr);
193         strncpy(mEXIFData.mModel, valstr, EXIF_MODEL_SIZE - 1);
194         mEXIFData.mModelValid= true;
195         }
196     else
197         {
198         mEXIFData.mModelValid= false;
199         }
200 
201     if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MAKE ) ) != NULL )
202         {
203         CAMHAL_LOGVB("EXIF Make: %s", valstr);
204         strncpy(mEXIFData.mMake, valstr, EXIF_MAKE_SIZE - 1);
205         mEXIFData.mMakeValid = true;
206         }
207     else
208         {
209         mEXIFData.mMakeValid= false;
210         }
211 
212 
213     if( ( valstr = params.get(android::CameraParameters::KEY_FOCAL_LENGTH) ) != NULL ) {
214         CAMHAL_LOGVB("EXIF Focal length: %s", valstr);
215         ExifElementsTable::stringToRational(valstr,
216                                             &mEXIFData.mFocalNum,
217                                             &mEXIFData.mFocalDen);
218     } else {
219         mEXIFData.mFocalNum = 0;
220         mEXIFData.mFocalDen = 0;
221     }
222 
223 
224     LOG_FUNCTION_NAME_EXIT;
225 
226     return ret;
227 }
228 
setupEXIF()229 status_t OMXCameraAdapter::setupEXIF()
230 {
231     status_t ret = NO_ERROR;
232     OMX_ERRORTYPE eError = OMX_ErrorNone;
233     OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer;
234     OMX_TI_CONFIG_EXIF_TAGS *exifTags;
235     unsigned char *startPtr = NULL;
236     unsigned char *sharedPtr = NULL;
237     struct timeval sTv;
238     struct tm *pTime;
239     OMXCameraPortParameters * capData = NULL;
240     CameraBuffer *memmgr_buf_array;
241     int buf_size = 0;
242 
243     LOG_FUNCTION_NAME;
244 
245     sharedBuffer.pSharedBuff = NULL;
246     capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex];
247 
248     if ( OMX_StateInvalid == mComponentState )
249         {
250         CAMHAL_LOGEA("OMX component is in invalid state");
251         ret = -EINVAL;
252         }
253 
254     if ( NO_ERROR == ret )
255         {
256         OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER);
257         sharedBuffer.nPortIndex = mCameraAdapterParameters.mImagePortIndex;
258 
259         //We allocate the shared buffer dynamically based on the
260         //requirements of the EXIF tags. The additional buffers will
261         //get stored after the EXIF configuration structure and the pointers
262         //will contain offsets within the shared buffer itself.
263         buf_size = sizeof(OMX_TI_CONFIG_EXIF_TAGS) +
264                           ( EXIF_MODEL_SIZE ) +
265                           ( EXIF_MAKE_SIZE ) +
266                           ( EXIF_DATE_TIME_SIZE ) +
267                           ( GPS_MAPDATUM_SIZE ) +
268                           ( GPS_PROCESSING_SIZE );
269         buf_size = ((buf_size+4095)/4096)*4096;
270         sharedBuffer.nSharedBuffSize = buf_size;
271 
272         memmgr_buf_array = mMemMgr.allocateBufferList(0, 0, NULL, buf_size, 1);
273         sharedBuffer.pSharedBuff = (OMX_U8*)camera_buffer_get_omx_ptr(&memmgr_buf_array[0]);
274         startPtr =  ( OMX_U8 * ) memmgr_buf_array[0].opaque;
275 
276         if ( NULL == startPtr)
277             {
278             CAMHAL_LOGEA("No resources to allocate OMX shared buffer");
279             ret = -1;
280             }
281 
282         //Extra data begins right after the EXIF configuration structure.
283         sharedPtr = startPtr + sizeof(OMX_TI_CONFIG_EXIF_TAGS);
284         }
285 
286     if ( NO_ERROR == ret )
287         {
288         exifTags = ( OMX_TI_CONFIG_EXIF_TAGS * ) startPtr;
289         OMX_INIT_STRUCT_PTR (exifTags, OMX_TI_CONFIG_EXIF_TAGS);
290         exifTags->nPortIndex = mCameraAdapterParameters.mImagePortIndex;
291 
292         eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp,
293                                ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags,
294                                &sharedBuffer );
295         if ( OMX_ErrorNone != eError )
296             {
297             CAMHAL_LOGEB("Error while retrieving EXIF configuration structure 0x%x", eError);
298             ret = -1;
299             }
300         }
301 
302     if ( NO_ERROR == ret )
303         {
304         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusModel ) &&
305               ( mEXIFData.mModelValid ) )
306             {
307             strncpy(( char * ) sharedPtr,
308                     mEXIFData.mModel,
309                     EXIF_MODEL_SIZE - 1);
310 
311             exifTags->pModelBuff = ( OMX_S8 * ) ( sharedPtr - startPtr );
312             exifTags->ulModelBuffSizeBytes = strlen((char*)sharedPtr) + 1;
313             sharedPtr += EXIF_MODEL_SIZE;
314             exifTags->eStatusModel = OMX_TI_TagUpdated;
315             }
316 
317          if ( ( OMX_TI_TagReadWrite == exifTags->eStatusMake) &&
318                ( mEXIFData.mMakeValid ) )
319              {
320              strncpy( ( char * ) sharedPtr,
321                       mEXIFData.mMake,
322                       EXIF_MAKE_SIZE - 1);
323 
324              exifTags->pMakeBuff = ( OMX_S8 * ) ( sharedPtr - startPtr );
325              exifTags->ulMakeBuffSizeBytes = strlen((char*)sharedPtr) + 1;
326              sharedPtr += EXIF_MAKE_SIZE;
327              exifTags->eStatusMake = OMX_TI_TagUpdated;
328              }
329 
330         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusFocalLength ))
331         {
332             if (mEXIFData.mFocalNum || mEXIFData.mFocalDen ) {
333                 exifTags->ulFocalLength[0] = (OMX_U32) mEXIFData.mFocalNum;
334                 exifTags->ulFocalLength[1] = (OMX_U32) mEXIFData.mFocalDen;
335                 CAMHAL_LOGVB("exifTags->ulFocalLength = [%u] [%u]",
336                              (unsigned int)(exifTags->ulFocalLength[0]),
337                              (unsigned int)(exifTags->ulFocalLength[1]));
338                 exifTags->eStatusFocalLength = OMX_TI_TagUpdated;
339             }
340         }
341 
342          if ( OMX_TI_TagReadWrite == exifTags->eStatusDateTime )
343              {
344              int status = gettimeofday (&sTv, NULL);
345              pTime = localtime (&sTv.tv_sec);
346              if ( ( 0 == status ) && ( NULL != pTime ) )
347                 {
348                 snprintf(( char * ) sharedPtr, EXIF_DATE_TIME_SIZE,
349                          "%04d:%02d:%02d %02d:%02d:%02d",
350                          pTime->tm_year + 1900,
351                          pTime->tm_mon + 1,
352                          pTime->tm_mday,
353                          pTime->tm_hour,
354                          pTime->tm_min,
355                          pTime->tm_sec );
356                 }
357 
358              exifTags->pDateTimeBuff = ( OMX_S8 * ) ( sharedPtr - startPtr );
359              sharedPtr += EXIF_DATE_TIME_SIZE;
360              exifTags->ulDateTimeBuffSizeBytes = EXIF_DATE_TIME_SIZE;
361              exifTags->eStatusDateTime = OMX_TI_TagUpdated;
362              }
363 
364          if ( OMX_TI_TagReadWrite == exifTags->eStatusImageWidth )
365              {
366              exifTags->ulImageWidth = capData->mWidth;
367              exifTags->eStatusImageWidth = OMX_TI_TagUpdated;
368              }
369 
370          if ( OMX_TI_TagReadWrite == exifTags->eStatusImageHeight )
371              {
372              exifTags->ulImageHeight = capData->mHeight;
373              exifTags->eStatusImageHeight = OMX_TI_TagUpdated;
374              }
375 
376          if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLatitude ) &&
377               ( mEXIFData.mGPSData.mLatValid ) )
378             {
379             exifTags->ulGpsLatitude[0] = abs(mEXIFData.mGPSData.mLatDeg);
380             exifTags->ulGpsLatitude[2] = abs(mEXIFData.mGPSData.mLatMin);
381             exifTags->ulGpsLatitude[4] = abs(mEXIFData.mGPSData.mLatSec);
382             exifTags->ulGpsLatitude[1] = 1;
383             exifTags->ulGpsLatitude[3] = 1;
384             exifTags->ulGpsLatitude[5] = abs(mEXIFData.mGPSData.mLatSecDiv);
385             exifTags->eStatusGpsLatitude = OMX_TI_TagUpdated;
386             }
387 
388         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpslatitudeRef ) &&
389              ( mEXIFData.mGPSData.mLatValid ) )
390             {
391             exifTags->cGpslatitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLatRef[0];
392             exifTags->cGpslatitudeRef[1] = '\0';
393             exifTags->eStatusGpslatitudeRef = OMX_TI_TagUpdated;
394             }
395 
396          if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitude ) &&
397               ( mEXIFData.mGPSData.mLongValid ) )
398             {
399             exifTags->ulGpsLongitude[0] = abs(mEXIFData.mGPSData.mLongDeg);
400             exifTags->ulGpsLongitude[2] = abs(mEXIFData.mGPSData.mLongMin);
401             exifTags->ulGpsLongitude[4] = abs(mEXIFData.mGPSData.mLongSec);
402             exifTags->ulGpsLongitude[1] = 1;
403             exifTags->ulGpsLongitude[3] = 1;
404             exifTags->ulGpsLongitude[5] = abs(mEXIFData.mGPSData.mLongSecDiv);
405             exifTags->eStatusGpsLongitude = OMX_TI_TagUpdated;
406             }
407 
408         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitudeRef ) &&
409              ( mEXIFData.mGPSData.mLongValid ) )
410             {
411             exifTags->cGpsLongitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLongRef[0];
412             exifTags->cGpsLongitudeRef[1] = '\0';
413             exifTags->eStatusGpsLongitudeRef = OMX_TI_TagUpdated;
414             }
415 
416         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitude ) &&
417              ( mEXIFData.mGPSData.mAltitudeValid) )
418             {
419             exifTags->ulGpsAltitude[0] = ( OMX_U32 ) mEXIFData.mGPSData.mAltitude;
420             exifTags->ulGpsAltitude[1] = 1;
421             exifTags->eStatusGpsAltitude = OMX_TI_TagUpdated;
422             }
423 
424         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitudeRef ) &&
425              ( mEXIFData.mGPSData.mAltitudeValid) )
426             {
427             exifTags->ucGpsAltitudeRef = (OMX_U8) mEXIFData.mGPSData.mAltitudeRef;
428             exifTags->eStatusGpsAltitudeRef = OMX_TI_TagUpdated;
429             }
430 
431         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsMapDatum ) &&
432              ( mEXIFData.mGPSData.mMapDatumValid ) )
433             {
434             memcpy(sharedPtr, mEXIFData.mGPSData.mMapDatum, GPS_MAPDATUM_SIZE);
435 
436             exifTags->pGpsMapDatumBuff = ( OMX_S8 * ) ( sharedPtr - startPtr );
437             exifTags->ulGpsMapDatumBuffSizeBytes = GPS_MAPDATUM_SIZE;
438             exifTags->eStatusGpsMapDatum = OMX_TI_TagUpdated;
439             sharedPtr += GPS_MAPDATUM_SIZE;
440             }
441 
442         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsProcessingMethod ) &&
443              ( mEXIFData.mGPSData.mProcMethodValid ) )
444             {
445             exifTags->pGpsProcessingMethodBuff = ( OMX_S8 * ) ( sharedPtr - startPtr );
446             memcpy(sharedPtr, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
447             sharedPtr += sizeof(ExifAsciiPrefix);
448 
449             memcpy(sharedPtr,
450                    mEXIFData.mGPSData.mProcMethod,
451                    ( GPS_PROCESSING_SIZE - sizeof(ExifAsciiPrefix) ) );
452             exifTags->ulGpsProcessingMethodBuffSizeBytes = GPS_PROCESSING_SIZE;
453             exifTags->eStatusGpsProcessingMethod = OMX_TI_TagUpdated;
454             sharedPtr += GPS_PROCESSING_SIZE;
455             }
456 
457         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsVersionId ) &&
458              ( mEXIFData.mGPSData.mVersionIdValid ) )
459             {
460             exifTags->ucGpsVersionId[0] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[0];
461             exifTags->ucGpsVersionId[1] =  ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[1];
462             exifTags->ucGpsVersionId[2] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[2];
463             exifTags->ucGpsVersionId[3] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[3];
464             exifTags->eStatusGpsVersionId = OMX_TI_TagUpdated;
465             }
466 
467         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsTimeStamp ) &&
468              ( mEXIFData.mGPSData.mTimeStampValid ) )
469             {
470             exifTags->ulGpsTimeStamp[0] = mEXIFData.mGPSData.mTimeStampHour;
471             exifTags->ulGpsTimeStamp[2] = mEXIFData.mGPSData.mTimeStampMin;
472             exifTags->ulGpsTimeStamp[4] = mEXIFData.mGPSData.mTimeStampSec;
473             exifTags->ulGpsTimeStamp[1] = 1;
474             exifTags->ulGpsTimeStamp[3] = 1;
475             exifTags->ulGpsTimeStamp[5] = 1;
476             exifTags->eStatusGpsTimeStamp = OMX_TI_TagUpdated;
477             }
478 
479         if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsDateStamp ) &&
480              ( mEXIFData.mGPSData.mDatestampValid ) )
481             {
482             strncpy( ( char * ) exifTags->cGpsDateStamp,
483                          ( char * ) mEXIFData.mGPSData.mDatestamp,
484                          GPS_DATESTAMP_SIZE );
485             exifTags->eStatusGpsDateStamp = OMX_TI_TagUpdated;
486             }
487 
488         eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
489                                ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags,
490                                &sharedBuffer );
491 
492         if ( OMX_ErrorNone != eError )
493             {
494             CAMHAL_LOGEB("Error while setting EXIF configuration 0x%x", eError);
495             ret = -1;
496             }
497         }
498 
499     if ( NULL != memmgr_buf_array )
500         {
501         mMemMgr.freeBufferList(memmgr_buf_array);
502         }
503 
504     LOG_FUNCTION_NAME_EXIT;
505 
506     return ret;
507 }
508 
setupEXIF_libjpeg(ExifElementsTable * exifTable,OMX_TI_ANCILLARYDATATYPE * pAncillaryData,OMX_TI_WHITEBALANCERESULTTYPE * pWhiteBalanceData)509 status_t OMXCameraAdapter::setupEXIF_libjpeg(ExifElementsTable* exifTable,
510                                              OMX_TI_ANCILLARYDATATYPE* pAncillaryData,
511                                              OMX_TI_WHITEBALANCERESULTTYPE* pWhiteBalanceData)
512 {
513     status_t ret = NO_ERROR;
514     OMX_ERRORTYPE eError = OMX_ErrorNone;
515     struct timeval sTv;
516     struct tm *pTime;
517     OMXCameraPortParameters * capData = NULL;
518 
519     LOG_FUNCTION_NAME;
520 
521     capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex];
522 
523     if ((NO_ERROR == ret) && (mEXIFData.mModelValid)) {
524         ret = exifTable->insertElement(TAG_MODEL, mEXIFData.mModel);
525     }
526 
527      if ((NO_ERROR == ret) && (mEXIFData.mMakeValid)) {
528         ret = exifTable->insertElement(TAG_MAKE, mEXIFData.mMake);
529      }
530 
531     if ((NO_ERROR == ret)) {
532         if (mEXIFData.mFocalNum || mEXIFData.mFocalDen) {
533             char temp_value[256]; // arbitrarily long string
534             snprintf(temp_value,
535                     sizeof(temp_value)/sizeof(char),
536                     "%u/%u",
537                     mEXIFData.mFocalNum,
538                     mEXIFData.mFocalDen);
539             ret = exifTable->insertElement(TAG_FOCALLENGTH, temp_value);
540 
541         }
542     }
543 
544     if ((NO_ERROR == ret)) {
545         int status = gettimeofday (&sTv, NULL);
546         pTime = localtime (&sTv.tv_sec);
547         char temp_value[EXIF_DATE_TIME_SIZE + 1];
548         if ((0 == status) && (NULL != pTime)) {
549             snprintf(temp_value, EXIF_DATE_TIME_SIZE,
550                      "%04d:%02d:%02d %02d:%02d:%02d",
551                      pTime->tm_year + 1900,
552                      pTime->tm_mon + 1,
553                      pTime->tm_mday,
554                      pTime->tm_hour,
555                      pTime->tm_min,
556                      pTime->tm_sec );
557             ret = exifTable->insertElement(TAG_DATETIME, temp_value);
558         }
559      }
560 
561     if ((NO_ERROR == ret)) {
562         char temp_value[5];
563         snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%lu", capData->mWidth);
564         ret = exifTable->insertElement(TAG_IMAGE_WIDTH, temp_value);
565      }
566 
567     if ((NO_ERROR == ret)) {
568         char temp_value[5];
569         snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%lu", capData->mHeight);
570         ret = exifTable->insertElement(TAG_IMAGE_LENGTH, temp_value);
571      }
572 
573     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLatValid)) {
574         char temp_value[256]; // arbitrarily long string
575         snprintf(temp_value,
576                  sizeof(temp_value)/sizeof(char) - 1,
577                  "%d/%d,%d/%d,%d/%d",
578                  abs(mEXIFData.mGPSData.mLatDeg), 1,
579                  abs(mEXIFData.mGPSData.mLatMin), 1,
580                  abs(mEXIFData.mGPSData.mLatSec), abs(mEXIFData.mGPSData.mLatSecDiv));
581         ret = exifTable->insertElement(TAG_GPS_LAT, temp_value);
582     }
583 
584     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLatValid)) {
585         ret = exifTable->insertElement(TAG_GPS_LAT_REF, mEXIFData.mGPSData.mLatRef);
586     }
587 
588     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLongValid)) {
589         char temp_value[256]; // arbitrarily long string
590         snprintf(temp_value,
591                  sizeof(temp_value)/sizeof(char) - 1,
592                  "%d/%d,%d/%d,%d/%d",
593                  abs(mEXIFData.mGPSData.mLongDeg), 1,
594                  abs(mEXIFData.mGPSData.mLongMin), 1,
595                  abs(mEXIFData.mGPSData.mLongSec), abs(mEXIFData.mGPSData.mLongSecDiv));
596         ret = exifTable->insertElement(TAG_GPS_LONG, temp_value);
597     }
598 
599     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mLongValid)) {
600         ret = exifTable->insertElement(TAG_GPS_LONG_REF, mEXIFData.mGPSData.mLongRef);
601     }
602 
603     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mAltitudeValid)) {
604         char temp_value[256]; // arbitrarily long string
605         snprintf(temp_value,
606                  sizeof(temp_value)/sizeof(char) - 1,
607                  "%d/%d",
608                  abs( mEXIFData.mGPSData.mAltitude), 1);
609         ret = exifTable->insertElement(TAG_GPS_ALT, temp_value);
610     }
611 
612     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mAltitudeValid)) {
613         char temp_value[5];
614         snprintf(temp_value,
615                  sizeof(temp_value)/sizeof(char) - 1,
616                  "%d", mEXIFData.mGPSData.mAltitudeRef);
617         ret = exifTable->insertElement(TAG_GPS_ALT_REF, temp_value);
618     }
619 
620     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mMapDatumValid)) {
621         ret = exifTable->insertElement(TAG_GPS_MAP_DATUM, mEXIFData.mGPSData.mMapDatum);
622     }
623 
624     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mProcMethodValid)) {
625         char temp_value[GPS_PROCESSING_SIZE];
626 
627         memcpy(temp_value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
628         memcpy(temp_value + sizeof(ExifAsciiPrefix),
629                 mEXIFData.mGPSData.mProcMethod,
630                 (GPS_PROCESSING_SIZE - sizeof(ExifAsciiPrefix)));
631         ret = exifTable->insertElement(TAG_GPS_PROCESSING_METHOD, temp_value);
632     }
633 
634     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mVersionIdValid)) {
635         char temp_value[256]; // arbitrarily long string
636         snprintf(temp_value,
637                  sizeof(temp_value)/sizeof(char) - 1,
638                  "%d,%d,%d,%d",
639                  mEXIFData.mGPSData.mVersionId[0],
640                  mEXIFData.mGPSData.mVersionId[1],
641                  mEXIFData.mGPSData.mVersionId[2],
642                  mEXIFData.mGPSData.mVersionId[3]);
643         ret = exifTable->insertElement(TAG_GPS_VERSION_ID, temp_value);
644     }
645 
646     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mTimeStampValid)) {
647         char temp_value[256]; // arbitrarily long string
648         snprintf(temp_value,
649                  sizeof(temp_value)/sizeof(char) - 1,
650                  "%d/%d,%d/%d,%d/%d",
651                  mEXIFData.mGPSData.mTimeStampHour, 1,
652                  mEXIFData.mGPSData.mTimeStampMin, 1,
653                  mEXIFData.mGPSData.mTimeStampSec, 1);
654         ret = exifTable->insertElement(TAG_GPS_TIMESTAMP, temp_value);
655     }
656 
657     if ((NO_ERROR == ret) && (mEXIFData.mGPSData.mDatestampValid) ) {
658         ret = exifTable->insertElement(TAG_GPS_DATESTAMP, mEXIFData.mGPSData.mDatestamp);
659     }
660 
661     if (NO_ERROR == ret) {
662         const char* exif_orient =
663                 ExifElementsTable::degreesToExifOrientation(mPictureRotation);
664 
665         if (exif_orient) {
666            ret = exifTable->insertElement(TAG_ORIENTATION, exif_orient);
667         }
668     }
669 
670     // fill in short and ushort tags
671     if (NO_ERROR == ret) {
672         char temp_value[2];
673         temp_value[1] = '\0';
674 
675         // AWB
676         if (mParameters3A.WhiteBallance == OMX_WhiteBalControlAuto) {
677             temp_value[0] = '0';
678         } else {
679             temp_value[0] = '1';
680         }
681         exifTable->insertElement(TAG_WHITEBALANCE, temp_value);
682 
683         // MeteringMode
684         // TODO(XXX): only supporting this metering mode at the moment, may change in future
685         temp_value[0] = '2';
686         exifTable->insertElement(TAG_METERING_MODE, temp_value);
687 
688         // ExposureProgram
689         // TODO(XXX): only supporting this exposure program at the moment, may change in future
690         temp_value[0] = '3';
691         exifTable->insertElement(TAG_EXPOSURE_PROGRAM, temp_value);
692 
693         // ColorSpace
694         temp_value[0] = '1';
695         exifTable->insertElement(TAG_COLOR_SPACE, temp_value);
696 
697         temp_value[0] = '2';
698         exifTable->insertElement(TAG_SENSING_METHOD, temp_value);
699 
700         temp_value[0] = '1';
701         exifTable->insertElement(TAG_CUSTOM_RENDERED, temp_value);
702     }
703 
704     if (pAncillaryData && (NO_ERROR == ret)) {
705         unsigned int numerator = 0, denominator = 0;
706         char temp_value[256];
707         unsigned int temp_num = 0;
708 
709         // DigitalZoomRatio
710         snprintf(temp_value,
711                  sizeof(temp_value)/sizeof(char),
712                  "%u/%u",
713                  pAncillaryData->nDigitalZoomFactor, 1024);
714         exifTable->insertElement(TAG_DIGITALZOOMRATIO, temp_value);
715 
716         // ExposureTime
717         snprintf(temp_value,
718                  sizeof(temp_value)/sizeof(char),
719                  "%u/%u",
720                  pAncillaryData->nExposureTime, 1000000);
721         exifTable->insertElement(TAG_EXPOSURETIME, temp_value);
722 
723         // ApertureValue and FNumber
724         snprintf(temp_value,
725                  sizeof(temp_value)/sizeof(char),
726                  "%u/%u",
727                  pAncillaryData->nApertureValue, 100);
728         exifTable->insertElement(TAG_FNUMBER, temp_value);
729         exifTable->insertElement(TAG_APERTURE, temp_value);
730 
731         // ISO
732         snprintf(temp_value,
733                  sizeof(temp_value)/sizeof(char),
734                  "%u,0,0",
735                  pAncillaryData->nCurrentISO);
736         exifTable->insertElement(TAG_ISO_EQUIVALENT, temp_value);
737 
738         // ShutterSpeed
739         snprintf(temp_value,
740                  sizeof(temp_value)/sizeof(char),
741                  "%f",
742                  log(pAncillaryData->nExposureTime) / log(2));
743         ExifElementsTable::stringToRational(temp_value, &numerator, &denominator);
744         snprintf(temp_value, sizeof(temp_value)/sizeof(char), "%u/%u", numerator, denominator);
745         exifTable->insertElement(TAG_SHUTTERSPEED, temp_value);
746 
747         // Flash
748         if (mParameters3A.FlashMode == OMX_IMAGE_FlashControlAuto) {
749             if(pAncillaryData->nFlashStatus) temp_num = 0x19; // Flash fired, auto mode
750             else temp_num = 0x18; // Flash did not fire, auto mode
751         } else if (mParameters3A.FlashMode == OMX_IMAGE_FlashControlOn) {
752             if(pAncillaryData->nFlashStatus) temp_num = 0x9; // Flash fired, compulsory flash mode
753             else temp_num = 0x10; // Flash did not fire, compulsory flash mode
754         } else if(pAncillaryData->nFlashStatus) {
755             temp_num = 0x1; // Flash fired
756         } else {
757             temp_num = 0x0; // Flash did not fire
758         }
759         snprintf(temp_value,
760                  sizeof(temp_value)/sizeof(char),
761                  "%u", temp_num);
762         exifTable->insertElement(TAG_FLASH, temp_value);
763 
764         if (pWhiteBalanceData) {
765             unsigned int lightsource = 0;
766             unsigned int colourtemp = pWhiteBalanceData->nColorTemperature;
767             bool flash_fired = (temp_num & 0x1); // value from flash above
768 
769             // stole this from framework/tools_library/src/tools_sys_exif_tags.c
770             if( colourtemp <= 3200 ) {
771                 lightsource = 3; // Tungsten
772             } else if( colourtemp > 3200 && colourtemp <= 4800 ) {
773                 lightsource = 2; // Fluorescent
774             } else if( colourtemp > 4800 && colourtemp <= 5500 ) {
775                 lightsource = 1; // Daylight
776             } else if( colourtemp > 5500 && colourtemp <= 6500 ) {
777                 lightsource = 9; // Fine weather
778             } else if( colourtemp > 6500 ) {
779                 lightsource = 10; // Cloudy weather
780             }
781 
782             if(flash_fired) {
783                 lightsource = 4; // Flash
784             }
785 
786             snprintf(temp_value,
787                     sizeof(temp_value)/sizeof(char),
788                     "%u", lightsource);
789             exifTable->insertElement(TAG_LIGHT_SOURCE, temp_value);
790         }
791     }
792 
793     LOG_FUNCTION_NAME_EXIT;
794 
795     return ret;
796 }
797 
convertGPSCoord(double coord,int & deg,int & min,int & sec,int & secDivisor)798 status_t OMXCameraAdapter::convertGPSCoord(double coord,
799                                            int &deg,
800                                            int &min,
801                                            int &sec,
802                                            int &secDivisor)
803 {
804     double tmp;
805 
806     LOG_FUNCTION_NAME;
807 
808     if ( coord == 0 ) {
809 
810         CAMHAL_LOGE("Invalid GPS coordinate");
811 
812         return -EINVAL;
813     }
814 
815     deg = (int) floor(fabs(coord));
816     tmp = ( fabs(coord) - floor(fabs(coord)) ) * GPS_MIN_DIV;
817     min = (int) floor(tmp);
818     tmp = ( tmp - floor(tmp) ) * ( GPS_SEC_DIV * GPS_SEC_ACCURACY );
819     sec = (int) floor(tmp);
820     secDivisor = GPS_SEC_ACCURACY;
821 
822     if( sec >= ( GPS_SEC_DIV * GPS_SEC_ACCURACY ) ) {
823         sec = 0;
824         min += 1;
825     }
826 
827     if( min >= 60 ) {
828         min = 0;
829         deg += 1;
830     }
831 
832     LOG_FUNCTION_NAME_EXIT;
833 
834     return NO_ERROR;
835 }
836 
837 } // namespace Camera
838 } // namespace Ti
839