// seccam.c //Ted Huntington adapted from "motion" //This program is published under the GNU license // #define PUTPICTURE 1 //put image out to jpg if diff #define bpp 24 //important that screen resolution must match!!!! #define IBMCAM 1 #define STARTCAM 1 //number to start numbering cams with #define VIDEONUM 0 //start with /dev/video0 or video1 this keep changing in 2.6.12.6 #define NUMCAM 1 //2 #define MAXCAM 10 #define AUTOBRIGHT 1 #define LOWESTBRIGHT 0 #define CONSTANTRATE 1 #define IPCAM 1 //get image from IP camera #define INFO 0 #define AUDIO 0 //record audio #include #include #include #include #include #include #include #include #include #include #include #include #include #define __FAVOR_BSD /* use bsd'ish tcp header */ #include #include #include #include #include //X Windows #include #include #include #include //v4l #include "sys/mman.h" #include //Camera #include //need for struct video_window #include #include "seccam.h" typedef unsigned char u8; typedef unsigned short int u16; typedef unsigned int u32; typedef short int i16; //prototypes void Die(char *mess); u16 csum(unsigned short *buf,int nwords); int GetImage(u8 *img); void Die(char *mess) { perror(mess); exit(1); } #ifdef IBMCAM #define MAXCHANGE 1000 //how many pixels/3 may have changed before saving image 7000=ibm 150=logi #else #define MAXCHANGE 150 //how many pixels/3 may have changed before #endif #define CHANGERANGE 80 //60 how many bits above or below a pixel may be 20=ibm 80=logi //MAXCHANGE should be near 100, 100 pixels changing by 60 bits is a significant object //but 50 changed pixels is only background random change for logitech //I tested with a pink pen, and with 100/80, it was sometimes detected even when it occupied only 40 pixels //another good test, is to see if the changed pixels are near each other //if most of the changed pixels are all in one area, that is probably an object //Xwindows Display *xdisplay; Window xwindow; int xscreen; unsigned long xforeground, xbackground; XEvent xevent; GC xgc; Colormap cmap; XColor color, colorrgb; int depth; XImage *fximage; XImage *TitleImage; Visual *visual; char title[]="Security Camera"; char icon_title[]="Security Camera"; XFontStruct *font_info; char *font_name; char **font_path; int font_path_num; Pixmap pmap[MAXCAM]; XImage *Img[MAXCAM]; //Camera static int device_fd[MAXCAM]; static struct video_capability vidcap[MAXCAM]; static struct video_window vidwin[MAXCAM]; static struct video_picture vidpic[MAXCAM]; static struct video_clip vidclips[MAXCAM][32]; //32? struct tm *currenttime=NULL; struct tm *lastcurrenttime=NULL; time_t currenttimep, lasttime=0, eventtime=0, lastshot=0; char filename[255],filebase[255],timestamp[255],datestamp[255]; char filename2[255]; int camerawidth,cameraheight; config conf[MAXCAM]; int dev[MAXCAM]; int camera[MAXCAM]; //enable/disable camera char *gimg; //need global pointer int gsize; //and size for jpeg decompression #if IPCAM | AUDIO #define BUFFSIZE 8192 //single packets are usually not bigger than 8192 bytes struct pseudo_header { /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */ //unsigned long s_addr; //unsigned long d_addr; char zer0; unsigned char protocol; unsigned short length; }; struct DecmpThread { u8 * ipimg; u8 * img; int nb; int w; int h; }; int sock,port; struct ipq_handle *ipqh; ipq_packet_msg_t *ipqmsg; struct sockaddr_in sockin; char s_ip[20],d_ip[20]; int sock2,port2,sport; //struct ipq_handle *ipqh2; //ipq_packet_msg_t *ipqmsg2; //struct sockaddr_in sockin2; char s_ip2[20],d_ip2[20]; char packet[4096]; struct ip *iph,*iph2; //IP protocol header struct tcphdr *tcph,*tcph2; //TCP header unsigned char buffer[BUFFSIZE]; #endif /* this function generates header checksums */ u16 csum (unsigned short *buf, int nwords) { //is 1s compliment of 1s complement of sum of all 16-bit numbers //1s complement is inverse+1 unsigned long sum; for (sum = 0; nwords > 0; nwords--) sum += *buf++; sum = (sum >> 16) + (sum & 0xffff); //add carry + 32-bit sum sum += (sum >> 16); //is Little Endian so reverse? perhaps add 1? return ~sum; //inverse } static void v4l_autobright (int camnum, unsigned char *image, int height, int width) { struct video_picture vid_pic; int i, j,avg,offset,min,max; j=0; avg=0; offset=0; min=140; max=190; if (!LOWESTBRIGHT) { for (i=0; i max || avg < min) { //was 64 if (ioctl(dev[camnum], VIDIOCGPICT, &vid_pic)==-1) { fprintf(stderr,"ioctl VIDIOCGPICT"); } if (avg > max && vid_pic.brightness>0) { offset=avg-max; if (vid_pic.brightness > 30*offset) vid_pic.brightness-=30*offset; else vid_pic.brightness=1;// -1;//0; printf("auto_brightness >%d cam=%d ave=%d %d\n",max,camnum,avg,vid_pic.brightness); } // printf("auto_brightness check <%d cam=%d ave=%d %d\n",min,camnum, avg,vid_pic.brightness); if (avg < min && vid_pic.brightness<65535) { offset=min-avg; if (vid_pic.brightness < (65535-30*offset)) vid_pic.brightness+=30*offset; else vid_pic.brightness=65535; printf("auto_brightness <%d cam=%d ave=%d %d\n",min,camnum, avg,vid_pic.brightness); } // printf("auto_brightness %d: %d %d\n", ldev,avg,vid_pic.brightness); if (ioctl(dev[camnum], VIDIOCSPICT, &vid_pic)==-1) { fprintf(stderr,"ioctl VIDIOCSPICT"); } } } //LOWESTBRIGHT else { if (vid_pic.brightness>1) { vid_pic.brightness=1; if (ioctl(dev[camnum], VIDIOCSPICT, &vid_pic)==-1) { fprintf(stderr,"ioctl VIDIOCSPICT"); } printf("auto_brightness %d\n",vid_pic.brightness); } //if vid_pic } //else LOWESTBRIGHT } static void v4l_bright (int dev, int amount) { struct video_picture vid_pic; int i, j=0, avg=0, offset=0; if (ioctl(dev, VIDIOCGPICT, &vid_pic)==-1) { fprintf(stderr,"ioctl VIDIOCGPICT"); } if (amount>0) { if (vid_pic.brightness+amount>65535) vid_pic.brightness=65535; else vid_pic.brightness+=amount; } else { if (vid_pic.brightness+amount<1) vid_pic.brightness=1; else vid_pic.brightness+=amount; } printf("brightness %d: %d\n", dev,vid_pic.brightness); if (ioctl(dev, VIDIOCSPICT, &vid_pic)==-1) { fprintf(stderr,"ioctl VIDIOCSPICT"); } } void put_jpeg (FILE *picture, char *image, int width, int height, int quality) { int y, x, line_width; JSAMPROW row_ptr[1]; struct jpeg_compress_struct cjpeg; struct jpeg_error_mgr jerr; unsigned char *line; line = malloc (width * 3); if (!line) return; cjpeg.err = jpeg_std_error(&jerr); jpeg_create_compress (&cjpeg); cjpeg.image_width = width; cjpeg.image_height= height; cjpeg.input_components = 3; cjpeg.in_color_space = JCS_RGB; jpeg_set_defaults (&cjpeg); jpeg_set_quality (&cjpeg, quality, TRUE); cjpeg.dct_method = JDCT_FASTEST; jpeg_stdio_dest (&cjpeg, picture); jpeg_start_compress (&cjpeg, TRUE); row_ptr[0] = line; line_width = width * 3; for ( y = 0; y < height; y++) { for (x = 0; x < line_width; x+=3) { line[x] = image[x+2]; line[x+1] = image[x+1]; line[x+2] = image[x]; } jpeg_write_scanlines (&cjpeg, row_ptr, 1); image += line_width; } jpeg_finish_compress (&cjpeg); jpeg_destroy_compress (&cjpeg); free (line); } void mem_init_source (j_decompress_ptr cinfo) { struct jpeg_source_mgr* mgr = cinfo->src; mgr->next_input_byte = gimg; mgr->bytes_in_buffer = gsize; // mgr->next_input_byte = data; // mgr->bytes_in_buffer = size; //printf("gimg=%x\n",*(u32 *)gimg); #if INFO printf("init %d\n",gsize - mgr->bytes_in_buffer); #endif } boolean mem_fill_input_buffer (j_decompress_ptr cinfo) { struct jpeg_source_mgr* mgr = cinfo->src; #if INFO printf("fill %d\n", gsize - mgr->bytes_in_buffer); #endif //printf("fill %d\n", size - mgr->bytes_in_buffer); return 0; } void mem_skip_input_data (j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr* mgr = cinfo->src; #if INFO printf("skip %d +%d\n", gsize - mgr->bytes_in_buffer, num_bytes); #endif //printf("skip %d +%d\n", size - mgr->bytes_in_buffer, num_bytes); if(num_bytes<=0) return; mgr->next_input_byte += num_bytes; mgr->bytes_in_buffer -= num_bytes; } boolean mem_resync_to_restart (j_decompress_ptr cinfo, int desired) { struct jpeg_source_mgr* mgr = cinfo->src; // printf("resync %d\n", size - mgr->bytes_in_buffer); #if INFO printf("resync %d\n", gsize - mgr->bytes_in_buffer); #endif mgr->next_input_byte = gimg; mgr->bytes_in_buffer = gsize; // mgr->next_input_byte = data; // mgr->bytes_in_buffer = size; return 1; } void mem_term_source (j_decompress_ptr cinfo) { struct jpeg_source_mgr* mgr = cinfo->src; //printf("term %d\n", size - mgr->bytes_in_buffer); } void DecompressJpeg(u8 *img,u8 *bimg,int nb,int width,int height) { // int y, x, line_width; // JSAMPROW row_ptr[1]; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; // unsigned char *line; struct jpeg_source_mgr srcmgr; //struct jpeg_destination_mgr destmgr; int total,num_scanlines; //int height,width; //FILE *output_file; //FILE *input_file; int x,y; u8 *j,tmp; // width=320; // height=240; #if INFO fprintf(stdout,"In DecompressJpg\n"); #endif memset(&cinfo, 0, sizeof(cinfo)); memset(&jerr, 0, sizeof(jerr)); memset(&srcmgr, 0, sizeof(srcmgr)); /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ //jerr.addon_message_table = ccinfo_message_table; //jerr.first_addon_message = JMSG_FIRSTADDONCODE; //jerr.last_addon_message = JMSG_LASTADDONCODE; // cinfo.out_color_space =JCS_RGB; /* Insert custom marker processor for COM and APP12. * APP12 is used by some digital camera makers for textual info, * so we provide the ability to display it as text. * If you like, additional APPn marker types can be selected for display, * but don't try to override APP0 or APP14 this way (see libjpeg.doc). */ // jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); // jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); gimg=img; //need globals for jpg decompressions gsize=nb; //printf("gimg=%x %x %x\n",gimg,*(u32 *)gimg,*(u32 *)(gimg+1)); srcmgr.next_input_byte = img; srcmgr.bytes_in_buffer = nb; srcmgr.init_source =mem_init_source; srcmgr.fill_input_buffer =mem_fill_input_buffer; srcmgr.skip_input_data =mem_skip_input_data; srcmgr.resync_to_restart =mem_resync_to_restart; srcmgr.term_source =mem_term_source; /* srcmgr.next_input_byte = data; srcmgr.bytes_in_buffer = size; srcmgr.init_source =mem_init_source ; srcmgr.fill_input_buffer =mem_fill_input_buffer ; srcmgr.skip_input_data =mem_skip_input_data ; srcmgr.resync_to_restart =mem_resync_to_restart ; srcmgr.term_source =mem_term_source ; */ /* Specify data source for decompression */ //input_file=fopen("out.jpg","rb"); //jpeg_stdio_src(&cinfo,input_file); //CreateSourceManager(&srcMgr,&cinfo,img,nb); cinfo.err=jpeg_std_error(&jerr); cinfo.src=&srcmgr; #if INFO printf("read jpeg header\n"); #endif /* Read file header, set default decompression parameters */ jpeg_read_header(&cinfo, TRUE); // cinfo.raw_data_out = TRUE; //get raw data only //printf("color=%x\n",cinfo.out_color_space); //printf("%d %d %d\n",cinfo.image_width,cinfo.image_height,cinfo.num_components); /* Adjust default decompression parameters by re-parsing the options */ // file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); // file_index = parse_switches(&cinfo, 0, 0, 0, TRUE); // output_file=fopen("test.bmp","wb"); // srcmgr.output_file = output_file; #if INFO printf("Start decompress\n"); #endif /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Write output file header */ //(srcMgr.start_output) (&cinfo,&srcmgr); /* // Process data //can also use jpeg_read_raw_data for raw 24 bit data fprintf(stdout,"before while\n"); total=0; while (cinfo.output_scanline < cinfo.output_height) { //num_scanlines = jpeg_read_scanlines(&cinfo, srcmgr->buffer,srcmgr->buffer_height); num_scanlines=jpeg_read_raw_data(&cinfo,&srcmgr.buffer,&srcmgr.buffer_height); //num_scanlines=jpeg_read_raw_data(&cinfo,(JSAMPIMAGE)(bimg+total),(JDIMENSION)srcMgr.bytes_in_buffer); // (srcMgr.put_pixel_rows) (&cinfo,&srcMgr,num_scanlines); //total+=srcMgr.bytes_in_buffer; } */ for(y=0;ytm_year+1900); mkdir_check(filebase, 0755); sprintf(filebase, "%s%02d/", filebase, currenttime->tm_mon+1); mkdir_check(filebase, 0755); sprintf(filebase, "%s%02d/", filebase, currenttime->tm_mday); mkdir_check(filebase, 0755); /* sprintf(filebase, "%s%d-", filebase, camnum); sprintf(filebase, "%s%02d", filebase, currenttime->tm_hour); sprintf(filebase, "%s_%02d", filebase, currenttime->tm_min); sprintf(filebase, "%s_%02d", filebase, currenttime->tm_sec); gettimeofday(&tmv,NULL); ms=tmv.tv_usec/1000; sprintf(filebase, "%s-%03d", filebase, ms); */ // sprintf(filebase, "%s%02d/", filebase, currenttime->tm_hour); // mkdir_check(filebase, 0755); // sprintf(filebase, "%s%02d/", filebase, currenttime->tm_min); // mkdir_check(filebase, 0755); } /* void motion_detected (int diffs, int dev, int devpipe, int devmpipe, struct images *imgs) { struct coord location; if (conf.locate || track.port) location=alg_locate_center(imgs->out, imgs->width, imgs->height); if (conf.locate) alg_locate(location, imgs->out, imgs->new, imgs->width, imgs->height); if (shots= conf.mingap ) { lastshot=currenttimep; if (conf.motion_img || conf.new_img) { if (!conf.oldlayout) { mkfilebase (filebase, currenttime); sprintf(filebase, "%s%02d-%02d", filebase, currenttime->tm_sec, shots); } else { sprintf(filebase, "%02d-%04d%02d%02d%02d%02d%02d", event_nr, currenttime->tm_year + 1900, currenttime->tm_mon +1, currenttime->tm_mday, currenttime->tm_hour, currenttime->tm_min, currenttime->tm_sec); } } if (conf.motion_img) { if (conf.ppm) sprintf(file, "%sm.ppm", filebase); else sprintf(file, "%sm.jpg", filebase); printf("Motion picture saved to: %s\n", file); filesmc++; filesm=realloc(filesm, filesmc*(sizeof(void *))); filesm[filesmc-1]=malloc(strlen(file)+1); strcpy(filesm[filesmc-1], file); filesmrate=realloc(filesmrate, filesmc*(sizeof(void *))); filesmrate[filesmc-1]=lastrate; draw_text(imgs->out, conf.width-70, conf.height-20, conf.height, conf.width, datestamp); draw_text(imgs->out, conf.width-70, conf.height-10, conf.height, conf.width, timestamp); put_picture(file, imgs->out, conf.width, conf.height); sprintf(file, "%s.jpg", filebase); printf("Normal picture saved to: %s\n", file); filesc++; files=realloc(files, filesc*(sizeof(void *))); files[filesc-1]=malloc(strlen(file)+1); strcpy(files[filesc-1], file); filesrate=realloc(filesrate, filesc*(sizeof(void *))); filesrate[filesc-1]=lastrate; put_picture(file, imgs->new, conf.width, conf.height); if (conf.onsavecommand) { exec_command(conf.onsavecommand, file); } } } if (!conf.quiet) printf("\a"); printf("Motion detected %d\n", diffs); lasttime=currenttimep; } } */ #if IPCAM | AUDIO void WriteIpCamImg(char *filename,char* img,int nb) { FILE *fptr; fptr=fopen(filename,"wb"); fwrite(img,nb,1,fptr); fclose(fptr); } //WriteIpCamImg void SendPacket(u8 flags,int seq,int ack,u8 options,u8 *data,int datalen) { //sock, sockin, s_ip, d_ip, port are globals //struct ip *iph; //IP protocol header //struct tcphdr *tcph; //TCP header struct pseudo_header pseudo; char *eoh; int optlen,result; u8 opt[20]; u8 *tcpdata; struct timeval tp; iph=(struct ip *)packet; tcph=(struct tcphdr *)(packet+sizeof(struct ip)); //possibly the receive buffer could be the same as the send //but for now I am using two different buffers // iph2=(struct ip *)buffer; // tcph2=(struct tcphdr *)(buffer+sizeof(struct ip)); memset(iph,sizeof(struct ip),0); memset(tcph,sizeof(struct tcphdr),0); //complete ip header info iph->ip_hl = 5; //header length in 32 bit segments iph->ip_v = 4; //version iph->ip_tos = 0; iph->ip_id = htons(random()); /* the value doesn't matter here */ iph->ip_off = htons(IP_DF);//IP_DF; //fragment offset field, dont fragment iph->ip_ttl = IPDEFTTL;//0x40; //time to live, # of router hops before die iph->ip_p = IPPROTO_TCP; //transport protocol 6=TCP iph->ip_src.s_addr = inet_addr(s_ip);/* SYN's can be blindly spoofed */ iph->ip_dst.s_addr = inet_addr(d_ip); //fill tcp header tcph->th_sport = htons(sport); /* arbitrary port 49391 */ tcph->th_dport = htons(port); //camera sends on port 80 (WWW HTTP) tcph->th_seq = seq;//htonl(1);// in a SYN packet, the sequence is a random tcph->th_ack = ack;/* number, and the ack sequence is 0 in the 1st packet */ tcph->th_x2 = 0; //MSS=maximum segment size, (I presume this is th_win, but maybe am wrong) can only be sent in the SYN packet according to rfc.net/rfc879.txt //MTU=maximum transmission unit (max size of any kind of packet) 1500 in Linux (and 1500 is the largest allowed for Ethernet, and therefore most of the Internet) tcph->th_win = htons(2048);//0xffff;//htons(1460); //htonl(65535);//htons(1460);//x4=5840 /* maximum allowed window size */ tcph->th_urp = 0; optlen=0; eoh = packet + sizeof(struct iphdr) + sizeof(struct tcphdr); gettimeofday(&tp,NULL); switch(options) { case 1: //can actually write options directly to packet using tlen opt[optlen++] = TCP_MAXSEG; opt[optlen++] = TCPOLEN_MAXSEG; opt[optlen++] = 0x05; //1460 0x05b4 opt[optlen++] = 0xb4; //1460 0x05b4 opt[optlen++] = TCPOPT_SACK_PERMITTED; opt[optlen++] = TCPOLEN_SACK_PERMITTED; opt[optlen++] = TCPOPT_TIMESTAMP; opt[optlen++] = TCPOLEN_TIMESTAMP; //*((u32 *) &buf[totlen]) = htonl(TCPOPT_NOP << 24 | TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8); //totlen += sizeof(u32); //*((u32 *) &buf[totlen]) = htonl(TCPOPT_TSTAMP_HDR); //totlen += sizeof(u32); *((u32 *) &opt[optlen]) = htonl(tp.tv_sec); optlen += sizeof(u32); *((u32 *) &opt[optlen]) = 0; optlen += sizeof(u32); *((u32 *) &opt[optlen]) = htonl(TCPOPT_NOP << 24 | TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8 | 2); //sc->sc_request_r_scale); optlen += sizeof(u32); memset(eoh,0,20); memcpy(eoh,opt,optlen); break; case 2: opt[optlen++] = TCPOPT_NOP; opt[optlen++] = TCPOPT_NOP; opt[optlen++] = TCPOPT_TIMESTAMP; opt[optlen++] = TCPOLEN_TIMESTAMP; *((u32 *) &opt[optlen]) = htonl(tp.tv_sec); optlen += sizeof(u32); *((u32 *) &opt[optlen]) =*((u32 *)buffer+12);//ACK must be set, is last timestamp - probably should go from end - 1 optlen += sizeof(u32); memset(eoh, 0, 20); memcpy(eoh,opt,optlen); break; } //end switch //printf("eoh[0]=%x optlen=%d\n",eoh[0],optlen); //printf("01 window=%04x\n",tcph->th_win); iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr)+optlen+datalen; //003c /* no payload */ //not htons? iph->ip_sum =0; iph->ip_sum = csum((u16 *)packet,(((iph->ip_len>>1) + 1) & ~1)); //memcpy((u8 *)tcph+sizeof(struct tcphdr)+optlen,(u8 *)&pseudo,sizeof(struct pseudo_header)); tcph->th_flags = flags;/* initial connection request */ tcph->th_off = (sizeof(struct tcphdr)+optlen)>>2; //data offset cannot be 0 tcpdata=(char *)((char *)tcph+sizeof(struct tcphdr)+optlen); if (datalen>0 && data!=0) { memcpy(tcpdata,data,datalen); tcpdata[datalen]=0; //copies 0 to last position if odd datalen } // printf("seq=%x seq=%x\n",tcph->th_ack,tcph->th_seq); memset(&pseudo,0,sizeof(pseudo)); pseudo.protocol = IPPROTO_TCP; pseudo.length = htons(sizeof(struct tcphdr)+optlen+datalen); //adjust TCP size for checksum // printf("offset=%x\n",optlen+datalen+(datalen%2))); memcpy((u8 *)tcpdata+datalen+(datalen%2),(u8 *)&pseudo,sizeof(struct pseudo_header)); tcph->th_sum=0; tcph->th_sum=csum((u16 *)tcph-4,(sizeof(struct tcphdr)+optlen+ datalen+sizeof(struct pseudo_header)+9 )>>1); //+1 for odd packets result=sendto(sock,packet, //buffer with headers and data iph->ip_len, //total length of packet */ 0, //routing flags, usually always 0 */ (struct sockaddr *)&sockin, /* socket addr, just like in */ sizeof(sockin)); /* a normal send() */ //printf("sendto result=%d\n",result); } //end SendPacket void ReportFlags(char flags) { #if INFO printf("%x\n",flags); if (flags&TH_RST) printf("GOT RST\n"); if (flags&TH_ACK) printf("GOT ACK\n"); if (flags&TH_SYN) printf("GOT SYN\n"); if (flags&TH_FIN) printf("GOT FIN\n"); if (flags&TH_PUSH) printf("GOT PUSH\n"); #endif } int StartIPImages(void) { #define BUFFSIZE 8192 //single packets are usually not bigger than 8192 bytes #define SendStr "GET /cgi-bin/getimage.cgi?motion=1 HTTP/1.1\r\nHost: 192.168.0.107\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6\r\nAccept: image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\nIf-Modified-Since: Sat, 01 Jan 2000 18:09:09 GMT\r\nCache-Control: max-age=0\r\n\r\n" //#define SendStr "GET /cgi-bin/getimage.cgi?motion=0 HTTP/1.1\r\nHost: 192.168.0.106\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6\r\nAccept: image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset:\r\nISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\nCookie: maxDI=2; MyAudio=1; version=C61200-WX-2.00.00.60630-A1; HWMAC=00%3A14%3A29%3A00%3A51%3A92; NetIF=3; maxEvent=3; maxDO=1; NVR=0; modelCategory=0; maxChannel=1\r\n\r\n" //#define SendStr "GET /cgi-bin/getimage.cgi?motion=1 HTTP/1.1\r\nHost: 192.168.0.106\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6\r\nAccept: image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\nIf-Modified-Since: Sat, 01 Jan 2000 18:09:09 GMT\r\nCache-Control: max-age=0\r\n\r\n" #define NOOPTIONS 0 //remove options part of TCP header #define SENDRESET 0 int status=0,bytes=0,numbytes,pasthtml; // FILE *fptr; struct pseudo_header pseudo; char one = 1; // char *eoh = packet + sizeof(struct iphdr) + sizeof(struct tcphdr); //char *options = "\002\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000"; // char *options = "\x02\x04\x05\xb4\x04\x02\x08\x0a\x00\x1d\x44\x98\x00\x00\x00\x00\x01\x03\x03\x02"; // char opt[20]; //option buffer char *tcpdata; //tcp data buffer (holds HTTP getimage.cgi instruction) int optlen,datalen,waitack; int skip; struct timeval tp; u32 seq,ack; gettimeofday(&tp,NULL); strcpy(d_ip,"192.168.0.106"); // strcpy(d_ip,"192.168.0.107"); //strcpy(d_ip,"192.168.0.100"); strcpy(s_ip,"192.168.0.104"); //SYN/ACK always gets RST from this computer //this computer's TCP stack will respond. kind of ridiculous, it doesn't know about sends, but gets all receives. Very illogical //libdnet can be used to block the port used on this computer programmatically //but it is not part of the default (Mandriva 2006.0) system //fw_add(fw, &rule); fw.h can be used to FW_OP_BLOCK the TCP/IP stack from //reading incoming packets. port=80; //1047 80 /* Create the TCP socket */ //SOCK_STREAM Socket will do TCP ACK //SOCK_PACKET Socket will do ETH communication (Device Layer) //SOCK_RAW Socket will not and requires user to be root //Physical layer->Device Layer (Ethernet protocol) -> Network layer (IP) -> //Transport layer (TCP,UDP,ICMP) -> Session layer (application specific data) if ((sock = socket(PF_INET,SOCK_RAW,IPPROTO_TCP)) < 0) { Die("Failed to create socket\n"); } memset(&sockin,0,sizeof(sockin)); sockin.sin_family = AF_INET; sockin.sin_port = htons(port); sockin.sin_addr.s_addr = inet_addr(d_ip); //bind(sock,(struct sockaddr *)&sockin,sizeof(sockin)); /* finally, it is very advisable to do a IP_HDRINCL call, to make sure that the kernel knows the header is included in the data, and doesn't insert its own header into the packet before our data */ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) printf ("Warning: Cannot set HDRINCL!\n"); //The reason raw sockets (not a trivial requirement!) are needed is because: //the gadspot camera sends a packet that Linux interprets as an HTTP //packet, but it actually is also a TCP packet and does not ACK //but the gadspot camera requires an ACK. //I am a novice at this, but I don't know any way to force the Linux //TCP/IP service to send an ACK to this HTTP packet (which in Windows //Wireshark appears to be a TCP packet) //But with using raw sockets, somehow TCP/IP sends are ignored //by the system TCP/IP stack, but TCP/IP receives are not //and so when the client responds to a SYN with a SYN/ACK //the system is only aware of the SYN/ACK and sends a RST //to reset the connection, since it is unaware of the SYN send. //answers to this are: //1) the TCP/IP should ignore (not respond to) raw socket TCP/IP traffic //2) the TCP/IP stack should be aware of sending TCP/IP too //3) there should be some easy way to programmatically deactivate //kernel processing on raw sockets //4) perhaps some way of sending a tcp(ack), or specific tcp packets. //tell Linux TCP/IP stack to drop all packets on port 50000 //system("iptables -A INPUT -j QUEUE -p tcp --destination-port 50000"); //DROP //system("modprobe iptable_filter"); //system("modprobe ip_queue"); //printf("create ipq handle\n"); ipqh=ipq_create_handle(0,PF_INET); if (!ipqh) Die("cannot create ipq handle.\n"); status = ipq_set_mode(ipqh, IPQ_COPY_PACKET, BUFFSIZE); if (status < 0) Die("cannot set ipq mode.\n Make sure you did:\nmodprobe iptable_filter\nmodprobe ip_queue\n"); waitack=0; // while(!waitack) { //SendPacket(TH_SYN,random(),0,1,0,0); //fprint("send SYN\n"); bytes=0; while (bytes==0) { printf("Send SYN packet\n"); SendPacket(TH_SYN,random(),0,0,0,0); //important to not send with options, in particular to change the MSS //PACKET 2 //read back the cameras SYN/ACK skip=0; // bytes=0; bytes=ipq_read(ipqh,buffer,sizeof(buffer),2000000); if (bytes==0) { printf("read timed out in StartIPCamera\n"); printf("waiting for 1 minute\n"); sleep(60); } } //while.10 //printf("after read\n"); //should buffer be actual struct instead of pointer, //because how is space allocated? and then message //is after struct? tcph2=0;//to initiatize if (bytes>0 && ipq_message_type(buffer)==IPQM_PACKET) { ipqmsg = ipq_get_packet(buffer); status = ipq_set_verdict(ipqh, ipqmsg->packet_id,NF_DROP, 0, NULL); //move buffer to packet payload // printf("packet id= %lx\n",ipqmsg->packet_id); // printf("data_len= %x\n",ipqmsg->data_len); // printf("data= %x\n",*((u32 *)ipqmsg->payload)); tcph2=(struct tcphdr *)(ipqmsg->payload+sizeof(struct ip)); //printf("after tcph2 tcph=%x\n",tcph); #if INFO ReportFlags(tcph2->th_flags); #endif //check seq=last ack // printf("tcph2->th_ack=%x tcph_>th_seq=%x\n",htonl(tcph2->th_ack),htonl(tcph->th_seq)+1); if (htonl(tcph2->th_ack)==htonl(tcph->th_seq)+1) { waitack=1; } else { printf("camera SYN/ACK seq does not match last ack\n"); // printf("probably the camera is sending an ACK for a lost HTTP getimage request. Skipping ahead to get image.\n"); printf("probably the camera is sending image data already and will take 5 minutes to timeout. Sending RST reset and FIN/ACK finish signal.\n"); //seq= SendPacket(TH_FIN|TH_ACK,tcph->th_seq,tcph->th_ack,0,0,0); //end connection SendPacket(TH_RST,tcph->th_seq,tcph->th_ack,0,0,0); //Reset // exit(0); //camera will ACK RST skip=1; } } //IPQM_PACKET // } //while waitack if (skip==0) { //PACKET 3 //seq is last sent seq+1, ack is last received seq+1 seq=htonl(htonl(tcph->th_seq)+1); ack=htonl(htonl(tcph2->th_seq)+1); SendPacket(TH_ACK,seq,ack,2,0,0); //ACK SEQ //PACKET 4 // waitack=0; // while(!waitack) { //Send the HTTP request for an image //seq has not advanced, ack is ack=tcph2->th_seq; //dont need to add 1? SendPacket(TH_PUSH|TH_ACK,seq,ack,0,&SendStr,strlen(SendStr)); //PACKET 5 //get ACK from HTTP send //perhaps I will need to add other stuff to handle unusual events such as resends etc bytes=ipq_read(ipqh,buffer,sizeof(buffer),2000000); if (bytes==0) printf("read timed out in StartIPCamera (2)\n"); // printf("%d bytes\n",bytes); //should buffer be actual struct instead of pointer, //because how is space allocated? and then message //is after struct? tcph2=0;//to initiatize if (bytes>0 && ipq_message_type(buffer)==IPQM_PACKET) { ipqmsg = ipq_get_packet(buffer); //status = ipq_set_verdict(h, m->packet_id,NF_ACCEPT, 0, NULL); status = ipq_set_verdict(ipqh, ipqmsg->packet_id,NF_DROP, 0, NULL); tcph2=(struct tcphdr *)(ipqmsg->payload+sizeof(struct ip)); #if INFO ReportFlags(tcph2->th_flags); #endif // printf("tcph2->th_ack=%x tcph_>th_seq=%x\n",htonl(tcph2->th_ack)+1,htonl(tcph->th_seq)+sizeof(SendStr)); //verify that ack is ok if (htonl(tcph2->th_ack)+1!=htonl(tcph->th_seq)+sizeof(SendStr)) { printf("camera ACK to HTTP getimage request seq does not match last ack\n"); seq=tcph->th_seq; //guessed ack=tcph->th_ack; //guessed SendPacket(TH_RST,seq,ack,0,0,0); //Reset //camera will ack RST //StartIPImages(); //start over again with SYN - problem gets ipq handle again } } //IPQM_PACKET } //skip==0 //ip camera should now be sending images return(1); } //end StartIPImages int GetIPImage(u8 *img) { // unsigned char buffer[BUFFSIZE]; int status=0,bytes=0,numbytes,pasthtml; // char s_ip[20],d_ip[20]; // FILE *fptr; // char packet[4096]; // struct ip *iph,*iph2; //IP protocol header // struct tcphdr *tcph,*tcph2; //TCP header struct pseudo_header pseudo; // char one = 1; // char *eoh = packet + sizeof(struct iphdr) + sizeof(struct tcphdr); //char *options = "\002\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000"; // char *options = "\x02\x04\x05\xb4\x04\x02\x08\x0a\x00\x1d\x44\x98\x00\x00\x00\x00\x01\x03\x03\x02"; // char opt[20]; //option buffer char *tcpdata; //tcp data buffer (holds HTTP getimage.cgi instruction) int optlen,datalen; int lastpacket,ackflag,ignorepacket,boundary; struct timeval tp; int seq,ack; u16 chksum; // iph=(struct ip *)packet; // tcph=(struct tcphdr *)(packet+sizeof(struct ip)); //possibly the receive buffer could be the same as the send //but for now I am using two different buffers // iph2=(struct ip *)buffer; // tcph2=(struct tcphdr *)(buffer+sizeof(struct ip)); // //fptr=fopen("out.jpg","wb"); numbytes=0; pasthtml=0; datalen=0; lastpacket=0; ackflag=0; boundary=0; ignorepacket=0; seq=0; ack=0; while (!lastpacket) { //getting image #if INFO printf("start while\n"); //printf("%d: %s", status, buffer); //printf("%d\n",status); printf("b4 read "); #endif //timeout is in microseconds status=ipq_read(ipqh,buffer,sizeof(buffer),2000000); if (status<=0) { lastpacket=1; //exit while printf("read timed out\n"); if (status<0) { printf("ipq_read returned negative value.\n"); } ignorepacket=1; pasthtml=4; printf("b4 StopIPImages\n"); StopIPImages(); //sleep(300); //60 seconds sport++; if (sport>50010) sport=50000; printf("Changing to port %d\n",sport); printf("start getting images again\n"); StartIPImages(); printf("after start getting images again\n"); //stop and start again } else { #if INFO printf("after read\n"); #endif //usleep(5000); #if INFO printf("%d bytes\n",status); // printf("%s",buffer); #endif tcph2=0;//to initiatize tcpdata=0; if (ipq_message_type(buffer)==IPQM_PACKET) { ipqmsg = ipq_get_packet(buffer); status = ipq_set_verdict(ipqh,ipqmsg->packet_id,NF_DROP,0,NULL); tcph2=(struct tcphdr *)((u8 *)ipqmsg->payload+sizeof(struct ip)); #if INFO ReportFlags(tcph2->th_flags); #endif tcpdata=(u8 *)tcph2+(tcph2->th_off<<2); #if INFO //printf("%s\n",tcpdata); #endif datalen=ipqmsg->data_len-sizeof(struct ip)-(tcph2->th_off<<2); //includes options //Check checksum chksum=tcph2->th_sum; memset(&pseudo,0,sizeof(pseudo)); pseudo.protocol = IPPROTO_TCP; pseudo.length = htons(ipqmsg->data_len-sizeof(struct ip)); //adjust TCP size for checksum // printf("offset=%x\n",optlen+datalen+(datalen%2))); tcpdata[datalen]=0; //clear extra if odd memcpy((u8 *)tcpdata+datalen+(datalen%2),(u8 *)&pseudo,sizeof(struct pseudo_header)); tcph2->th_sum=0; tcph2->th_sum=csum((u16 *)tcph2-4,(ipqmsg->data_len-sizeof(struct ip)+sizeof(struct pseudo_header)+9 )>>1); //+1 for odd packets if (chksum!=tcph2->th_sum) { printf("Camera packet seq:%8x has TCP checksum error\n",htonl(tcph2->th_seq)); printf("cam:%04x actual:%04x\n",htons(chksum),htons(tcph2->th_sum)); ignorepacket=1; } //sizeof(struct tcphdr)+optlen+ datalen #if INFO // printf("datalen=%d\n",ipqmsg->data_len-sizeof(struct ip)-sizeof(struct tcphdr)); printf("datalen=%d\n",datalen); //printf("%08x\n",*(u32 *)tcpdata); #endif //datalen=ipqmsg->data_len-sizeof(struct ip)-sizeof(struct tcphdr); //tcpdata=(char *)tcph2+sizeof(struct tcphdr); ackflag=1; if (tcph2->th_flags&TH_RST) { ackflag=0; printf("Acking RST\n"); seq=tcph2->th_ack; //seq is last ack ack=htonl(htonl(tcph2->th_seq)+datalen);//+lastpacket); SendPacket(TH_ACK,seq,ack,0,0,0); #if INFO printf("sent ack\n"); #endif } if (tcph2->th_flags&TH_PUSH) ackflag=1; if (tcph2->th_flags&TH_FIN) { lastpacket=1; #if INFO printf("got last packet\n"); #endif //have to resync ignorepacket=1; //possibly wait a few seconds? //does not always start //sleep(5); //5 seconds StopIPImages(); //sleep(300); //60 seconds sport++; if (sport>50010) sport=50000; printf("Changing to port %d\n",sport); #if INFO printf("start getting images again\n"); #endif StartIPImages(); #if INFO printf("after start getting images again\n"); #endif //ackflag=1; } //streaming is the fastest, because waiting for FIN //takes 200ms, and FIN is the only way (technically) //of knowing the data is done. //this way the text "-- IPCAMBOUNDARY" arrives at the //beginning of the next image and we can just end there if (*(u32 *)tcpdata==0x50545448) { //HTTP #if INFO printf("http:\n"); #endif //check to see if this is a: //URL /cgi-bin/getimage.cgi was not found on this server. // printf("%08x\n",*(u32 *)(tcpdata+9)); if (*(u32 *)(tcpdata+9)==0x20343034) { //404 NOT FOUND #if INFO printf("http: 404 Not Found\n"); #endif //sleep(300); //sleep 5 minutes and try again //perhaps could use different port ignorepacket=1; pasthtml=4; StopIPImages(); sport++; if (sport>50010) sport=50000; printf("Changing to port %d\n",sport); #if INFO printf("start getting images again\n"); #endif StartIPImages(); #if INFO printf("after start getting images again\n"); #endif lastpacket=1; } else { ignorepacket=1; //dont write to jpg //ackflag=0; //dont ack, will ack here //SendPacket(TH_ACK,seq,ack,0,0,0); //do ack again with last values //ack=htonl(tcph2->seq); //ack=tcph2->th_seq; //SendPacket(TH_ACK,tcph->th_seq,ack,0,0,0); pasthtml=4; //can be data in HTTP packet //but don't think there is data in the HTTP when motion=1 } //404 } if (*(u32 *)tcpdata==0x50492d2d) { #if INFO printf("--IPCAM\n"); #endif //jpg frame in getimage.cgi?motion=1 is --IPCAM if (boundary==0) { //printf("--IPCAM START\n"); pasthtml=4; tcpdata=(char *)tcpdata+45; //header is 45 bytes long if (datalen>0) datalen-=45; //else ignorepacket=1; boundary++; } else { lastpacket=1; numbytes-=2; //for some reason 2 extra bytes #if INFO printf("--IPCAM END\n"); //marks start of new image #endif } } //printf("after data = %x]n",*(u32 *)((char *)tcpdata+datalen+4)); } //IPQM_PACKET //ignore all packets until we have a new --IPCAM if (datalen>0 && boundary>0 &&!lastpacket) { #if INFO printf("datalen>0 boundary>0 !lastpacket\n"); //if (datalen>0 && boundary>0 &&!lastpacket) { #endif // if (pasthtml<3 || ignorepacket) { //remove HTML header if (pasthtml<3) { //remove HTML header //basically 0d0a0d0a is the end of the header #if INFO printf("pasthtml<3\n"); #endif bytes=0; while(bytes3 #if INFO printf("copy all data\n"); #endif if (datalen>0) { // printf("lastpacket=%d ignorepacket=%d\n",lastpacket,ignorepacket); //if (!lastpacket && !ignorepacket) { //don't write FIN packet // printf("memcpy %d %x %d\n",numbytes,*(u32 *)tcpdata,datalen); memcpy(img+numbytes,tcpdata,datalen); // printf("data2=%x\n",*(u32 *)tcpdata,datalen); // printf("img=%x numbytes=%d\n",*(u32 *)img,numbytes); //fwrite(tcpdata,datalen,1,fptr); //} numbytes+=datalen; } //datalen>0 } } //datalen>0 ignorepacket=0; //SEND ACK if (ackflag) { //ack every push flag and last HTML packet (end of segment) #if INFO printf("ack\n"); #endif ackflag=0; //SEND ACK PACKET seq=tcph2->th_ack; //seq is last ack ack=htonl(htonl(tcph2->th_seq)+datalen);//+lastpacket); SendPacket(TH_ACK,seq,ack,0,0,0); #if INFO printf("sent ack\n"); #endif } //ackflag #if INFO printf("end while\n"); #endif } //read timed out } //end while #if INFO printf("after while\n"); #endif //fclose(fptr); // printf("%d: %s",bytes,tcpdata); #if INFO printf("return numbytes\n"); #endif return(numbytes); } //end GetIPImage int StopIPImages() { int status=0,bytes=0,numbytes,pasthtml; // char s_ip[20],d_ip[20]; // FILE *fptr; // char packet[4096]; // struct ip *iph,*iph2; //IP protocol header // struct tcphdr *tcph,*tcph2; //TCP header // struct pseudo_header pseudo; // char one = 1; // char *eoh = packet + sizeof(struct iphdr) + sizeof(struct tcphdr); //char *options = "\002\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000"; // char *options = "\x02\x04\x05\xb4\x04\x02\x08\x0a\x00\x1d\x44\x98\x00\x00\x00\x00\x01\x03\x03\x02"; // char opt[20]; //option buffer // char *tcpdata; //tcp data buffer (holds HTTP getimage.cgi instruction) int optlen,datalen,seq,ack; int lastpacket,ackflag,ignorepacket,boundary; struct timeval tp; //it is not a wonderful answer, but it vastly speeds things up //and does appear to work: //simply send a RST after getting data, dont even FIN the connection /* seq=tcph2->th_ack; //seq is last ack ack = htonl(htonl(tcph2->th_seq)+1); //no add 1 fprintf(stdout,"b4 send RST\n"); SendPacket(TH_RST,seq,ack,0,0,0); */ //camera will ACK RST /* //send FIN/ACK when HTTP arrives //need to delay 2 times the maximum amount of time an IP datagram might live in the Internet // sleep(10); // // usleep(100000);// us //SEND FIN PACKET pseudo.length = htons(sizeof(struct tcphdr)); //adjust TCP size for checksum memcpy((u8 *)tcph+sizeof(struct tcphdr),(u8 *)&pseudo,sizeof(struct pseudo_header)); //ip header length changes if options and/or data iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); iph->ip_sum = csum((u16 *)packet,(((iph->ip_len>>1) + 1) & ~1)); //tcp header //reuse ackflag //seq and ack remain the same as the last ACK // ackflag=tcph->th_seq; // tcph->th_seq=tcph->th_ack; //seq is last ack (ours) // tcph->th_ack = ackflag; //FIN ack uses SEQ of our last ACK // tcph->th_seq=tcph2->th_ack; //seq is last ack // tcph->th_ack = htonl(htonl(tcph2->th_seq)+1); //no add 1 tcph->th_off = (sizeof(struct tcphdr))>>2; tcph->th_flags=TH_FIN|TH_ACK; tcph->th_sum=0; tcph->th_sum=csum((u16 *)tcph-4,(sizeof(struct tcphdr)+sizeof(struct pseudo_header)+9 )>>1); //+1 for odd packets status=sendto(sock,packet,iph->ip_len,0,(struct sockaddr *)&sockin,sizeof(sockin)); //read ACK to FIN status=ipq_read(ipqh,buffer,sizeof(buffer),0); //printf("FIN ACK= %d bytes\n",bytes); tcph2=0;//to initiatize tcpdata=0; if (ipq_message_type(buffer)==IPQM_PACKET) { ipqmsg = ipq_get_packet(buffer); status = ipq_set_verdict(ipqh,ipqmsg->packet_id,NF_DROP,0,NULL); tcph2=(struct tcphdr *)(ipqmsg->payload+sizeof(struct ip)); // printf("datalen=%d\n",ipqmsg->data_len-sizeof(struct ip)-sizeof(struct tcphdr)); datalen=ipqmsg->data_len-sizeof(struct ip)-sizeof(struct tcphdr); tcpdata=(char *)tcph2+sizeof(struct tcphdr); printf("last ack datalen= %d\n",datalen); } //IPQM_PACKET */ fprintf(stdout,"b4 ipq destroy\n"); ipq_destroy_handle(ipqh); close(sock); fprintf(stdout,"end StopIPImages\n"); return(1); } //end StopIPImages int StartIPAudio(void) { #define SampleRate 8000 //8000Htz #define SampleSize 8 //8 bit sample #define Channels 1 //Mono //#define BUFFSIZE 2048 #define SendAStr "GET /cgi-bin/getaudio.cgi HTTP/1.1\r\nHost: 192.168.0.106\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10)\r\nGecko/20050716 Firefox/1.0.6\r\nAccept: image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection:\r\nkeep-alive\r\nIf-Modified-Since: Sat, 01 Jan 2000 18:09:09 GMT\r\nCache-Control: max-age=0\r\n\r\n" #define Detect 1 //Only record changes #define Diff 3 //Difference between last sample struct sockaddr_in sockin2; int optval; //audio appears to work with SOCK_STREAM //and therefore does not appear to need SOCK_RAW //making this easier (SYN and ACKs automatically done) //by default this computer uses a port such as 49342 to send //printf("StartIPSoundo\n"); //strcpy(d_ip2,"192.168.0.107"); strcpy(d_ip2,"192.168.0.106"); //printf("StartIPSound\n"); port2=80; //1047 80 /* Create the TCP socket */ if ((sock2 = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) { Die("Failed to create socket\n"); } optval=512; setsockopt(sock2,IPPROTO_TCP,TCP_MAXSEG,&optval,sizeof(optval)); /* Construct the server sockaddr_in structure */ memset(&sockin2, 0, sizeof(sockin2)); /* Clear struct */ sockin2.sin_family = AF_INET; /* Internet/IP */ sockin2.sin_addr.s_addr = inet_addr(d_ip2); /* IP address */ sockin2.sin_port = htons(port2); /* server port */ /* Establish connection */ if (connect(sock2,(struct sockaddr *)&sockin2,sizeof(sockin2))<0) { Die("Failed to connect with server\n"); } //Send the HTTP request for a audio data if (write(sock2,SendAStr,sizeof(SendAStr)-1)!= sizeof(SendAStr)-1) { Die("Failed to send bytes to client"); } return(1); } //end StartIPAudio int GetIPAudio(int Seconds) { #define SampleRate 8000 //8000Htz #define SampleSize 8 //8 bit sample #define Channels 1 //Mono //#define BUFFSIZE 2048 #define Detect 1 //Only record changes #define DiffSize 0x20 //Difference between last sample 0x60-0x80-0xa0 typedef struct { long ChunkID; long ChunkSize; long Format; } WaveRiffChunk; typedef struct { long chunkID; long chunkSize; short wFormatTag; unsigned short wChannels; unsigned long dwSamplesPerSec; unsigned long dwAvgBytesPerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; } WavFormatChunk; typedef struct { long chunkID; long chunkSize; unsigned char waveformData[]; } WavDataChunk; // struct sockaddr_in sockin2; // u8 buffer[BUFFSIZE]; u8 sbuffer[SampleRate*SampleSize*Channels*10]; //no more than 10 seconds! (malloc+free in thread has problem) unsigned int echolen; int status=0,bytes=0,numbytes,pasthtml; char filename[255],filebase[255]; FILE *fptr; int wend,wend2,tcnt,skip2,i,change,NumSamp,ms; WaveRiffChunk wrc; WavFormatChunk wfc; WavDataChunk wdc; time_t temptime; struct tm *utime; struct timeval tmv; u8 last; NumSamp=Seconds*SampleRate*SampleSize*Channels; // printf("%d: %s",bytes,buffer); numbytes=0; pasthtml=0; wend=0; wend2=0; skip2=0; //audio will continue until stopped //before and after every 2000 bytes are 2 byte markers //ffa8=before //ffa9=after while (!wend) { //printf("%d: %s", status, buffer); // printf("%d\t%d\n",status,numbytes); // fwrite(buffer,status,1,fptr); status=read(sock2,buffer,sizeof(buffer)); // status=read(sock2,buffer,sizeof(buffer)); //printf("status %d: %s", status, buffer); printf("status %d",status); //check if acked //there may be data in the HTTP header if (*(u32 *)buffer != 0x50545448) {//HTTP (skip this header) pasthtml=4; } else { printf("HTTP\n"); } //printf("%d\t%d\t%d\n",status,numbytes,NumSamp); // fwrite(buffer,status,1,fptr); if (pasthtml<3) { //remove HTML header //basically 0d0a0d0a is the end of the header bytes=0; while(bytes3 //packets may begin with ffa8 or end with ffa9 //and these tags need to be removed //printf("start:%04x end:%04x status:%d\n",*(u16 *)buffer,*(u16 *)(buffer+status-2),status); if (*(u16 *)buffer==0xa8ff) { //printf("ffa8\n"); if (*(u16 *)(buffer+status-2)==0xa9ff) { memcpy(sbuffer+numbytes,buffer+2,status-4); numbytes+=status-4; } else { memcpy(sbuffer+numbytes,buffer+2,status-2); numbytes+=status-2; } } else { if (*(u16 *)(buffer+status-2)==0xa9ff) { //printf("ffa9\n"); memcpy(sbuffer+numbytes,buffer,status-2); numbytes+=status-2; } else { //no tags copy full buffer memcpy(sbuffer+numbytes,buffer,status); numbytes+=status; } } } //else pasthtml>3 //numbytes+=status; //numbytes+=bytes; //if (numbytes>SampleRate*Seconds) wend=1; //64kb = 8khz 8-bit printf("%d\t%d\t%d\n",status,numbytes,NumSamp); if (numbytes>NumSamp) wend=1; //64kb = 8khz 8-bit } //end while //printf("before detect\n"); if (Detect) { //done collecting data, look for change in audio data wend=0; last=sbuffer[0]; i=1; change=0; while(!wend && i(last+DiffSize) || sbuffer[i]<(last-DiffSize)) { change=1; wend=1; //exit while } else last=sbuffer[i]; i++; } //!wend } //Detect printf("change=%d\n",change); if (change || !Detect) { // printf("write file\n"); wrc.ChunkID=0x46464952; //RIFF; wrc.ChunkSize=4+sizeof(WavFormatChunk)+sizeof(WavDataChunk)+SampleRate*(SampleSize>>3)*Seconds; //filesize-8 wrc.Format=0x45564157; //WAVE //make .wav file header wfc.chunkID=0x20746d66; //fmt wfc.chunkSize=sizeof(WavFormatChunk)-8; wfc.wFormatTag=1; //PCM=1, others=compression wfc.wChannels=Channels; wfc.dwSamplesPerSec=SampleRate; wfc.dwAvgBytesPerSec=Channels*SampleRate*(SampleSize>>3); wfc.wBlockAlign=Channels*(SampleSize>>3); //bytes per sample=Channels*SampleSize wfc.wBitsPerSample=8; wdc.chunkID=0x61746164; //data wdc.chunkSize=Channels*SampleRate*(SampleSize>>3)*Seconds; //open .wav file and write header mkfilebase (filebase, currenttime,1); //sprintf(filename, "%s_%d.jpg", filebase,b); // sprintf(filename, "%s.jpg",filebase); //get ms gettimeofday(&tmv,NULL); ms=tmv.tv_usec/1000; temptime=time(NULL); utime=localtime(&temptime); // sprintf(filebase, "%s-%03d", filebase, ms); sprintf(filename, "%s01-%04d%02d%02d-%02d%02d%02d%03d.wav", filebase,utime->tm_year+1900, utime->tm_mon+1, utime->tm_mday, utime->tm_hour,utime->tm_min, utime->tm_sec,ms); /* temptime=time(NULL); utime=localtime(&temptime); gettimeofday(&tmv,NULL); sprintf(fname,"a%02d%02d%02d-%06d.wav",utime->tm_hour,utime->tm_min,utime->tm_sec,(int)tmv.tv_usec); */ fptr=fopen(filename,"wb"); fwrite(&wrc,sizeof(wrc),1,fptr); fwrite(&wfc,sizeof(wfc),1,fptr); fwrite(&wdc,8,1,fptr); //write data fwrite(sbuffer,NumSamp,1,fptr); fclose(fptr); } //end if change // bytes=recv(sock,buffer,BUFFSIZE-1,0); // bytes = recv(sock,buffer,BUFFSIZE,0); //bytes = recv(sock,buffer,1,0); //bytes=read(sock,buffer,1); // printf("%d: %s",bytes,buffer); //printf("free sbuffer %x\n",sbuffer); //free(sbuffer); // printf("done with audio\n"); return(1); } //end GetIPAudio int StopIPAudio(void) { close(sock2); return(1); } //end StopIPAudio void GetIPAudioThread(void) { pthread_t thread1; while(1) { pthread_create(&thread1,NULL,GetIPAudio,5); pthread_join(thread1,NULL); //wait for thread to complete //use wait()? } } //GetIPAudioThread void DecompressThread(struct DecmpThread *Dth) { DecompressJpeg(Dth->ipimg,Dth->img,Dth->nb,Dth->w,Dth->h); //bmp format } //DecompressThread #endif //if IPCAM | AUDIO int main(int argc, char **argv) { int i,a,b,diff; time_t lastframe=0; char linkpath[255]; FILE *picture; char Key; struct images imgs[MAXCAM]; #if IPCAM | AUDIO u8 *ipimg; int nb=0; pthread_t thread1; pthread_t thrjpeg; struct DecmpThread Dth; #endif int finish; struct timeval tmv; int ms; int gt,totalwidth,totalheight,jpgok; b=0; gt=0; camera[0]=1; camera[1]=0; camera[2]=0; totalwidth=0; for(i=0;ifid); depth = DefaultDepth(xdisplay, DefaultScreen(xdisplay)); visual=DefaultVisual(xdisplay,DefaultScreen(xdisplay)); fprintf(stderr, "Screen depth=%d\n",depth); //fximage=XCreateImage(xdisplay,visual,depth,ZPixmap,0,0,640,300,8,0); //640x3 %8? //fximage->data=(char *)malloc(fximage->bytes_per_lie*300+16); //pixmap[0] = XCreatePixmap(xdisplay, xwindow, 352,288, depth); //pixmap[1] = XCreatePixmap(xdisplay, xwindow, 640,350, depth); for(i=0;ibytes_per_line=conf[i].width*3;//1056; //352*3 Img[i]->bits_per_pixel=24; pmap[i]=XCreatePixmap(xdisplay,xwindow,conf[i].width,conf[i].height,depth); XFlush (xdisplay); #if !IPCAM && !AUDIO dev[i]=open (conf[i].device, O_RDWR); if (dev[i] < 0) { fprintf(stderr,"Failed to open video device %s",conf[i].device); exit(1); } printf("Opened video device %d\n",i); #endif //!IPCAM && !AUDIO /* create a reference frame */ memcpy(imgs[i].ref, imgs[i].new,conf[i].width*conf[i].height*3); imgs[i].width=conf[i].width; imgs[i].height=conf[i].height; } //end for i /* Img[1]= XCreateImage(xdisplay,visual,depth,ZPixmap,0,0,conf[1].width,conf[1].height,8,0); Img[1]->bytes_per_line=conf[1].width*3;//3 1056; //352*3 Img[1]->bits_per_pixel=24; pmap[1]=XCreatePixmap(xdisplay,xwindow,conf[1].width,conf[1].height,depth); */ /* dev[1]=open (conf[1].device, O_RDWR); if (dev[1] < 0) { perror ("Failed to open video device 2"); exit(1); } printf("Opened video device 2\n"); */ /* set the device settings */ //v4l_start (conf.device, conf.width, conf.height, conf.input, conf.norm); /* Capture first image, or we will get an alarm on start */ //v4l_next (conf.device, imgs.new, conf.width, conf.height); #if 0 /* create a reference frame */ memcpy(imgs[0].ref, imgs[0].new,conf[0].width*conf[0].height*3); memcpy(imgs[1].ref, imgs[1].new, conf[1].width*conf[1].height*3); imgs[0].width=conf[0].width; imgs[0].height=conf[0].height; imgs[1].width=conf[1].width; imgs[1].height=conf[1].height; #endif //MAIN LOOP //start IP camera #if IPCAM StartIPImages(); //may need to be close to getimage // nb=GetIPImage(ipimg); //get one image to stop checksum errors #endif #if AUDIO StartIPAudio(); pthread_create(&thread1,NULL,GetIPAudioThread,5); #endif while (!finish) { // printf("in while !finish\n"); if (XPending(xdisplay)) { XNextEvent (xdisplay, &xevent); //fprintf(stderr,"%d ",xevent.type); switch (xevent.type) { /* ignore this event */ case Expose: break; case ButtonPress: fprintf(stdout,"A mouse button was pressed.\n"); break; case KeyPress: Key=XLookupKeysym(&xevent.xkey,0); //fprintf(stderr,"key=%x \n",Key); // if (Key==-30 || Key==-31) ex=0; //ignore shift keys switch (Key) { /* branch to appropiate key handler */ case 0x30: //0 //stop all motors break; case 0x31: //1 break; case 0x32: //2 break; case 0x33: //3 break; case 0x34: //4 break; case 0x51: //left arrow break; case 0x52: //up arrow break; case 0x53: //right arrow break; case 0x54: //down arrow break; case 0x61: //a 3 v4l_bright (dev[0], 500); // v4l_autobright(dev[0], imgs[0].new, conf[0].width, conf[0].height); // v4l_autobright(dev[1], imgs[1].new, conf[1].width, conf[1].height); break; case 0x62: //b balance //v4l_bright (dev, 100); break; case 0x63: //c break; case 0x64: //d //v4l_bright (dev, -100); break; case 0x65: //e break; case 0x68: //h half speed break; case 0x69: //i start getting images break; case 0x6a: //j break; case 0x6b: //k break; case 0x73: //s v4l_bright (dev[1], 500); break; case 0x74: //t break; case 0x76: //v break; case 0x77: //w break; case 0x78: //x v4l_bright (dev[1], -500); break; case 0x7a: //z v4l_bright (dev[0], -500); break; case 0x1b: /* Esc */ // ex=1; //exit finish=1; break; default: break; } //end switch Key break; } //end switch Xevent } //end if Xevent Pending currenttimep=time(NULL); currenttime=localtime(¤ttimep); // gettimeofday(&tmv,NULL); // ms=tmv.tv_usec/1000; // fprintf(stderr,"ms=%d ",ms); if ((lastcurrenttime->tm_sec != currenttime->tm_sec && b==0) || CONSTANTRATE) { //only 1 image every second unless CONSTANTRATE //fprintf(stderr,"%d=%d ",lastcurrenttime->tm_sec,currenttime->tm_sec); lastcurrenttime->tm_sec=currenttime->tm_sec; gt=1; //b=0; // b=0; } else { if (gt) { b++; //gt=1; } if (b==NUMCAM) { gt=0; b=0; } } #if 0 if (lastcurrenttime->tm_sec != currenttime->tm_sec) { //only 1 image every second //fprintf(stderr,"%d %d\n",lastcurrenttime->tm_sec,currenttime->tm_sec); lastcurrenttime->tm_sec=currenttime->tm_sec; //get cam0 gt=1; b=0; } else { if (ms>350 && b==0) { gt=1; b=1; } else { if (ms>700 && b==0) { gt=1; b=2; fprintf(stderr,"here"); } } } #endif //imgs.new=vid_next(dev, imgs.new, conf.width, conf.height); if (gt==1) //read in image { if (camera[b]==1) { #if IPCAM // fprintf(stdout,"GetImage\n"); jpgok=0; while (!jpgok) { //printf("in while jpgok\n"); nb=GetIPImage(ipimg); //jpeg format #if INFO printf("after GetIPImage\n"); #endif //fprintf(stdout,"Numbytes=%d\n",nb); jpgok=1; if (*(u16 *)ipimg!=0xd8ff) { printf("No SOI marker (FFD8). Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+2)!=0xe2ff) { printf("No FFE2 marker. Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+8)!=0xe7ff) { printf("No FFE7 marker. Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+17)!=0xc0ff) { printf("No FFC0 marker. Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+0x24)!=0xdbff) { printf("No FFDB marker. Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+0xaa)!=0xc4ff) { printf("No FFC4 marker. Skipping jpg.\n"); jpgok=0; } if (*(u16 *)(ipimg+590)!=0xdaff) { printf("no FFDA SOS (Start of stream marker found), skipping jpeg\n"); jpgok=0; } if (*(u16 *)(ipimg+nb-2)!=0xd9ff) { //make sure the SOS marker is there or else DecompressJpeg will exit with error printf("No EOI marker (FFA9) at 2 bytes from end. %04x nb=%d skipping.\n",*(u16 *)(ipimg+nb-2),nb); jpgok=0; } if (!jpgok) { //if error write out image mkfilebase (filebase, currenttime,b); //get ms gettimeofday(&tmv,NULL); ms=tmv.tv_usec/1000; sprintf(filename2, "%serr%02d-%04d%02d%02d-%02d%02d%02d%03d.jpg", filebase,jpgok,currenttime->tm_year+1900, currenttime->tm_mon+1, currenttime->tm_mday, currenttime->tm_hour, currenttime->tm_min, currenttime->tm_sec,ms); //write file for testing purposes WriteIpCamImg(filename2,ipimg,nb); } //if !jpgok } //while !jpgok //it may be from a resend //need to add ack check in tcp/ip code //way to turn off exit on error with jpeg? //maybe find and develop C code for decompressor //actually gadcam does not send ffd9 SOS end marker //skip decompress and compare jpeg data only? /* //I thought putting the Decompress in a thread would stop //the program from exiting. No, it did not. Dth.ipimg=ipimg; Dth.img=imgs[b].new; Dth.nb=nb; Dth.w=imgs[b].width; Dth.h=imgs[b].height; pthread_create(&thrjpeg,NULL,DecompressThread,&Dth); pthread_join(thrjpeg,NULL); //wait for thread to complete */ //crashes: //just hangs, no TCP/IP traffic. Perhaps stopped on a read that never came? DecompressJpeg(ipimg,imgs[b].new,nb,imgs[b].width,imgs[b].height); //bmp format #endif #if !IPCAM && !AUDIO read(dev[b], imgs[b].new, conf[b].width*conf[b].height*3); #endif #if AUTOBRIGHT && !IPCAM && !AUDIO v4l_autobright(b, imgs[b].new, conf[b].width, conf[b].height); #endif } //read(dev[0], imgs[0].new, conf[0].width*conf[0].height*3); //read(dev[1], imgs[1].new, conf[1].width*conf[1].height*3); //v4l_autobright(dev[0], imgs[0].new, conf[0].width, conf[0].height); //v4l_autobright(dev[1], imgs[1].new, conf[1].width, conf[1].height); //fprintf(stderr,"hereb"); if (camera[b]==1) { Img[b]->data=imgs[b].new; //XPutImage(xdisplay,pmap[0],xgc,Img[0],0,0,0,0,351,287); XPutImage(xdisplay,pmap[b],xgc,Img[b],0,0,0,0,conf[b].width-1,conf[b].height-1); XCopyArea(xdisplay,pmap[b],xwindow,xgc,0,0,conf[b].width,conf[b].height,b*conf[b].width,0); } //if camera[b] XFlush (xdisplay); /* for (i=0; itm_year + 1900, currenttime->tm_mon + 1, currenttime->tm_mday); sprintf(timestamp, "%02d_%02d_%02d", currenttime->tm_hour, currenttime->tm_min, currenttime->tm_sec); //currenttime->tm_sec, shots); /* // if (!IPCAM) { draw_text(imgs[b].new, conf[b].width-70, conf[b].height-20, conf[b].height, conf[b].width, datestamp); draw_text(imgs[b].new, conf[b].width-70, conf[b].height-10, conf[b].height, conf[b].width, timestamp); //} */ /* draw_text(imgs[b].new, conf[b].width-70, conf[b].height-20, conf[b].height,conf[b].width, datestamp); draw_text(imgs[b].new, conf[b].width-70, conf[b].height-10, conf[b].height,conf[b].width, timestamp); */ // draw_text(imgs[1].new, conf[1].width-70, conf[1].height-20, conf[1].height,conf[1].width, datestamp); // draw_text(imgs[1].new, conf[1].width-70, conf[1].height-10, conf[1].height,conf[1].width, timestamp); //for(b=b;b<2;b++) //{ //compare last image (reference image) to new image diff=0; for(a=0;a*(imgs[b].ref+a)+CHANGERANGE)) {diff++;} } if (diff>MAXCHANGE) //3000 { // fprintf(stderr,"diff=%d\n",diff); // fprintf(stderr,"%d-%s\n",b,timestamp); mkfilebase (filebase, currenttime,b); //sprintf(filename, "%s_%d.jpg", filebase,b); // sprintf(filename, "%s.jpg",filebase); //get ms gettimeofday(&tmv,NULL); ms=tmv.tv_usec/1000; // sprintf(filebase, "%s-%03d", filebase, ms); //#if 0 //IBMCAM //cam 4,5 sprintf(filename, "%s%02d-%04d%02d%02d-%02d%02d%02d%03d.jpg", filebase,b+4,currenttime->tm_year+1900, currenttime->tm_mon+1, currenttime->tm_mday, currenttime->tm_hour, currenttime->tm_min, currenttime->tm_sec,ms); //cam 1,2,3 sprintf(filename, "%s%02d-%04d%02d%02d-%02d%02d%02d%03d.jpg", filebase,b+STARTCAM,currenttime->tm_year+1900, currenttime->tm_mon+1, currenttime->tm_mday, currenttime->tm_hour, currenttime->tm_min, currenttime->tm_sec,ms); //#endif fprintf(stderr,"%s\n",filename); draw_text(imgs[b].new, conf[b].width-70, conf[b].height-20, conf[b].height, conf[b].width, datestamp); draw_text(imgs[b].new, conf[b].width-70, conf[b].height-10, conf[b].height, conf[b].width, timestamp); /* GC gr_context1; XFontStruct *fontinfo; XGCValues gr_values; fontinfo = XLoadQueryFont(xdisplay,"6x10"); gr_values.font = fontinfo->fid; gr_values.function = GXcopy; gr_values.plane_mask = AllPlanes; gr_values.foreground = BlackPixel(xdisplay,xscreen); gr_values.background = WhitePixel(xdisplay,xscreen); gr_context1=XCreateGC(xdisplay,xwindow, GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gr_values); //,pmap[b] XDrawImageString(xdisplay,gr_context1,imgs[b].new,conf[1].width-200, conf[1].height-50,datestamp,strlen(datestamp)); //XDrawImageString(xdisplay,xgc,pmap[b],conf[1].width-70, conf[1].height-20,datestamp,strlen(datestamp)); */ //fprintf(stderr,"here %d %s",b,filename); #if PUTPICTURE // if (IPCAM) WriteIpCamImg(filename2,ipimg,nb); //else put_picture(filename, imgs[b].new, conf[b].width, conf[b].height,conf[b].quality); #endif //fprintf(stderr,"here2"); } //copy new image to reference image memcpy(imgs[b].ref, imgs[b].new, conf[b].width*conf[b].height*3); }//end if camera[b]==1 //}//end for b //gt=0; } //end gt image gt==1 //flushes all streams stdio fclose fflush(0); // } //end if lasttime->tm_sec different from curtime } //end if lasttime->tm_sec finish? if (!finish) fprintf(stderr,"error"); //start IP camera #if IPCAM StopIPImages(); #endif #if AUDIO //stop getaudio thread pthread_cancel(thread1); StopIPAudio(); #endif for(i=0;i404 Not Found

404 Not Found

The requested URL /cgi-bin/getimage.cgi was not found on this server. */