/* Hacked version of photopc that produces a webcam-like effect by polling the camera for the preview pick. Caution: eats your batteries. */ #ifndef LINT static char *rcsid="$Id: photopc.c,v 2.80 2000/08/13 21:51:48 crosser Exp $"; #endif /* Copyright (c) 1997-2000 Eugene G. Crosser Copyright (c) 1998,1999 Bruce D. Lightner (DOS/Windows support) You may distribute and/or use for any purpose modified or unmodified copies of this software if you preserve the copyright notice above. THIS SOFTWARE IS PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE. */ /* Derived from photopc.c's preview code & main loop, and support functions for same. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_FCNTL_H #include #endif #include #ifdef STDC_HEADERS #include #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #ifndef OPTARG_DEFINED #include #endif #ifdef UNIX #ifdef HAVE_SCHED_H #include #endif #ifdef HAVE_UNAME #include #endif #ifdef HAVE_UNISTD_H #include #endif #else #include "strcscmp.h" #endif #include "eph_io.h" #include "a12scan.h" #include "fnames.h" #include "ctimez.h" #include "filetime.h" #ifdef MAXPATH #undef MAXPATH #endif #define MAXPATH 256 #ifdef DOS #define MS_PROGRAM_NAMES #pragma warn -par #pragma warn -sus #endif #ifdef MSWINDOWS #define MS_PROGRAM_NAMES #define ERRNO GetLastError() #else #define ERRNO errno #endif #ifdef UNIX #define WRITEMODE "w" #define READMODE "r" #else #define WRITEMODE "wb" #define READMODE "rb" #endif #ifndef S_ISDIR #define S_ISDIR(st_mode) ((S_IFDIR & (st_mode)) ? 1 : 0) #endif #ifdef DEFAULT_DEVICE static char *device=DEFAULT_DEVICE; #else # ifdef UNIX static char *device="/dev/photopc"; # else static char *device="COM1:"; # endif #endif static int debug=0; static int quiet=0; static int usetimezone=1; static int setutime=0; static unsigned long filesize=0L; static long frame=0L; static char *nameformat=NULL; static int switchoff=0; static FILE *fp = NULL; static char *fname = NULL; static int have_folders=0; static int xchdir(eph_iob *iob,char *where) { char path[MAXPATH],*p; if (!have_folders) { fprintf(stderr,"no folders on this model\n"); return -1; } strncpy(path,where,sizeof(path)-1); path[sizeof(path)-1]='\0'; for (p=path;*p;p++) if (*p == '/') *p='\\'; if (path[0] == '\\') { if (eph_setvar(iob,84,"\\",1)) { fprintf(stderr,"could not chdir to \"\\\"\n"); return -1; } } for (p=strtok(path,"\\");p;p=strtok(NULL,"\\")) { if (eph_setvar(iob,84,p,(off_t)strlen(p))) { fprintf(stderr,"could not chdir to \"%s\"\n",p); return -1; } } return 0; } static int descend(eph_iob *iob,int depth,char *root,int(*each)(eph_iob *iob,char *path)) { long nfolders=0L,i; off_t f_size; char *folder,*p; char path[MAXPATH]; int rc; if (!have_folders) return (*each)(iob,root); if (depth > 10) { fprintf(stderr,"cannot be that deep (%d), error!\n",depth); return -1; } if (xchdir(iob,root)) { fprintf(stderr,"chdir to \"%s\" failed\n",root); return -1; } if ((rc=(*each)(iob,root)) != 0) { if (debug) printf("(*each)() returned %d\n",rc); return rc; } eph_getint(iob,83,&nfolders); if (debug) printf("descend: %s has %ld folders\n", root,nfolders); if (nfolders == 0L) return 0; folder=(char*)malloc(2048); f_size=2048; path[sizeof(path)-1]='\0'; for (i=1;i<=nfolders;i++) { eph_setint(iob,83,i); eph_getvar(iob,84,&folder,&f_size); if (debug) printf("depth=%4d i=%4ld:\n",depth,i); strncpy(path,root,sizeof(path)-2); if (path[strlen(path)-1] != '\\') strncat(path,"\\",sizeof(path)-2); strncat(path,folder,sizeof(path)-2); for (p=path+strlen(path)-1;(*p == ' ') && (p > path);p--) *p='\0'; if ((rc=descend(iob,depth+1,path,each))) { free(folder); return rc; } if (xchdir(iob,root)) { fprintf(stderr,"restore dir to \"%s\" failed\n",root); free(folder); return -1; } } free(folder); if (debug) printf("descend: full tree walked through\n"); return 0; } static int nonempty(eph_iob *iob,char *path) { long result; if (eph_getint(iob,10,&result)) { return -1; } if (result) { if (!quiet) printf("Starting in folder \"%s\"\n",path); return 1; } else return 0; } int init(eph_iob *iob) { long ret; int rc; if (eph_getint(iob,1,&ret)) return -1; #if 0 (void)eph_setint(iob,77,1L); (void)eph_setint(iob,82,60L); #endif if ((rc=eph_setnullint(iob,83))) { if (debug) printf("setnullint(83) returned %d\n",rc); } if (eph_setvar(iob,84,"\\",1)) { if (debug) printf("No folders on this model\n"); } else { have_folders=1; } if (have_folders) if (descend(iob,0,"\\",nonempty) < 0) return -1; return 0; } static void reporterror(int errcode,char *errstr) { if ((errcode != ERR_TIMEOUT) || debug) fprintf(stderr,"Error %d: %s\n",errcode,errstr); } void running(off_t count) { if (!quiet && filesize) { printf("%lu: %lu of %lu\r",(unsigned long)frame, (unsigned long)count,filesize); fflush(stdout); } } int storing(char *data,size_t len) { if (fwrite(data,len,1,fp) != 1) { perror(fname); return -1; } return 0; } int preview(eph_iob *iob ) { char *buffer=NULL; off_t bufsize; char zero=0; int rc=-1; bufsize=2048; buffer=malloc((size_t)bufsize); if (buffer == NULL) { fprintf(stderr,"could not alloc %lu bytes\n", (unsigned long)bufsize); goto exit; } if (eph_action(iob,5,&zero,1)) goto exit; if (eph_setint(iob,4,0L)) goto exit; if (eph_getvar(iob,14,&buffer,&bufsize)) goto exit; /* unlink( "/tmp/w.jpg" ); if (( fp = fopen( "/tmp/w.jpg", WRITEMODE )) != NULL ) { if (fwrite(buffer,(size_t)bufsize,1,fp) != 1) { perror( "/tmp/w.jpg" ); goto exit; } else { rc = 0; } } else { perror( "/tmp/w.jpg" ); }*/ printf( "Content-Type: image/jpeg\n\n" ); fwrite( buffer, (size_t) bufsize, 1, stdout ); /* streaming */ printf( "\n--myboundary\n" ); fflush( stdout ); rc = 0; exit: if (buffer) free(buffer); return rc; } int main(int argc,char *argv[]) { int c,rc=0; long speed=0L,ttspeed=0L,defttspeed=0L; eph_iob *iob; #ifdef MS_PROGRAM_NAMES char *program = argv[0]; char *q; /* remove program extension */ if ((q = strrchr(program, '.')) != NULL) *q = '\0'; /* remove directory */ if ((q = strrchr(program, '/')) != NULL) program = q + 1; if ((q = strrchr(program, '\\')) != NULL) program = q + 1; #endif #if HAVE_SCHED_SETSCHEDULER && USE_RTPRIO if (geteuid() == 0) { /* Try to set realtime priority */ struct sched_param sp; int rc,minp,maxp; minp=sched_get_priority_min(SCHED_FIFO); maxp=sched_get_priority_max(SCHED_FIFO); sp.sched_priority=minp+(maxp-minp)/2; if ((rc=sched_setscheduler(0,SCHED_FIFO,&sp)) == -1) fprintf(stderr,"failed to set realtime priority: %s\n", strerror(errno)); #if 0 if ((rc=sched_getscheduler(0)) == -1) fprintf(stderr,"getscheduler: %s\n",strerror(errno)); else if (sched_getparam(0,&sp) == -1) fprintf(stderr,"sched_getparm: %s\n", strerror(errno)); else printf("New scheduling policy: %d, prio %d\n", rc,sp.sched_priority); #endif /* Drop supervisor privelege */ (void)seteuid(getuid()); } #endif /* HAVE_SCHED_SETSCHEDULER */ while ((c=getopt(argc,argv,"l:s:S:f:vqhVzt")) != EOF) switch (c) { case 'l': device=optarg; break; case 's': /* real speed, physical in the line, tell the camera about it. */ speed=atol(optarg); break; case 'S': /* `pseudo' speed, tell this to the UNIX serial driver so that it will set real speed on the chip */ if (sscanf(optarg,"%ld,%ld",&defttspeed,&ttspeed) != 2) { fprintf(stderr,"bad `-S' setting, ignoring\n"); ttspeed=defttspeed=0L; } break; case 'f': nameformat=optarg; break; case 'v': debug++; break; case 'q': quiet=1; break; case 'z': usetimezone=0; break; case 't': setutime=1; break; default: return 1; } #ifdef DOS /* MS/DOS has silly assumptions about the timezone if TZ variable is not set. Hope the following will help in most cases, the results should be at least predictable... */ if (getenv("TZ") == NULL) { putenv("TZ=GMT0"); usetimezone = 0; } #endif tzset(); #ifndef UNIX /* Under DOS and Win32, usleep() is done with a local function that does self-calibration on first invokation. That's why the first call may cause overly big delay and break negotiation with the camera. */ usleep(0L); /* calibrate delay loops as required */ #endif #ifdef LOWMEMORY if (atexit(file_abort_cleanup) == -1) perror("error setting atexit function"); #endif #ifdef UNIX if (*device != '/') { char *p; p=device; device=malloc(strlen("/dev/")+strlen(p)+1); strcpy(device,"/dev/"); strcat(device,p); } #endif iob=eph_new(reporterror,NULL,running,storing,debug); if (!iob) { fprintf(stderr,"eph_new failed\n"); return 1; } if (eph_open(iob,device,speed,defttspeed,ttspeed)) { fprintf(stderr,"eph_open failed\n"); return 1; } if ((rc=init(iob))) { fprintf(stderr,"init failed\n"); goto exit; } printf( "HTTP/1.1 200 OK\n" ); printf( "Content-Type: multipart/x-mixed-replace;boundary=myboundary\n\n"); printf( "--myboundary\n" ); fflush( stdout ); while( 1 ) { if ( preview( iob ) != 0 ) break; } exit: /* On older models, action 04 with zero parameter terminates session but leaves the camera ON. On Olympus 600 (at least) this command not only terminates session but also turns the camera off. So, the "off" command will turn off newer models and *just* terminate session more quickly on older. You may want to terminate the command array by "off" on models like PhotoPC 600 to decrease power consumption when the session is over. */ eph_close(iob,switchoff); eph_free(iob); return rc; }