/* * cam_hacks.c * does strange things to a video feed * GPL - based on Jaromil's hasciicam * Thank you Rasta Coder! You are the man! */ /* NOTE I removed the YtoRGB thinghhy because it was causing some black pixels to become white. It was annoying! TODO fix beating fix 16-bit */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IMAGE_WIDTH 300 //the clip is divided up into this number of segments #define IMAGE_HEIGHT 200 //this is the number of frequencies... #define SCALE 4 #define SCREEN_WIDTH IMAGE_WIDTH*SCALE #define SCREEN_HEIGHT IMAGE_HEIGHT*SCALE char device[256]; int quiet = 0; int mode = 0; int useftp = 0; int input = 1; int daemon_mode = 0; int TOGGLE_invert = 0; int TOGGLE_threshold = 0; unsigned char threshold_value = 128; struct geometry { int w, h, size; int bright, contrast, gamma; }; struct geometry vid_geo; /* if width&height have been manually changed */ int whchanged = 0; char device[256]; int have_tuner = 0; /* v4l */ unsigned char *grab_data; struct video_capability grab_cap; struct video_mbuf grab_map; struct video_mmap grab_buf[32]; struct video_channel grab_chan; struct video_picture grab_pic; struct video_tuner grab_tuner; int minw, minh, maxw, maxh; int dev = -1; int cur_frame, ok_frame; int palette; /* rgb image is sampled */ unsigned char *rgb_surface; void setpixel(SDL_Surface *screen, int x, int y, Uint8 r, Uint8 g, Uint8 b) { Uint8 *ubuff8; Uint16 *ubuff16; Uint32 *ubuff32; Uint32 color; char c1, c2, c3; /* Lock the screen, if needed */ if(SDL_MUSTLOCK(screen)) { if(SDL_LockSurface(screen) < 0) return; } /* Get the color */ color = SDL_MapRGB( screen->format, r, g, b ); /* How we draw the pixel depends on the bitdepth */ switch(screen->format->BytesPerPixel) { case 1: ubuff8 = (Uint8*) screen->pixels; ubuff8 += (y * screen->pitch) + x; *ubuff8 = (Uint8) color; break; case 2: ubuff8 = (Uint8*) screen->pixels; ubuff8 += (y * screen->pitch) + (x*2); ubuff16 = (Uint16*) ubuff8; *ubuff16 = (Uint16) color; break; case 3: ubuff8 = (Uint8*) screen->pixels; ubuff8 += (y * screen->pitch) + (x*3); if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { c1 = (color & 0xFF0000) >> 16; c2 = (color & 0x00FF00) >> 8; c3 = (color & 0x0000FF); } else { c3 = (color & 0xFF0000) >> 16; c2 = (color & 0x00FF00) >> 8; c1 = (color & 0x0000FF); } ubuff8[0] = c3; ubuff8[1] = c2; ubuff8[2] = c1; break; case 4: ubuff8 = (Uint8*) screen->pixels; ubuff8 += (y*screen->pitch) + (x*4); ubuff32 = (Uint32*)ubuff8; *ubuff32 = color; break; default: fprintf(stderr, "Error: Unknown bitdepth!\n"); } /* Unlock the screen if needed */ if(SDL_MUSTLOCK(screen)) { SDL_UnlockSurface(screen); } } int vid_detect(char *devfile) { int counter, res; char *capabilities[] = { "VID_TYPE_CAPTURE can capture to memory", "VID_TYPE_TUNER has a tuner of some form", "VID_TYPE_TELETEXT has teletext capability", "VID_TYPE_OVERLAY can overlay its image to video", "VID_TYPE_CHROMAKEY overlay is chromakeyed", "VID_TYPE_CLIPPING overlay clipping supported", "VID_TYPE_FRAMERAM overlay overwrites video memory", "VID_TYPE_SCALES supports image scaling", "VID_TYPE_MONOCHROME image capture is grey scale only", "VID_TYPE_SUBCAPTURE capture can be of only part of the image" }; if (-1 == (dev = open(devfile,O_RDWR|O_NONBLOCK))) { perror("!! error in opening video capture device: "); return -1; } else { close(dev); dev = open(devfile,O_RDWR); } res = ioctl(dev,VIDIOCGCAP,&grab_cap); if(res<0) { perror("E' QUESTOOO!!!!!! error in VIDIOCGCAP: "); return -1; } fprintf(stderr,"Device detected is %s\n",devfile); fprintf(stderr,"%s\n",grab_cap.name); fprintf(stderr,"%u channels detected\n",grab_cap.channels); fprintf(stderr,"max size w[%u] h[%u] - min size w[%u] h[%u]\n",grab_cap.maxwidth,grab_cap.maxheight,grab_cap.minwidth,grab_cap.minheight); fprintf(stderr,"Video capabilities:\n"); for (counter=0;counter<11;counter++) if (grab_cap.type & (1 << counter)) fprintf(stderr,"%s\n",capabilities[counter]); if (-1 == ioctl(dev, VIDIOCGPICT, &grab_pic)) { perror("!! ioctl VIDIOCGPICT: "); exit(1); } if (grab_pic.palette & VIDEO_PALETTE_RGB32) fprintf(stderr,"VIDEO_PALETTE_GREY device is able to grab 32-bit RGB\n"); if(grab_cap.type & VID_TYPE_TUNER) /* if the device does'nt has any tuner, so we avoid some ioctl this should be a fix for many webcams, thanks to Ben Wilson */ have_tuner = 1; /* set and check the minwidth and minheight */ minw = grab_cap.minwidth; minh = grab_cap.minheight; maxw = grab_cap.maxwidth; maxh = grab_cap.maxheight; if (ioctl (dev, VIDIOCGMBUF, &grab_map) == -1) { perror("!! error in ioctl VIDIOCGMBUF: "); return -1; } /* print memory info */ fprintf(stderr,"memory map of %i frames: %i bytes\n",grab_map.frames,grab_map.size); for(counter=0;counter1) ? 1 : 0; if(have_tuner) { /* does this only if the device has a tuner */ // _band = 5; /* default band is europe west */ // _freq = 0; /* resets CHAN */ if (-1 == ioctl(dev,VIDIOCGCHAN,&grab_chan)) fprintf(stderr,"!! error in ioctl VIDIOCGCHAN: %s",strerror(errno)); if (-1 == ioctl(dev,VIDIOCSCHAN,&grab_chan)) fprintf(stderr,"error in ioctl VIDIOCSCHAN: %s",strerror(errno)); /* get/set TUNER settings */ if (-1 == ioctl(dev,VIDIOCGTUNER,&grab_tuner)) fprintf(stderr,"error in ioctl VIDIOCGTUNER: %s",strerror(errno)); } /* init video size from ascii size 1 ascii pixel = 4 video pixel so video h&w are each double than ascii */ vid_geo.h = IMAGE_HEIGHT; vid_geo.w = IMAGE_WIDTH; vid_geo.size = vid_geo.w*vid_geo.h; palette =VIDEO_PALETTE_RGB24; rgb_surface = (unsigned char *) malloc (vid_geo.size*3); //we need space for all three channels (3*8 = 24bit) //#############CONTROLL PALETTE################## /*VIDEO_PALETTE_RGB24;/*VIDEO_PALETTE_YUV420P;VIDEO_PALETTE_RGB32;/V4L2_PIX_FMT_SBGGR8;V4L2_PIX_FMT_SN9C10X; VIDEO_PALETTE_YUV422;*/ for(i=0; i=grab_map.frames) ? 0 : cur_frame+1; */ ok_frame = 0; cur_frame = 0; grab_buf[ok_frame].format = palette; if (-1 == ioctl(dev,VIDIOCSYNC,&grab_buf[ok_frame])) { perror("error in ioctl VIDIOCSYNC: "); return NULL; } grab_buf[cur_frame].format = palette; if (-1 == ioctl(dev,VIDIOCMCAPTURE,&grab_buf[cur_frame])) { perror("error in ioctl VIDIOCMCAPTURE: "); return NULL; } for (c=0,cc=0;c= threshold_value) i = 255; else i = 0; return i; } int main() { int fd; /* sound device file descriptor */ int arg; /* argument for ioctl calls */ int status; /* return status of system calls */ int row, column; unsigned char r,g,b,grey,ahh; float power; float pointer_x=0, pointer_y=0; int frame_count = 0; int found_pointer = 0; int s_cap = 50; //BALL float bx = 10, by = 10, bxs = 3, bys = 0; float f, dist; /* Declare SDL Variables */ SDL_Surface *screen; SDL_Event event; SDL_Rect temp_rect; /* Initialize SDL, exit if there is an error. */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError()); return -1; } /* When the program is through executing, call SDL_Quit */ atexit(SDL_Quit); /* Grab a surface on the screen */ screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE|SDL_ANYFORMAT); if( !screen ) { fprintf(stderr, "Couldn't create a surface: %s\n", SDL_GetError()); return -1; } struct stat st; if( stat("/dev/video",&st) <0) strcpy(device,"/dev/video0"); else strcpy(device,"/dev/video"); //***Attempt detection of capture device*** if( vid_detect(device) > 0 ) { vid_init(); } else exit(-1); while (1) { /* loop until Control-C */ //capture a frame from the webcam and store it in a rgb_surfacescale bitmap grab_one(); found_pointer = 0; //display the image for (row = 0; row < IMAGE_HEIGHT; row++) { for (column = 0; column < IMAGE_WIDTH; column++) { temp_rect.x = column*SCALE; temp_rect.y = row*SCALE; temp_rect.w = SCALE; temp_rect.h = SCALE; ahh = 0; power = thresh(get_rd(column+1,row-1)) + thresh(get_rd(column+1,row)) + thresh(get_rd(column+1,row+1)) + thresh(get_rd(column,row-1)) + thresh(get_rd(column,row)) + thresh(get_rd(column,row+1)) + thresh(get_rd(column-1,row-1)) + thresh(get_rd(column-1,row)) + thresh(get_rd(column-1,row+1)); power = power / 9; /* power = get_rd(column+1,row-1) + get_rd(column+1,row) + get_rd(column+1,row+1) + get_rd(column,row-1) + get_rd(column,row) + get_rd(column,row+1) + get_rd(column-1,row-1) + get_rd(column-1,row) + get_rd(column-1,row+1); power = power / 9; power = get_rd(column+1,row-1) * get_rd(column+1,row) * get_rd(column+1,row+1) * get_rd(column,row-1) * get_rd(column,row) * get_rd(column,row+1) * get_rd(column-1,row-1) * get_rd(column-1,row) * get_rd(column-1,row+1); power = pow(power, 1/9); */ if (power > 130) { grey = 255; if (found_pointer == 0) { found_pointer = 1; pointer_x = (pointer_x+column*SCALE)/2; pointer_y = (pointer_y+row*SCALE)/2; ahh = 255; } } else grey = 0; //if (grey > threshold_value) grey = 255; else grey + 0; r = get_red(column,row); b = get_blue(column,row); g = get_green(column,row); //SDL_FillRect( screen, &temp_rect, SDL_MapRGB(screen->format,r*power/255,g*power/255,b*power/255)); SDL_FillRect( screen, &temp_rect, SDL_MapRGB(screen->format,r,g,b)); } } //draw pointer temp_rect.x = pointer_x-5; temp_rect.y = pointer_y-5; temp_rect.w = 10; temp_rect.h = 10; SDL_FillRect( screen, &temp_rect, SDL_MapRGB(screen->format,0,0,255)); //deal with the ball bx += bxs; by += bys; //move the ball bys += 2; //planitary gravity bxs *= .97; bys *= .97; //dampen motion if (by > SCREEN_HEIGHT) bys = -bys; //bounce! if (bx < 0) {bxs = abs(bxs) + .1; bx = 1;} if (bx > SCREEN_WIDTH) {bxs = -abs(bxs) - .1; by = SCREEN_WIDTH-1;} //display the "ball" temp_rect.x = bx-5; temp_rect.y = by-5; temp_rect.w = 10; temp_rect.h = 10; SDL_FillRect( screen, &temp_rect, SDL_MapRGB(screen->format,0,255,0)); //repel from pointer dist = sqrt(pow((pointer_x - bx),2) + pow((pointer_y-by),2)); /* Calculate distance */ if (dist < 30) f = -30 / pow(dist,2); //calculate force bxs += f*(pointer_x-bx); /* Influence object in correct direction */ bys += f*(pointer_y-by); if (bxs > s_cap) bxs = s_cap; if (bxs < -s_cap) bxs = -s_cap; if (bys > s_cap) bys = s_cap; if (bys < -s_cap) bys = -s_cap; //make the changes to the screen visable SDL_Flip(screen); //clear screen SDL_FillRect( screen, NULL, SDL_MapRGB(screen->format,0,0,0) ); //test for events { SDL_PumpEvents(); SDL_Event event; while ( SDL_PollEvent(&event) ) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_i: TOGGLE_invert = (TOGGLE_invert + 1) % 2; printf("invert filter = %d\n",TOGGLE_invert); break; case SDLK_t: //toggle sonification on/off TOGGLE_threshold = (TOGGLE_threshold + 1) % 2; printf("threshold filter = %d\n",TOGGLE_threshold); break; case SDLK_MINUS: if ((int) threshold_value - 8 >= 0) threshold_value-=8; printf("threshold value = %d\n", threshold_value); break; case SDLK_EQUALS: //plus key if ((int) threshold_value + 8 <= 255) threshold_value+=8; printf("threshold value = %d\n", threshold_value); break; } break; case SDL_QUIT: exit(0); } } } //END EVENT CODE } }