apps/camogm2/camogm_kml.c

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *! FILE NAME  : camogm_kml.c
00003 *! DESCRIPTION: Provides writing to series of individual JPEG files for camogm
00004 *! Copyright (C) 2007 Elphel, Inc.
00005 *! -----------------------------------------------------------------------------**
00006 *!  This program is free software: you can redistribute it and/or modify
00007 *!  it under the terms of the GNU General Public License as published by
00008 *!  the Free Software Foundation, either version 3 of the License, or
00009 *!  (at your option) any later version.
00010 *!
00011 *!  This program is distributed in the hope that it will be useful,
00012 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *!  GNU General Public License for more details.
00015 *!
00016 *!  You should have received a copy of the GNU General Public License
00017 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 *! -----------------------------------------------------------------------------**
00019 *!
00020 *!  $Log: camogm_kml.c,v $
00021 *!  Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00022 *!
00023 *!
00024 *!  Revision 1.1  2008/05/02 12:45:58  spectr_rain
00025 *!  initial revision with the sound support
00026 *!
00027 *!  Revision 1.2  2008/04/13 21:05:20  elphel
00028 *!  Fixing KML generation
00029 *!
00030 *!  Revision 1.1  2008/04/11 23:06:52  elphel
00031 *!  files to handle KML generation
00032 *!
00033 *!
00034 */
00036 #include <unistd.h>
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <signal.h>
00040 #include <fcntl.h>
00041 #include <sys/uio.h>
00042 #include <errno.h>
00043 #include <sys/types.h>
00044 #include <sys/socket.h>
00045 #include <sys/stat.h>
00046 //#include <ctype.h>
00047 //#include <getopt.h>
00048 #include <time.h>
00049 #include <string.h>
00050 
00051 #include <netinet/in.h> /*little <-> big endian ?*/
00052 #include <sys/mman.h>           /* mmap */
00053 #include <sys/ioctl.h>
00054 
00055 #include <asm/elphel/c313a.h>
00056 #include <asm/elphel/ext353.h>
00057 #include <asm/byteorder.h>
00058 
00059 
00060 #include <ogg/ogg.h> // has to be before ogmstreams.h
00061 #include "ogmstreams.h" // move it to <>?
00062 
00063 #include "camogm_kml.h"
00064 #include "camogm.h"
00065 const char ExifDirFileName[]="/dev/exif_metadir";
00066 
00068 int camogm_init_kml(void) {
00069   return 0;
00070 }
00071 void camogm_free_kml(void) {
00072 }
00073 /*
00074 int camogm_start_mov(void) {
00075 
00077   if (!((state->frame_lengths=malloc(4*state->max_frames)))) return -CAMOGM_FRAME_MALLOC ;
00079    sprintf(state->path,"%s%010ld_%06ld.mov",state->path_prefix,state->frame_params.timestamp_sec,state->frame_params.timestamp_usec);
00080    if (((state->ivf=open(state->path,O_RDWR | O_CREAT, 0777)))<0){
00081      D0(fprintf (debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path,state->ivf,errno));
00082      return -CAMOGM_FRAME_FILE_ERR;
00083    }
00086   state->frame_data_start=QUICKTIME_MIN_HEADER+16+ 4*(state->max_frames)+ ( 4*(state->max_frames))/(state->frames_per_chunk); // 8 bytes for "skip" tag
00087    lseek(state->ivf, state->frame_data_start, SEEK_SET);
00088   return 0;
00089 }
00090 
00091 */
00092 int camogm_start_kml(void) {
00093 //  struct exif_dir_table_t kml_exif[ExifKmlNumber] ;  //! store locations of the fields needed for KML generations in the Exif block
00097    struct exif_dir_table_t dir_table_entry;
00098    int fd_ExifDir;
00099    int indx;
00100    for (indx=0;indx<ExifKmlNumber;indx++) state->kml_exif[indx].ltag=0;
00102    fd_ExifDir=open(ExifDirFileName,O_RDONLY);
00103    if (fd_ExifDir<0) { // check control OK
00104      D0(fprintf (debug_file,"Error opening %s\n", ExifDirFileName));
00105      return -CAMOGM_FRAME_FILE_ERR;
00106    }
00107    while (read(fd_ExifDir, &dir_table_entry, sizeof(dir_table_entry))>0) {
00108      switch (dir_table_entry.ltag) {
00109        case Exif_Photo_DateTimeOriginal:      indx= Exif_Photo_DateTimeOriginal_Index; break;
00110        case Exif_GPSInfo_GPSLatitudeRef:      indx= Exif_GPSInfo_GPSLatitudeRef_Index; break;
00111        case Exif_GPSInfo_GPSLatitude:         indx= Exif_GPSInfo_GPSLatitude_Index ; break;
00112        case Exif_GPSInfo_GPSLongitudeRef:     indx= Exif_GPSInfo_GPSLongitudeRef_Index ; break;
00113        case Exif_GPSInfo_GPSLongitude:        indx= Exif_GPSInfo_GPSLongitude_Index; break;
00114        case Exif_GPSInfo_GPSAltitudeRef:      indx= Exif_GPSInfo_GPSAltitudeRef_Index; break;
00115        case Exif_GPSInfo_GPSAltitude:         indx= Exif_GPSInfo_GPSAltitude_Index; break;
00116        case Exif_GPSInfo_GPSTimeStamp:        indx= Exif_GPSInfo_GPSTimeStamp_Index; break;
00117        case Exif_GPSInfo_GPSDateStamp:        indx= Exif_GPSInfo_GPSDateStamp_Index; break;
00118        case Exif_GPSInfo_CompassDirectionRef: indx= Exif_GPSInfo_CompassDirectionRef_Index; break;
00119        case Exif_GPSInfo_CompassDirection:    indx= Exif_GPSInfo_CompassDirection_Index; break;
00120        case Exif_GPSInfo_CompassPitchRef:     indx= Exif_GPSInfo_CompassPitchRef_Index; break;
00121        case Exif_GPSInfo_CompassPitch:        indx= Exif_GPSInfo_CompassPitch_Index; break;
00122        case Exif_GPSInfo_CompassRollRef:      indx= Exif_GPSInfo_CompassRollRef_Index; break;
00123        case Exif_GPSInfo_CompassRoll:         indx= Exif_GPSInfo_CompassRoll_Index; break;
00124        default: indx=-1;
00125      }
00126      if (indx>=0) {
00127            memcpy(&(state->kml_exif[indx]),&dir_table_entry,sizeof(dir_table_entry));
00128            D2(fprintf(debug_file,"indx=%02d, ltag=0x%05x, len=0x%03x, src=0x%03x, dst=0x%03x\n",indx, \
00129               (int) dir_table_entry.ltag, \
00130               (int) dir_table_entry.len, \
00131               (int) dir_table_entry.src, \
00132               (int) dir_table_entry.dst));
00133      }
00134    }
00135    close (fd_ExifDir);
00136    sprintf(state->kml_path,"%s%010ld_%06ld.kml",state->path_prefix,state->this_frame_params.timestamp_sec,state->this_frame_params.timestamp_usec);
00137    if (!((state->kml_file=fopen(state->kml_path,"w+"))) ){
00138      D0(fprintf (debug_file, "Error opening %s for writing\n", state->kml_path));
00139      return -CAMOGM_FRAME_FILE_ERR;
00140   }
00142   fprintf (state->kml_file,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
00143                             "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n");
00144   fprintf (state->kml_file,"<Document>\n");
00145   state->kml_used= 1;
00146   return 0;
00147 }
00148 
00149 int camogm_frame_kml(void){
00150   char JPEGFileName[300];
00151   char * filename;
00152   int  fd_JPEG;
00153   int  i,j;
00154   ssize_t iovlen,l;
00155   struct iovec chunks_iovec[7];
00156   char datestr[11];
00157   double  longitude=0.0, latitude=0.0,  altitude=0.0,  heading=0.0,  tilt=0.0,  roll=0.0, pitch=0.0;
00158   int hours=0, minutes=0;
00159   double seconds=0.0;
00160   int * ip;
00161   if (state->kml_file) { // probably not needed
00162     i=state->this_frame_params.timestamp_sec - (state->kml_last_ts + state->kml_period);
00163     if ((i>1) || ((i==0) && ( state->this_frame_params.timestamp_usec > state->kml_last_uts  ))) {
00164 //    if (state->this_frame_params.timestamp_sec > (state->kml_last_ts + state->kml_period)) { // this way it is safe to put kml_period=1000, then kml_period=1
00165       state->kml_last_ts=state->this_frame_params.timestamp_sec;
00166       state->kml_last_uts=state->this_frame_params.timestamp_usec;
00167       if (state->format==CAMOGM_FORMAT_JPEG) {
00168         strcpy (JPEGFileName, state->path);
00169       } else {
00170         sprintf(JPEGFileName,"%s%010ld_%06ld.jpeg",state->path_prefix,state->this_frame_params.timestamp_sec,state->this_frame_params.timestamp_usec);
00171         if (((fd_JPEG=open(JPEGFileName,O_RDWR | O_CREAT, 0777)))>=0){
00172           l=0;
00173           for (i=0; i< (state->chunk_index)-1; i++) {
00174             chunks_iovec[i].iov_base=state->packetchunks[i+1].chunk;
00175             chunks_iovec[i].iov_len= state->packetchunks[i+1].bytes;
00176             l+=chunks_iovec[i].iov_len;
00177           }
00178           iovlen=writev(fd_JPEG,chunks_iovec, (state->chunk_index)-1);
00179           if (iovlen < l) {
00180                  j=errno;
00181                  D0(fprintf(debug_file,"writev error %d (returned %d, expected %d)\n",j,iovlen,l));
00182                  close (fd_JPEG);
00183                  return -CAMOGM_FRAME_FILE_ERR;
00184           }
00185           close (fd_JPEG);
00186         } else {
00187           D0(fprintf (debug_file, "Error opening %s for writing, returned %d, errno=%d\n", JPEGFileName,fd_JPEG,errno));
00188           return -CAMOGM_FRAME_FILE_ERR;
00189         }
00190      }
00191 
00193      filename=strrchr(JPEGFileName, '/');
00194      filename[0]='\0';
00195      filename++;
00198      if (state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].ltag==Exif_GPSInfo_GPSDateStamp) { // Exif_GPSInfo_GPSDateStamp is present in template
00199        memcpy(datestr, &(state->ed[state->kml_exif[Exif_GPSInfo_GPSDateStamp_Index].dst]) ,10);
00200        datestr[4]='-';datestr[7]='-';datestr[10]='\0';
00201      }
00202      if (state->kml_exif[Exif_GPSInfo_GPSTimeStamp_Index].ltag==Exif_GPSInfo_GPSTimeStamp) { // Exif_GPSInfo_GPSTimeStamp is present in template
00203        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_GPSTimeStamp_Index].dst]);
00204        hours=   __cpu_to_be32( ip[0]);
00205        minutes= __cpu_to_be32( ip[2]);
00206        seconds= (1.0*(__cpu_to_be32( ip[4])+1))/__cpu_to_be32( ip[5]); 
00207        D2(fprintf (debug_file,"(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",ip[0],ip[1],ip[2],ip[3],ip[4],ip[5]));
00208        D2(fprintf (debug_file,"(when) 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",__cpu_to_be32(ip[0]), \
00209                                                                        __cpu_to_be32(ip[1]), \
00210                                                                        __cpu_to_be32(ip[2]), \
00211                                                                        __cpu_to_be32(ip[3]), \
00212                                                                        __cpu_to_be32(ip[4]), \
00213                                                                        __cpu_to_be32(ip[5])));
00214      }
00215      D1(fprintf (debug_file,"when=%sT%02d:%02d:%05.2fZ\n",datestr, hours, minutes, seconds));
00216 
00218      if (state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].ltag==Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
00219        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_GPSLongitude_Index].dst]);
00220        longitude=__cpu_to_be32( ip[0])/(1.0*__cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2])/(60.0*__cpu_to_be32( ip[3]));
00221        if ((state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].ltag==Exif_GPSInfo_GPSLongitudeRef) &&
00222            (state->ed[state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst] != 'E')) longitude=-longitude;
00223      D2(fprintf (debug_file,"(longitude) 0x%x 0x%x 0x%x 0x%x '%c'\n",ip[0],ip[1],ip[2],ip[3],state->ed[state->kml_exif[Exif_GPSInfo_GPSLongitudeRef_Index].dst]));
00224      }
00225 
00226      if (state->kml_exif[Exif_GPSInfo_GPSLatitude_Index].ltag==Exif_GPSInfo_GPSLatitude) { // Exif_GPSInfo_GPSLatitude is present in template
00227        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_GPSLatitude_Index].dst]);
00228        latitude=__cpu_to_be32( ip[0])/(1.0*__cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2])/(60.0*__cpu_to_be32( ip[3]));
00229        if ((state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].ltag==Exif_GPSInfo_GPSLatitudeRef) &&
00230            (state->ed[state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst] != 'N')) latitude=-latitude;
00231      D2(fprintf (debug_file,"(latitude) 0x%x 0x%x 0x%x 0x%x '%c'\n",ip[0],ip[1],ip[2],ip[3],state->ed[state->kml_exif[Exif_GPSInfo_GPSLatitudeRef_Index].dst]?'-':'+'));
00232      }
00234      if (state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].ltag==Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template
00235        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_GPSAltitude_Index].dst]);
00236        altitude=(1.0*__cpu_to_be32( ip[0]))/__cpu_to_be32( ip[1]);
00237        if ((state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].ltag==Exif_GPSInfo_GPSAltitudeRef) &&
00238            (state->ed[state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst] != '\0')) altitude=-altitude;
00239      D2(fprintf (debug_file,"(altitude) 0x%x 0x%x '%c'\n",ip[0],ip[1],state->ed[state->kml_exif[Exif_GPSInfo_GPSAltitudeRef_Index].dst]));
00240      }
00241 
00242      D1(fprintf (debug_file,"longitude=%f, latitude=%f, altitude=%f\n",longitude, latitude, altitude));
00243 
00245      if (state->kml_exif[Exif_GPSInfo_CompassDirection_Index].ltag==Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template
00246        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_CompassDirection_Index].dst]);
00247        heading=(1.0*__cpu_to_be32( ip[0]))/__cpu_to_be32( ip[1]);
00248      D2(fprintf (debug_file,"(heading) 0x%x 0x%x\n",ip[0],ip[1]));
00249      }
00251      if (state->kml_exif[Exif_GPSInfo_CompassRoll_Index].ltag==Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
00252        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_CompassRoll_Index].dst]);
00253        roll=__cpu_to_be32( ip[0])/(1.0*__cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2])/(60.0*__cpu_to_be32( ip[3]));
00254        if ((state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].ltag==Exif_GPSInfo_CompassRollRef) &&
00255            (state->ed[state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst] != EXIF_COMPASS_ROLL_ASCII[0])) roll=-roll;
00256      D2(fprintf (debug_file,"(roll) 0x%x 0x%x '%c'\n",ip[0],ip[1],state->ed[state->kml_exif[Exif_GPSInfo_CompassRollRef_Index].dst]));
00257      }
00258 
00259      if (state->kml_exif[Exif_GPSInfo_CompassPitch_Index].ltag==Exif_GPSInfo_CompassPitch) { // Exif_GPSInfo_CompassPitch is present in template
00260        ip= (int *) &(state->ed[state->kml_exif[Exif_GPSInfo_CompassPitch_Index].dst]);
00261        pitch=__cpu_to_be32( ip[0])/(1.0*__cpu_to_be32( ip[1])) + __cpu_to_be32( ip[2])/(60.0*__cpu_to_be32( ip[3]));
00262        if ((state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].ltag==Exif_GPSInfo_CompassPitchRef) &&
00263            (state->ed[state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst] !=  EXIF_COMPASS_PITCH_ASCII[0])) pitch=-pitch;
00264      D2(fprintf (debug_file,"(pitch) 0x%x 0x%x '%c'\n",ip[0],ip[1],state->ed[state->kml_exif[Exif_GPSInfo_CompassPitchRef_Index].dst]));
00265      }
00267      tilt=roll+90.0;
00268      if (tilt <0.0) tilt=0;
00269      else if (tilt > 180.0) tilt=180.0;
00270      D2(fprintf (debug_file,"heading=%f, roll=%f, pitch=%f, tilt=%f\n",heading, roll, pitch, tilt));
00271 
00273      altitude=(state->kml_height_mode?altitude:0.0)+state->kml_height;
00274 
00275 
00277      fprintf(state->kml_file,"<PhotoOverlay>\n" \
00278                              "  <shape>rectangle</shape>\n" \
00279                              "  <TimeStamp>\n" \
00280                              "     <when>%sT%02d:%02d:%05.2fZ</when>\n" \
00281                              "  </TimeStamp>\n" \
00282                              "  <Icon>\n" \
00283                              "    <href>%s</href>\n" \
00284                              "  </Icon>\n" \
00285                              " <Camera>\n" \
00286                              "   <longitude>%f</longitude>\n" \
00287                              "   <latitude>%f</latitude>\n" \
00288                              "   <altitude>%f</altitude>\n" \
00289                              "   <heading>%f</heading>\n" \
00290                              "   <tilt>%f</tilt>\n" \
00291                              "   <roll>%f</roll>\n" \
00292                              "   <altitudeMode>%s</altitudeMode>\n" \
00293                              "  </Camera>\n" \
00294                              "  <ViewVolume>\n" \
00295                              "    <leftFov>%f</leftFov>\n" \
00296                              "    <rightFov>%f</rightFov>\n" \
00297                              "    <bottomFov>%f</bottomFov>\n" \
00298                              "    <topFov>%f</topFov>\n" \
00299                              "    <near>%f</near>\n" \
00300                              "  </ViewVolume>\n" \
00301                              "</PhotoOverlay>\n", \
00302                              datestr, hours, minutes, seconds, \
00303                               filename, longitude,latitude,altitude,heading,tilt,roll,state->kml_height_mode?"absolute":"relativeToGround", \
00304                              -(state->kml_horHalfFov), state->kml_horHalfFov, -(state->kml_vertHalfFov), state->kml_vertHalfFov, state->kml_near);
00305     }
00306   }
00307   return 0;
00308 }
00309 
00310 
00311 int camogm_end_kml(void){
00312 
00313   if (state->kml_file) {
00314     fprintf (state->kml_file,"</Document>\n");
00315     fprintf (state->kml_file,"</kml>\n");
00316     fclose(state->kml_file);
00317     state->kml_file=NULL;
00318   }
00319   return 0;
00320 }
00321 

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1