Paste Description for scale webcam linux
use for scaling webcam video on a linux machine (something I c.ouldn't find an app for)
scale webcam linux
- /*
- * 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 <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <sys/time.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <pwd.h>
- #include <signal.h>
- #include <SDL/SDL.h>
- #include <linux/soundcard.h>
- #include <linux/types.h>
- #include <linux/videodev.h>
- #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;counter<grab_map.frames;counter++)
- fprintf(stderr,"Offset of frame %i: %i\n",counter,grab_map.offsets[counter]);
- return dev;
- }
- int vid_init() {
- int linespace = 5;
- int i;
- /* set image source and TV norm */
- grab_chan.channel = input = (grab_cap.channels>1) ? 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; i++) {
- grab_buf[i].format = palette; //RGB24;
- grab_buf[i].frame = i;
- grab_buf[i].height = vid_geo.h;
- grab_buf[i].width = vid_geo.w;
- }
- if (-1 == ioctl(dev,VIDIOCMCAPTURE,&grab_buf[0])) {
- /*palette=VIDEO_PALETTE_YUV420P;
- for(i=0; i<grab_map.frames; i++) {
- grab_buf[i].format = palette; //RGB24;
- }
- if (-1 == ioctl(dev,VIDIOCMCAPTURE,&grab_buf[0])) {
- fprintf(stderr,"error in ioctl VIDIOCMCAPTURE: %s",strerror(errno));
- }*/
- fprintf(stderr,"error: VIDEO_PALETTE_RGB24 doesn't seem to work");
- }
- grab_data = mmap (0, grab_map.size, PROT_READ | PROT_WRITE, MAP_SHARED, dev, 0);
- if (MAP_FAILED == grab_data) {
- perror ("Cannot allocate video4linux grabber buffer ");
- exit (1); }
- /* feed up the mmapped frames */
- if (-1 == ioctl(dev,VIDIOCMCAPTURE,&grab_buf[0])) {
- fprintf(stderr,"error in ioctl VIDIOCMCAPTURE: %s",strerror(errno));
- }
- cur_frame = ok_frame = 0;
- return dev;
- }
- unsigned char *grab_one () {
- int c = 0, cc=0;
- /* we use just one frame
- no matters about the capability of the cam
- this makes grabbing much faster on my webcam
- i hope also on yours
- ok_frame = cur_frame;
- cur_frame = (cur_frame>=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<vid_geo.size;c++,cc+=3)
- {
- rgb_surface[c*3] = grab_data[grab_map.offsets[ok_frame] + cc + 2]; //red // was 2
- rgb_surface[c*3+1] = grab_data[grab_map.offsets[ok_frame] + cc + 1]; //blue // 1
- rgb_surface[c*3+2] = grab_data[grab_map.offsets[ok_frame] + cc + 0]; //green
- }
- return rgb_surface;
- }
- unsigned char get_red(int x, int y)
- {
- return rgb_surface[(x+y*IMAGE_WIDTH)*3];
- }
- unsigned char get_blue(int x, int y)
- {
- return rgb_surface[(x+y*IMAGE_WIDTH)*3+2];
- }
- unsigned char get_green(int x, int y)
- {
- return rgb_surface[(x+y*IMAGE_WIDTH)*3+1];
- }
- unsigned char get_rd(int x, int y)
- {
- unsigned char r, g, b;
- r = get_red(x,y);
- b = get_blue(x,y);
- g = get_green(x,y);
- return 255 * r / (b + g + r + 1);
- }
- unsigned char thresh(unsigned char i)
- {
- if (i >= 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;
- break;
- case SDLK_t: //toggle sonification on/off
- TOGGLE_threshold = (TOGGLE_threshold + 1) % 2;
- break;
- case SDLK_MINUS:
- if ((int) threshold_value - 8 >= 0) threshold_value-=8;
- break;
- case SDLK_EQUALS: //plus key
- if ((int) threshold_value + 8 <= 255) threshold_value+=8;
- break;
- }
- break;
- case SDL_QUIT:
- exit(0);
- }
- }
- } //END EVENT CODE
- }
- }