#include #include #include #define DEFNAME "frame" #define DEFEXT ".jpg" #define DEFCNT 10 // options int hdronly=1; int showhdr=1; int maxframes=DEFCNT; int saveall=0; int savelast=0; int nowrite=0; int timestamp=0; int locts=0; int verb=1; int skipframes=0; int nthframe=0; int nthframecnt=0; FILE*fi; FILE*fm; void xabort2(char*reason,char*reasonparm){ if(verb)fprintf(stderr,reason,reasonparm); if(verb)fprintf(stderr,"\nAbort.\n"); exit(1); } void xabort(char*reason){ xabort2("%s",reason); } // espcam: // Content-Type: image/jpeg // Content-Length: 25594 // // doorcam: // --boundarydonotcross // Content-Type: image/jpeg // Content-Length: 48992 // X-Timestamp: 1630358637.512000 // X-UStreamer-Device: /dev/video2 // // workflow: // read header until Content-Length is found, set clen // read until \r\n\r\n // read and output-dump clen bytes // repeat read-header #include #include char localts[32]; char*getlocaltimestamp(){ int millisec; struct tm* tm_info; struct timeval tv; char buf[32]; gettimeofday(&tv, NULL); tm_info = localtime(&tv.tv_sec); // 2021-09-01T00:59:31.296 strftime(buf, 26, "%Y-%m-%dT%H:%M:%S", tm_info); snprintf(localts,31,"%s.%03d",buf,(tv.tv_usec)/1000); return localts; } #define MAXHDR 512 char hdr[MAXHDR]; int hdrpos=0; int imgno=1; int readheaderline(){ int c=0; int valid=1; hdrpos=0; hdr[0]=0; while(c!=0x0a){ c=fgetc(fi); if(feof(fi))xabort("End of file reached."); if(c==0x0d)continue; if(c==0x0a)return valid; if(c<' ')valid=0; if(c>0x7f)valid=0; if(hdrpos>MAXHDR-2)continue; // ignore too long lines, we're likely in image here anyway and getting garbage hdr[hdrpos]=c; hdrpos++; hdr[hdrpos]=0; } } void sanitizetstamp(char*s){ int t; if(strstr(s,".."))s[0]=0; for(t=0;t'z')s[t]='_';else if(s[t]=='/')s[t]='_';else if(s[t]=='|')s[t]='_';else if(s[t]=='\\')s[t]='_'; } } void dumpframe(long clen,char*name,char*tstamp){ long t; char fn[512]=""; FILE*fo; sanitizetstamp(tstamp); if(clen<=0){if(showhdr)fprintf(fm,"image length invalid, skipping\n");return;} if(showhdr)fprintf(fm,"image %d data [%d]...\n",imgno,clen); if(tstamp[0]){ if(savelast){if(maxframes==imgno){snprintf(fn,255,"%s-%s"DEFEXT,name,tstamp);if(name[0]==0)snprintf(fn,255,DEFNAME"-%s"DEFEXT,tstamp);}} if(saveall){if(name[0]==0)snprintf(fn,255,DEFNAME"%d-%s"DEFEXT,imgno,tstamp);else snprintf(fn,255,"%s%d-%s"DEFEXT,name,imgno,tstamp);} } else{ if(savelast){if(maxframes==imgno){strncpy(fn,name,255);if(name[0]==0)strcpy(fn,DEFNAME DEFEXT);}} if(saveall){if(name[0]==0)snprintf(fn,255,DEFNAME"%d"DEFEXT,imgno);else snprintf(fn,255,"%s%d"DEFEXT,name,imgno);} } fn[511]=0; // sanity if(!skipframes)if(nthframe){ if(nthframecnt){nthframecnt--;fn[0]=0;} else{nthframecnt=nthframe;} } if(skipframes){skipframes--;fn[0]=0;} if(fn[0])if(verb) if(strcmp(name,"-")){ if(nowrite)fprintf(fm,"Would write to file '%s'.\n",fn); else fprintf(fm,"Writing to file '%s'.\n",fn); }else{ if(nowrite)fprintf(fm,"Would write to stdout.\n"); else fprintf(fm,"Writing to stdout.\n",fn); } if(nowrite)fn[0]=0; if(fn[0]){ int c; if(!strcmp(name,"-"))fo=stdout; else fo=fopen(fn,"wb"); if(!fo)xabort2("Cannot open output file '%s'.",fn); for(t=0;t\n"); printf("Options:\n"); printf(" -n stop reading after n frames (0=never stop, default=%d)\n",maxframes); printf(" -o name of output file, default "DEFNAME DEFEXT"; prefix-only with numbers and timestamps, - for stdout\n"); printf(" -q quiet; do not show headers\n"); printf(" -qq quieter, do not show anything\n"); printf(" -sa save all frames, implies numbering of filenames\n"); printf(" -s save last frame, needs -n\n"); printf(" -N do not save any file, just output messages\n"); printf(" -xts use timestamps from X-Timestamp: headers\n"); printf(" -se output messages to stderr (implied with -o -)\n"); printf(" -skip skip n frames in the beginning\n"); printf(" -nth output only each n-th frame\n"); printf(" -h this help\n"); printf("\n"); printf("Example:\n"); printf("curl http://webcam:8000/stream | parsemjpeg -n 5 -o snapsnot.jpg -s\n"); printf("fetches MJPEG stream, saves 5th image to snapshot.jpg\n"); exit(0); } int main(int argc,char*argv[]){ long clen=0; // Content-Length char*fn=""; char*fpref=""; char tstamp[256]=""; fm=stdout; for(int t=1;t