00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 #include <unistd.h>
00108 #include <stdio.h>
00109 #include <stdlib.h>
00110 #include <signal.h>
00111 #include <fcntl.h>
00112 #include <errno.h>
00113 #include <sys/types.h>
00114 #include <sys/socket.h>
00115 #include <sys/stat.h>
00116
00117
00118 #include <time.h>
00119 #include <string.h>
00120 #include <syslog.h>
00121
00122 #include <netinet/in.h>
00123 #include <sys/mman.h>
00124 #include <sys/ioctl.h>
00125
00126 #include <asm/elphel/c313a.h>
00127 #include <asm/elphel/exifa.h>
00128 #include <asm/elphel/ext353.h>
00129 #include <asm/byteorder.h>
00130
00131 #if ELPHEL_DEBUG
00132 #define ELPHEL_DEBUG_THIS 0
00133 #else
00134 #define ELPHEL_DEBUG_THIS 0
00135 #endif
00136
00137
00138 #if ELPHEL_DEBUG_THIS
00139 #define D(x) fprintf(stderr,"%s:%d:%s: ",__FILE__,__LINE__,__FUNCTION__);x
00140 #else
00141 #define D(x)
00142 #endif
00143
00144
00145 #define USEHTTP10(x) x
00146
00147
00148
00149 #define JPEG_HEADER_MAXSIZE 0x300 // will not change
00150
00151 #define TRAILER_SIZE 0x02
00152 #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00153
00154 unsigned long * ccam_dma_buf;
00155
00156 char trailer[TRAILER_SIZE] = {0xff,0xd9};
00157
00158
00159 const char url_args[]="This server supports sequence of commands entered in the URL (separated by \"/\", case sensitive )\n"
00160 "executing them from left to right as they appear in the URL\n"
00161 "img - send image at the current pointer (if it is first command - use last acquired image, if none availabe - send 1x1 gif)\n"
00162 "bimg - same as above, but save the whole image in the memory before sending - useful to avoid overruns with slow connection \n"
00163 "mimg[n] - send images as a multipart JPEG (all commands after will be ignored), possible to specify optional fps reduction\n"
00164 " i.e. mimg4 - skip 3 frames for each frame output (1/4 fps) \n"
00165 "bmimg[n] - same as above, buffered\n"
00166 "pointers - send XML-formatted data about frames available in the camera circular buffer)\n\n"
00167 "Any of the 5 commands above can appear only once in the URL string, the second instance will be ignored. If none of the 5\n"
00168 "are present in the URL 1x1 pixel gif will be returned to the client after executing the URL command.\n\n"
00169 "torp - set frame pointer to global read pointer, maintained by the camera driver. If frame at that pointer\n"
00170 " is invalid, use scnd (see below)\n"
00171 "towp - set frame pointer to hardware write pointer - position where next frame will be aquired\n"
00172 "prev - move to previous frame in buffer, nop if there are none\n"
00173 "next - move to the next frame in buffer (will stop at write pointer, see towp above)\n"
00174 "last - move to the most recently acquired frame, or to write pointer if there are none.\n"
00175 " this command is implied at the start of the url command sequence.\n"
00176 "first - move to the oldest frame still available in the buffer. It is not safe to rely on it if\n"
00177 " more frames are expected - data might be overwritten at any moment and the output will be corrupted.\n"
00178 "second - move to the second oldest frame in the buffer - somewhat safer than \"first\" - there will be time for\n"
00179 " \"next\" command at least before frame data (and pointer structures) will be overwritten.\n"
00180 "save - save current frame pointer as a global read pointer that holds it values between server requests.\n"
00181 " This pointer is shared between all the clients and applications that use it.\n"
00182 "wait - Wait until there will be a frame at current pointer ready\n";
00183 int sendImage (int bufferImageData, int fd_circ, int use_Exif);
00184 void sendBuffer(void * buffer, int len);
00185 void listener_loop(int port);
00186 void errorMsgXML(char * msg);
00187 int framePointersXML(int fd_circ);
00188 int metaXML(int fd_circ, int mode);
00189 int printExifXML(int exif_page);
00190
00191 int out1x1gif(void);
00192
00193
00194 #define saferead255(f,d,l) read(f,d,((l)<256)?(l):255)
00195 int printExifXML(int exif_page) {
00196 int indx;
00197 long numfields=0;
00198 struct exif_dir_table_t dir_table_entry;
00199 int fd_exifdir;
00200 struct exif_dir_table_t exif_dir[ExifKmlNumber] ;
00201
00202
00203 fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY);
00204 if (fd_exifdir <0) {
00205 printf ("<error>\"Opening %s\"</error>\n",EXIFDIR_DEV_NAME);
00206 return -2 ;
00207 }
00208 for (indx=0; indx<ExifKmlNumber; indx++) exif_dir[indx].ltag=0;
00209 while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry))>0) {
00210 switch (dir_table_entry.ltag) {
00211 case Exif_Image_ImageDescription: indx= Exif_Image_ImageDescription_Index; break;
00212 case Exif_Image_FrameNumber: indx= Exif_Image_FrameNumber_Index; break;
00213 case Exif_Photo_DateTimeOriginal: indx= Exif_Photo_DateTimeOriginal_Index; break;
00214 case Exif_Photo_SubSecTimeOriginal: indx= Exif_Photo_SubSecTimeOriginal_Index; break;
00215 case Exif_Photo_ExposureTime: indx= Exif_Photo_ExposureTime_Index; break;
00216 case Exif_GPSInfo_GPSLatitudeRef: indx= Exif_GPSInfo_GPSLatitudeRef_Index; break;
00217 case Exif_GPSInfo_GPSLatitude: indx= Exif_GPSInfo_GPSLatitude_Index ; break;
00218 case Exif_GPSInfo_GPSLongitudeRef: indx= Exif_GPSInfo_GPSLongitudeRef_Index ; break;
00219 case Exif_GPSInfo_GPSLongitude: indx= Exif_GPSInfo_GPSLongitude_Index; break;
00220 case Exif_GPSInfo_GPSAltitudeRef: indx= Exif_GPSInfo_GPSAltitudeRef_Index; break;
00221 case Exif_GPSInfo_GPSAltitude: indx= Exif_GPSInfo_GPSAltitude_Index; break;
00222 case Exif_GPSInfo_GPSTimeStamp: indx= Exif_GPSInfo_GPSTimeStamp_Index; break;
00223 case Exif_GPSInfo_GPSDateStamp: indx= Exif_GPSInfo_GPSDateStamp_Index; break;
00224 case Exif_GPSInfo_GPSMeasureMode: indx= Exif_GPSInfo_GPSMeasureMode_Index; break;
00225 case Exif_GPSInfo_CompassDirectionRef: indx= Exif_GPSInfo_CompassDirectionRef_Index; break;
00226 case Exif_GPSInfo_CompassDirection: indx= Exif_GPSInfo_CompassDirection_Index; break;
00227 case Exif_GPSInfo_CompassPitchRef: indx= Exif_GPSInfo_CompassPitchRef_Index; break;
00228 case Exif_GPSInfo_CompassPitch: indx= Exif_GPSInfo_CompassPitch_Index; break;
00229 case Exif_GPSInfo_CompassRollRef: indx= Exif_GPSInfo_CompassRollRef_Index; break;
00230 case Exif_GPSInfo_CompassRoll: indx= Exif_GPSInfo_CompassRoll_Index; break;
00231 default: indx=-1;
00232 }
00233 if (indx>=0) {
00234 memcpy(&(exif_dir[indx]),&dir_table_entry,sizeof(dir_table_entry));
00235 numfields++;
00236 }
00237 }
00238 close (fd_exifdir);
00240
00241 long rational3[6];
00242 long exif_page_start;
00243 char val[256];
00244 int hours=0, minutes=0;
00245 double seconds=0.0;
00246 double longitude=0.0, latitude=0.0, altitude=0.0, heading=0.0, roll=0.0, pitch=0.0, exposure=0.0;
00247 val[255]='\0';
00248 int fd_exif= open(EXIF_DEV_NAME, O_RDONLY);
00249 if (fd_exif <0) {
00250 printf ("<error>\"Opening %s\"</error>\n",EXIF_DEV_NAME);
00251 return -3 ;
00252 }
00253 exif_page_start= lseek (fd_exif, exif_page, SEEK_END);
00254 if (exif_page_start<0) {
00255 printf ("<error>\"Exif page (%d) is out of range\"</error>\n",exif_page);
00256 close (fd_exif);
00257 return -1 ;
00258 }
00260 if (exif_dir[Exif_Image_ImageDescription_Index].ltag==Exif_Image_ImageDescription) {
00261 lseek (fd_exif,
00262 exif_page_start+exif_dir[Exif_Image_ImageDescription_Index].dst,
00263 SEEK_SET);
00264 saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
00265 printf("<ImageDescription>\"%s\"</ImageDescription>\n",val);
00266 }
00268 if (exif_dir[Exif_Image_FrameNumber_Index].ltag==Exif_Image_FrameNumber) {
00269 lseek (fd_exif,
00270 exif_page_start+exif_dir[Exif_Image_FrameNumber_Index].dst,
00271 SEEK_SET);
00272 read(fd_exif, rational3, 4);
00273 sprintf (val,"%ld", (long) __cpu_to_be32( rational3[0]));
00274 printf("<FrameNumber>\"%s\"</FrameNumber>\n",val);
00275 }
00276
00278 if (exif_dir[Exif_Photo_DateTimeOriginal_Index].ltag==Exif_Photo_DateTimeOriginal) {
00279 lseek (fd_exif,
00280 exif_page_start+exif_dir[Exif_Photo_DateTimeOriginal_Index].dst,
00281 SEEK_SET);
00282 read(fd_exif, val, 19);
00283 val[19]='\0';
00284 if (exif_dir[Exif_Photo_SubSecTimeOriginal_Index].ltag==Exif_Photo_SubSecTimeOriginal) {
00285 val[19]='.';
00286 lseek (fd_exif,
00287 exif_page_start+exif_dir[Exif_Photo_SubSecTimeOriginal_Index].dst,
00288 SEEK_SET);
00289 read(fd_exif, &val[20], 7);
00290 val[27]='\0';
00291 }
00292 printf("<DateTimeOriginal>\"%s\"</DateTimeOriginal>\n",val);
00293 }
00295 if (exif_dir[Exif_Photo_ExposureTime_Index].ltag==Exif_Photo_ExposureTime) {
00296 lseek (fd_exif,
00297 exif_page_start+exif_dir[Exif_Photo_ExposureTime_Index].dst,
00298 SEEK_SET);
00299 read(fd_exif, rational3, 8);
00300 exposure=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00301 sprintf (val,"%f",exposure);
00302 printf("<ExposureTime>\"%s\"</ExposureTime>\n",val);
00303 }
00305 if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag==Exif_GPSInfo_GPSMeasureMode) {
00306 lseek (fd_exif,
00307 exif_page_start+exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst,
00308 SEEK_SET);
00309 read(fd_exif, val, 1);
00310 printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n",val);
00311 }
00313 if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag==Exif_GPSInfo_GPSDateStamp) {
00314 lseek (fd_exif,
00315 exif_page_start+exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst,
00316 SEEK_SET);
00317 read(fd_exif, val, 10);
00318 val[10]='\0';
00319 if (exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].ltag==Exif_GPSInfo_GPSTimeStamp) {
00320 lseek (fd_exif,
00321 exif_page_start+exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].dst,
00322 SEEK_SET);
00323 read(fd_exif, rational3, 24);
00324 hours= __cpu_to_be32( rational3[0]);
00325 minutes= __cpu_to_be32( rational3[2]);
00326 seconds= (1.0*(__cpu_to_be32( rational3[4])+1))/__cpu_to_be32( rational3[5]);
00327 sprintf (&val[10]," %02d:%02d:%05.2f",hours,minutes,seconds);
00328 }
00329 printf("<GPSDateTime>\"%s\"</GPSDateTime>\n",val);
00330 }
00331
00334 if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag==Exif_GPSInfo_GPSLongitude) {
00335 lseek (fd_exif,
00336 exif_page_start+exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst,
00337 SEEK_SET);
00338 read(fd_exif, rational3, 24);
00339 longitude=__cpu_to_be32( rational3[0])/(1.0*__cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2])/(60.0*__cpu_to_be32( rational3[3]));
00340 if (exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].ltag==Exif_GPSInfo_GPSLongitudeRef) {
00341 lseek (fd_exif,
00342 exif_page_start+exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].dst,
00343 SEEK_SET);
00344 read(fd_exif, val, 1);
00345 if (val[0]!= 'E') longitude=-longitude;
00346 }
00347 sprintf (val,"%f",longitude);
00348 printf("<GPSLongitude>\"%s\"</GPSLongitude>\n",val);
00349 }
00351 if (exif_dir[Exif_GPSInfo_GPSLatitude_Index].ltag==Exif_GPSInfo_GPSLatitude) {
00352 lseek (fd_exif,
00353 exif_page_start+exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst,
00354 SEEK_SET);
00355 read(fd_exif, rational3, 24);
00356 latitude=__cpu_to_be32( rational3[0])/(1.0*__cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2])/(60.0*__cpu_to_be32( rational3[3]));
00357 if (exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].ltag==Exif_GPSInfo_GPSLatitudeRef) {
00358 lseek (fd_exif,
00359 exif_page_start+exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].dst,
00360 SEEK_SET);
00361 read(fd_exif, val, 1);
00362 if (val[0] != 'N') latitude=-latitude;
00363 }
00364 sprintf (val,"%f",latitude);
00365 printf("<GPSLatitude>\"%s\"</GPSLatitude>\n",val);
00366 }
00368 if (exif_dir[Exif_GPSInfo_GPSAltitude_Index].ltag==Exif_GPSInfo_GPSAltitude) {
00369 lseek (fd_exif,
00370 exif_page_start+exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst,
00371 SEEK_SET);
00372 read(fd_exif, rational3, 8);
00373 altitude=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00374
00375 if (exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].ltag==Exif_GPSInfo_GPSAltitudeRef) {
00376 lseek (fd_exif,
00377 exif_page_start+exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].dst,
00378 SEEK_SET);
00379 read(fd_exif, val, 1);
00380 if (val[0] != '\0') altitude=-altitude;
00381 }
00382 sprintf (val,"%f",altitude);
00383 printf("<GPSAltitude>\"%s\"</GPSAltitude>\n",val);
00384 }
00386 if (exif_dir[Exif_GPSInfo_CompassDirection_Index].ltag==Exif_GPSInfo_CompassDirection) {
00387 lseek (fd_exif,
00388 exif_page_start+exif_dir[Exif_GPSInfo_CompassDirection_Index].dst,
00389 SEEK_SET);
00390 read(fd_exif, rational3, 8);
00391 heading=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00392 sprintf (val,"%f",heading);
00393 printf("<CompassDirection>\"%s\"</CompassDirection>\n",val);
00394 }
00397 if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag==Exif_GPSInfo_CompassRoll) {
00398 lseek (fd_exif,
00399 exif_page_start+exif_dir[Exif_GPSInfo_CompassRoll_Index].dst,
00400 SEEK_SET);
00401 read(fd_exif, rational3, 8);
00402 roll=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00403
00404 if (exif_dir[Exif_GPSInfo_CompassRollRef_Index].ltag==Exif_GPSInfo_CompassRollRef) {
00405 lseek (fd_exif,
00406 exif_page_start+exif_dir[Exif_GPSInfo_CompassRollRef_Index].dst,
00407 SEEK_SET);
00408 read(fd_exif, val, 1);
00409 if (val[0] != EXIF_COMPASS_ROLL_ASCII[0]) roll=-roll;
00410 }
00411 sprintf (val,"%f",roll);
00412 printf("<CompassRoll>\"%s\"</CompassRoll>\n",val);
00413 }
00414
00416 if (exif_dir[Exif_GPSInfo_CompassPitch_Index].ltag==Exif_GPSInfo_CompassPitch) {
00417 lseek (fd_exif,
00418 exif_page_start+exif_dir[Exif_GPSInfo_CompassPitch_Index].dst,
00419 SEEK_SET);
00420 read(fd_exif, rational3, 8);
00421 pitch=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00422
00423 if (exif_dir[Exif_GPSInfo_CompassPitchRef_Index].ltag==Exif_GPSInfo_CompassPitchRef) {
00424 lseek (fd_exif,
00425 exif_page_start+exif_dir[Exif_GPSInfo_CompassPitchRef_Index].dst,
00426 SEEK_SET);
00427 read(fd_exif, val, 1);
00428 if (val[0] != EXIF_COMPASS_PITCH_ASCII[0]) pitch=-pitch;
00429 }
00430 sprintf (val,"%f",pitch);
00431 printf("<CompassPitch>\"%s\"</CompassPitch>\n",val);
00432 }
00433 close (fd_exif);
00434 return 0;
00435 }
00436
00437
00438
00439 int metaXML(int fd_circ, int mode) {
00440 int frameParamPointer=0;
00441 struct interframe_params_t frame_params;
00442 int jpeg_len,jpeg_start,buff_size,timestamp_start;
00443 if (mode==2) {
00444 printf ("</meta>\n");
00445 return 0;
00446 } else if (mode==0) {
00447 printf("HTTP/1.0 200 OK\n");
00448 printf("Server: Elphel Imgsrv\n");
00449 printf("Content-Type: text/xml\n");
00450 printf("Pragma: no-cache\n");
00451 printf("\n");
00452 printf ("<?xml version=\"1.0\"?>\n" \
00453 "<meta>\n");
00454 }
00455
00456 jpeg_start=lseek(fd_circ,0,SEEK_CUR);
00457 D(fprintf(stderr,"jpeg_start= (long)=0x%x\n",jpeg_start>>2));
00458 if (jpeg_start <0 ) {
00459 printf("<error>\"No frame at the current pointer\"</error>\n");
00460 return -1;
00461 }
00462 buff_size=lseek(fd_circ,0,SEEK_END);
00464 lseek(fd_circ, jpeg_start, SEEK_SET);
00465
00466 frameParamPointer=jpeg_start-32;
00467 if (frameParamPointer<0) frameParamPointer+=buff_size;
00468 memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32);
00469 jpeg_len=frame_params.frame_length;
00471 timestamp_start=jpeg_start+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC;
00472 if (timestamp_start >= buff_size) timestamp_start-=buff_size;
00473 memcpy (&(frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00475 printf ("<frame>\n" \
00476 "<start> 0x%x </start>\n" \
00477 "<hash32_r> 0x%x </hash32_r>\n" \
00478 "<hash32_g> 0x%x </hash32_g>\n" \
00479 "<hash32_gb>0x%x </hash32_gb>\n" \
00480 "<hash32_b> 0x%x </hash32_b>\n" \
00481 "<quality2> 0x%x </quality2>\n" \
00482 "<color> 0x%x </color>\n" \
00483 "<byrshift> 0x%x </byrshift>\n" \
00484 "<width> 0x%x </width>\n" \
00485 "<height> 0x%x </height>\n" \
00486 "<meta_index> 0x%x </meta_index>\n" \
00487 "<signffff> 0x%x </signffff>\n"
00488 , (int) jpeg_start
00489 , (int) frame_params.hash32_r
00490 , (int) frame_params.hash32_g
00491 , (int) frame_params.hash32_gb
00492 , (int) frame_params.hash32_b
00493 , (int) frame_params.quality2
00494 , (int) frame_params.color
00495 , (int) frame_params.byrshift
00496 , (int) frame_params.width
00497 , (int) frame_params.height
00498 , (int) frame_params.meta_index
00499 , (int) frame_params.signffff
00500 );
00501
00502 if (frame_params.signffff !=0xffff) {
00503 printf("<error>\"wrong signature (should be 0xffff)\"</error>\n");
00504 } else {
00506 printf ("<Exif>\n");
00507 printExifXML(frame_params.meta_index);
00508 printf ("</Exif>\n");
00509 }
00510 printf ("</frame>\n");
00511 return 0;
00512 }
00513
00514
00515 int framePointersXML(int fd_circ) {
00516 const char ctlFileName[]="/dev/frameparsall";
00517 int fd_fparmsall;
00518 char s[512];
00519 int p, wp, rp;
00520 int nf=0;
00521 int nfl=0;
00522 int buf_free, buf_used;
00523 int save_p;
00524 int frame8, frame_number, sensor_state, compressor_state;
00525 char *cp_sensor_state, *cp_compressor_state;
00526
00527 struct framepars_all_t *frameParsAll;
00528 struct framepars_t *framePars;
00529 unsigned long *globalPars;
00530
00531
00532 fd_fparmsall = open(ctlFileName, O_RDWR);
00533 if (fd_fparmsall<0) {
00534 printf ("Error opening %s\n", ctlFileName);
00535 fprintf(stderr,"%s:%d:%s: Error opening %s\n",__FILE__,__LINE__,__FUNCTION__, ctlFileName);
00536 return -1;
00537 }
00538
00540 frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ, MAP_SHARED, fd_fparmsall, 0);
00541 if((int)frameParsAll == -1) {
00542 frameParsAll=NULL;
00543 printf("Error in mmap /dev/frameparsall");
00544 fprintf(stderr,"%s:%d:%s: Error in mmap in %s\n",__FILE__,__LINE__,__FUNCTION__,ctlFileName);
00545 close (fd_fparmsall);
00546 fd_fparmsall = -1;
00547 return -1;
00548 }
00549 framePars=frameParsAll->framePars;
00550 globalPars=frameParsAll->globalPars;
00551
00552
00553 frame_number=lseek(fd_fparmsall, 0, SEEK_CUR );
00554 frame8= frame_number & PARS_FRAMES_MASK;
00555
00556 sensor_state=framePars[frame8].pars[P_SENSOR_RUN];
00557 compressor_state=framePars[frame8].pars[P_COMPRESSOR_RUN];
00558 cp_sensor_state= (sensor_state==0)?
00559 "SENSOR_RUN_STOP":
00560 ((sensor_state==1)?
00561 "SENSOR_RUN_SINGLE":
00562 ((sensor_state==2)?"SENSOR_RUN_CONT":"UNKNOWN"));
00563 cp_compressor_state= (compressor_state==0)?
00564 "COMPRESSOR_RUN_STOP":
00565 ((compressor_state==1)?
00566 "COMPRESSOR_RUN_SINGLE":
00567 ((compressor_state==2)?"COMPRESSOR_RUN_CONT":"UNKNOWN"));
00568
00569 save_p=lseek(fd_circ,0,SEEK_CUR);
00570 rp=lseek(fd_circ,LSEEK_CIRC_TORP,SEEK_END);
00571 wp=lseek(fd_circ,LSEEK_CIRC_TOWP,SEEK_END);
00572 p=wp;
00573 while ((p>=0) & (nf<500)) {
00574 if (p==rp) nfl=nf;
00575 p=lseek(fd_circ,LSEEK_CIRC_PREV,SEEK_END);
00576 nf++;
00577 }
00578 buf_free=GLOBALPARS(G_FREECIRCBUF);
00579 buf_used=GLOBALPARS(G_CIRCBUFSIZE)-GLOBALPARS(G_FREECIRCBUF);
00580
00581 lseek(fd_circ,save_p,SEEK_SET);
00582 buf_free=lseek(fd_circ,LSEEK_CIRC_FREE,SEEK_END);
00583 lseek(fd_circ,save_p,SEEK_SET);
00584 buf_used=lseek(fd_circ,LSEEK_CIRC_USED,SEEK_END);
00585 lseek(fd_circ,save_p,SEEK_SET);
00586
00587 sprintf (s,"<?xml version=\"1.0\"?>\n" \
00588 "<frame_pointers>\n" \
00589 " <this>%d</this>\n" \
00590 " <write>%d</write>\n" \
00591 " <read>%d</read>\n" \
00592 " <frames>%d</frames>\n" \
00593 " <left>%d</left>\n" \
00594 " <free>%d</free>\n" \
00595 " <used>%d</used>\n" \
00596 " <frame>%d</frame>\n" \
00597 " <sensor_state>\"%s\"</sensor_state>\n" \
00598 " <compressor_state>\"%s\"</compressor_state>\n" \
00599 "</frame_pointers>\n",
00600 save_p,
00601 wp,
00602 rp,
00603 nf-1,
00604 nfl,
00605 buf_free,
00606 buf_used,
00607 frame_number,
00608 cp_sensor_state,
00609 cp_compressor_state);
00610 printf("HTTP/1.0 200 OK\n");
00611 printf("Server: Elphel Imgsrv\n");
00612 printf("Content-Length: %d\n",strlen(s));
00613 printf("Content-Type: text/xml\n");
00614 printf("Pragma: no-cache\n");
00615 printf("\n");
00616 printf(s);
00618 close(fd_fparmsall);
00619 D(fprintf (stderr,">%s< [%d bytes]\n",s,strlen(s)));
00620 return 0;
00621 }
00622
00623 int out1x1gif(void) {
00624 char s[]="HTTP/1.0 200 OK\n" \
00625 "Server: Elphel Imgsrv\n" \
00626 "Content-Length: 35\n" \
00627 "Content-Type: image/gif\n" \
00628 "\n" \
00629 "GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00" \
00630 "\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x4c" \
00631 "\x01\x00\x3b";
00632 fwrite (s,1,sizeof(s),stdout);
00633 return 0;
00634 }
00635
00636 void errorMsgXML(char * msg) {
00637 char s[1024];
00638 sprintf (s,"<?xml version=\"1.0\"?>\n" \
00639 "<frame_params>\n" \
00640 "<error>%s</error>\n" \
00641 "</frame_params>\n",msg);
00642 D(fprintf (stderr,">%s< [%d bytes]",s,strlen(s)));
00643 printf("HTTP/1.0 200 OK\n");
00644 printf("Server: Elphel Imgsrv\n");
00645 printf("Content-Length: %d\n",strlen(s));
00646 printf("Content-Type: text/xml\n");
00647 printf("Pragma: no-cache\n");
00648 printf("\n");
00649 printf(s);
00650 }
00651
00652
00653
00656
00657 int sendImage (int bufferImageData, int fd_circ, int use_Exif) {
00658 const char HeadFileName[]="/dev/jpeghead";
00659 const char ExifFileName[]="/dev/exif_exif";
00660 int exifDataSize=0;
00662 int frameParamPointer=0;
00663 struct interframe_params_t frame_params;
00665 int buff_size;
00666 int jpeg_len;
00667 int jpeg_start;
00668 int fd_head;
00669 int fd_exif;
00670 int head_size;
00671 int jpeg_full_size, jpeg_this_size;
00672 char * jpeg_copy;
00673 int l,i;
00675 jpeg_start=lseek(fd_circ,0,SEEK_CUR);
00676 D(fprintf(stderr,"jpeg_start= (long)=0x%x\n",jpeg_start>>2));
00677 fd_head = open(HeadFileName, O_RDWR);
00678 if (fd_head<0) {
00679 fprintf (stderr,"Error opening %s\n", HeadFileName);
00680 return -1;
00681 }
00682 lseek(fd_head,jpeg_start+1,SEEK_END);
00683 head_size=lseek(fd_head,0,SEEK_END);
00684 if (head_size>JPEG_HEADER_MAXSIZE) {
00685 fprintf(stderr,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,head_size, JPEG_HEADER_MAXSIZE );
00686 close (fd_head);
00687 return -2;
00688 }
00690 buff_size=lseek(fd_circ,0,SEEK_END);
00692 lseek(fd_circ, jpeg_start, SEEK_SET);
00693 D(fprintf(stderr,"position (longs)=0x%x\n", (int) lseek(fd_circ,0,SEEK_CUR)>>2));
00694
00696
00697 frameParamPointer=jpeg_start-32;
00698 if (frameParamPointer<0) frameParamPointer+=buff_size;
00699 memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32);
00700 jpeg_len=frame_params.frame_length;
00701 if (frame_params.signffff !=0xffff) {
00702 fprintf(stderr, "wrong signature - %d\r\n",(int) frame_params.signffff);
00703 close (fd_head);
00704 return -4;
00705 }
00706
00707 if (use_Exif) {
00708 D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
00710 fd_exif = open(ExifFileName, O_RDONLY);
00711 if (fd_exif<0) {
00712 fprintf (stderr,"Error opening %s\n", ExifFileName);
00713 close (fd_head);
00714 return -5;
00715 }
00716 exifDataSize=lseek(fd_exif,1,SEEK_END);
00717 if (exifDataSize < 0) exifDataSize=0;
00718 if (!exifDataSize) close(fd_exif);
00719 } else {
00720 frame_params.meta_index=0;
00721 fd_exif=-1;
00722 }
00726
00727 jpeg_full_size=jpeg_len+head_size+2+exifDataSize;
00728 if (bufferImageData) jpeg_this_size=jpeg_full_size;
00729 else jpeg_this_size=head_size+exifDataSize;
00730 jpeg_copy=malloc(jpeg_this_size);
00731 if (!jpeg_copy) {
00732 syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00734 for (i=0;i<10;i++) {
00735 usleep(((jpeg_this_size & 0x3ff) + 5) * 100);
00736 jpeg_copy=malloc(jpeg_this_size);
00737 if (jpeg_copy) break;
00738 syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00739 }
00740 if (!jpeg_copy) {
00741 syslog(LOG_ERR, "%s:%d malloc (%d) failed 10 times - giving up", __FILE__,__LINE__,jpeg_this_size);
00742 exit (1);
00743 }
00744 }
00745
00746 lseek(fd_head,0,0);
00747 read (fd_head,&jpeg_copy[exifDataSize],head_size);
00748 close (fd_head);
00749 if (exifDataSize>0) {
00750 memcpy (jpeg_copy,&jpeg_copy[exifDataSize],2);
00751 lseek(fd_exif,frame_params.meta_index,SEEK_END);
00752 read (fd_exif,&jpeg_copy[2],exifDataSize);
00753 close(fd_exif);
00754 }
00755 printf("Content-Type: image/jpeg\n");
00756 if (bufferImageData) {
00757 l=head_size+exifDataSize;
00759 if ((jpeg_start+jpeg_len) > buff_size) {
00760 memcpy (&jpeg_copy[l], (unsigned long * ) &ccam_dma_buf[jpeg_start>>2],buff_size-jpeg_start);
00761 l+=buff_size-jpeg_start;
00762 memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[0],jpeg_len-(buff_size-jpeg_start));
00763 } else {
00764 memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[jpeg_start>>2],jpeg_len);
00765 }
00766 memcpy (&jpeg_copy[jpeg_len+head_size+exifDataSize],trailer,2);
00767 printf("Content-Length: %d\n",jpeg_full_size);
00768 printf("\n");
00769 sendBuffer(jpeg_copy, jpeg_full_size);
00770 } else {
00771 printf("Content-Length: %d\n",jpeg_full_size);
00772 printf("\n");
00773 sendBuffer(jpeg_copy, head_size+exifDataSize);
00775 if ((jpeg_start+jpeg_len) > buff_size) {
00777 sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], buff_size-jpeg_start);
00779 sendBuffer((void *) &ccam_dma_buf[0], jpeg_len-(buff_size-jpeg_start));
00780 } else {
00782 sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], jpeg_len);
00783 }
00784 sendBuffer(trailer,2);
00785 }
00786 free(jpeg_copy);
00787 return 0;
00788
00789 }
00790
00791
00793 void sendBuffer(void * buffer, int len) {
00794 int bytesLeft=len;
00795 int offset=0;
00796 int bytesWritten;
00797 char * cbuffer= (char *) buffer;
00798 D(fprintf (stderr,"buffer=%p, len=%d\n",buffer, len));
00799 while (bytesLeft>0) {
00800 D(fprintf (stderr," --bytesLeft=%d\n",bytesLeft));
00801
00802 bytesWritten= fwrite (&cbuffer[offset],1,bytesLeft,stdout);
00803 bytesLeft-= bytesWritten;
00804 offset+= bytesWritten;
00805 }
00806 }
00807
00808
00809
00810
00811 void listener_loop(int port)
00812 {
00813 char errormsg[1024];
00814 const char circbufFileName[]="/dev/circbuf";
00815 int fd_circ;
00816 int this_p;
00817 int rslt;
00818 int buf_images=0;
00819 char buf [1024];
00820 int len=0;
00821 char * cp, *cp1, *cp2;
00822 int slow,skip;
00823 int sent2socket=-1;
00824 struct sockaddr_in sock;
00825 int res;
00826 int one=1;
00827 int buff_size;
00828 memset((char *)&sock, 0, sizeof(sock));
00829 sock.sin_port = htons(port);
00830 sock.sin_family = AF_INET;
00831 res = socket(AF_INET, SOCK_STREAM, 0);
00832 setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
00833 bind(res, (struct sockaddr * ) &sock,sizeof(sock));
00834 listen(res, 10);
00835 int exif_enable=1;
00836 while (1) {
00837 int fd;
00838 fd = accept(res,NULL,0);
00839 if (fd == -1) continue;
00840 signal(SIGCHLD, SIG_IGN);
00841
00843 if (fork() == 0) {
00844 close(res);
00846 fflush(stdout);
00847 fflush(stderr);
00848 dup2(fd, 0);
00849 dup2(fd, 1);
00850 close(fd);
00852 if (fgets(buf, sizeof(buf)-1, stdin)) len=strlen(buf);
00853 cp=buf;
00854 strsep(&cp, "/?");
00855 if (cp) {
00858 cp1=strchr(cp,' ');
00859 if (cp1) cp1[0]='\0';
00860 }
00861 if (!cp || (strlen(cp)==0)) {
00862 printf("HTTP/1.0 200 OK\n");
00863 printf("Server: Elphel Imgsrv\n");
00864 printf("Content-Length: %d\n",strlen(url_args));
00865 printf("Content-Type: text/plain\n");
00866 printf("\n");
00867 printf(url_args);
00868 fflush(stdout);
00869 _exit(0);
00870 }
00872 fd_circ = open(circbufFileName, O_RDWR);
00873 if (fd_circ<0) {
00874 fprintf (stderr,"Error opening %s\n", circbufFileName);
00875 out1x1gif();
00876 fflush(stdout);
00877 _exit(0);
00878 }
00880 buff_size=lseek(fd_circ,0,SEEK_END);
00882 ccam_dma_buf = (unsigned long *) mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
00883 if((int)ccam_dma_buf == -1) {
00884 fprintf(stderr, "Error in mmap\n");
00885 close(fd_circ);
00886 out1x1gif();
00887 fflush(stdout);
00888 _exit(0);
00889 }
00890 this_p=lseek(fd_circ,LSEEK_CIRC_LAST,SEEK_END);
00892 while ((cp1=strsep(&cp, "/?&"))) {
00894 if (strchr("0123456789",cp1[0])) {
00895 this_p= lseek(fd_circ,strtol(cp1, NULL, 10),SEEK_SET);
00896 } else if ((strcmp(cp1, "img")==0) || (strcmp(cp1, "bimg")==0)) {
00897 if (sent2socket>0) break;
00898 if (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END)<0)
00899 rslt=out1x1gif();
00900 else {
00901 printf("HTTP/1.0 200 OK\n");
00902 printf("Server: Elphel Imgsrv\n");
00903 printf("Expires: 0\n");
00904 printf("Pragma: no-cache\n");
00905 buf_images= (strcmp(cp1, "img")==0)?0:1;
00906 rslt=sendImage (buf_images, fd_circ, exif_enable);
00907 }
00908 sent2socket=1;
00909 if (rslt<0) {
00910 if (sent2socket==1) out1x1gif();
00911 else {
00912 sprintf(errormsg,"sendImage error = %d (%s:line %d)",rslt,__FILE__,__LINE__);
00913 errorMsgXML(errormsg);
00914 }
00915 }
00916 fflush(stdout);
00917
00919 } else if ((strncmp(cp1, "mimg",4)==0) || (strncmp(cp1, "bmimg",5)==0) || (strncmp(cp1, "mbimg",5)==0)) {
00920 if (sent2socket>0) break;
00921 if (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END)<0)
00922 rslt=out1x1gif();
00923 else {
00924
00925
00926 buf_images= (strncmp(cp1, "mimg",4)==0)?0:1;
00927 cp2=cp1+(buf_images?5:4);
00928 slow=strtol(cp2, NULL, 10);
00929 if (slow < 1) slow =1;
00930
00931 printf("HTTP/1.0 200 OK\n");
00932 printf("Server: Elphel Imgsrv\n");
00933 printf("Expires: 0\n");
00934 printf("Pragma: no-cache\n");
00935 printf("Content-Type: multipart/x-mixed-replace;boundary=ElphelMultipartJPEGBoundary\n");
00936 rslt=0;
00937 while (rslt>=0) {
00938 printf("\n--ElphelMultipartJPEGBoundary\n");
00939 rslt=sendImage (buf_images, fd_circ, exif_enable);
00940 fflush(stdout);
00941 if (rslt>=0) for (skip=0;skip<slow;skip++) {
00942 this_p=lseek(fd_circ,LSEEK_CIRC_NEXT, SEEK_END);
00944 if ((lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0) &&
00945 (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END) < 0) &&
00946 (lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0))
00947 this_p=lseek(fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
00948 else this_p=lseek(fd_circ,LSEEK_CIRC_LAST, SEEK_END);
00949 }
00950 }
00951 _exit(0);
00952 }
00953 } else if (strcmp(cp1, "pointers")==0) {
00954 if (sent2socket>0) break;
00955 framePointersXML(fd_circ);
00956 sent2socket=3;
00957 fflush(stdout);
00958 } else if (strcmp(cp1, "meta")==0) {
00959 if ((sent2socket>0) && (sent2socket!=2)) break;
00960 metaXML(fd_circ,(sent2socket>0)?1:0);
00961 sent2socket=2;
00962 fflush(stdout);
00963 } else if (strcmp(cp1, "noexif")==0) {
00964 exif_enable=0;
00965 } else if (strcmp(cp1, "exif")==0) {
00966 exif_enable=1;
00967 } else if (strcmp(cp1, "torp")==0) {
00968 this_p=lseek(fd_circ,LSEEK_CIRC_TORP, SEEK_END);
00969 } else if (strcmp(cp1, "towp")==0) {
00970 this_p=lseek(fd_circ,LSEEK_CIRC_TOWP, SEEK_END);
00971 } else if (strcmp(cp1, "prev")==0) {
00972 this_p=lseek(fd_circ,LSEEK_CIRC_PREV, SEEK_END);
00973 } else if (strcmp(cp1, "next")==0) {
00974 this_p=lseek(fd_circ,LSEEK_CIRC_NEXT, SEEK_END);
00975 } else if (strcmp(cp1, "last")==0) {
00976 this_p=lseek(fd_circ,LSEEK_CIRC_LAST, SEEK_END);
00977 } else if (strcmp(cp1, "first")==0) {
00978 this_p=lseek(fd_circ,LSEEK_CIRC_FIRST,SEEK_END);
00979 } else if (strcmp(cp1, "second")==0) {
00980 this_p=lseek(fd_circ,LSEEK_CIRC_SCND, SEEK_END);
00981 } else if (strcmp(cp1, "save")==0) {
00982 this_p=lseek(fd_circ,LSEEK_CIRC_SETP,SEEK_END);
00983 } else if (strcmp(cp1, "wait")==0) {
00984 if ((lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0) &&
00985 (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END) < 0) &&
00986 (lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0))
00987 this_p=lseek(fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
00988 } else if (strcmp(cp1, "favicon.ico")==0) {
00990 } else {
00991 if (cp1[0]!='_') fprintf(stderr,"Unrecognized URL command: \"%s\" - ignoring\n",cp1);
00992 }
00993 }
00994 if (sent2socket<=0) {
00995 out1x1gif();
00996 } else if (sent2socket==2) {
00997 metaXML(fd_circ,2);
00998 }
00999
01000 fflush(stdout);
01001 _exit(0);
01002 }
01003 close(fd);
01004 }
01005 }
01006
01008 int main(int argc, char *argv[])
01009 {
01010 const char usage[]= "Usage:\n%s -p <port_number>\n" \
01011 "Start image server, bind it to port <port_number>\n";
01012
01013 int port;
01014 if ((argc < 3) || (strcasecmp(argv[1], "-p"))) {
01015 printf (usage,argv[0]);
01016 printf (url_args);
01017 return 0;
01018 }
01019 port=strtol(argv[2], NULL, 10);
01020 if (!port) {printf ("Invalid port number %d\n", port); return -1;}
01021 signal(SIGCHLD, SIG_IGN);
01022 if (fork() == 0) {
01023 listener_loop(port);
01024 _exit(0);
01025 }
01026 return 0;
01027 }