dockapps/wmwebcam/wmwebcam.c
2017-02-21 11:15:02 +00:00

362 lines
9.2 KiB
C

/* wmwebcam - modified vidcat - read the README file for more info */
/*
* vidcat.c
*
* Copyright (C) 1998 - 2000 Rasca, Berlin
* EMail: thron@gmx.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <jpeglib.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include "wmwebcam-mask.xbm"
#include "minirgb.h"
//////////////////////// CHANGE THESE IF NECESSARY ///////////////////////////
#define DEF_WIDTH 352 // changing these requires adjustements
#define DEF_HEIGHT 288 // to the source, use default if possible
#define SENDINGDELAY 60 // default delay between saving jpeg
// images and scriptrunning (in seconds)
#define OUTPUTFILE "/tmp/wmwebcam.jpg" // default output file
#define CUSTOMSCRIPT "wmwebcam.pl" // default custom script
#define QUAL_DEFAULT 100 // default jpeg outputquality
//////////////////////////////////////////////////////////////////////////////
char *basename (const char *s);
Display *display;
Window win;
Window iconwin;
GC gc;
MiniRGB ui; /* 64x64 main window buffer */
MiniRGB draw; /* buffer with images etc */
void new_window(char *name, char *mask_data)
{
Pixel fg, bg;
XGCValues gcval;
XSizeHints sizehints;
XClassHint classhint;
XWMHints wmhints;
int screen;
Window root;
Pixmap mask;
screen = DefaultScreen(display);
root = DefaultRootWindow(display);
sizehints.flags = USSize;
sizehints.width = 64;
sizehints.height = 64;
fg = BlackPixel(display, screen);
bg = WhitePixel(display, screen);
win = XCreateSimpleWindow(display, root,
0, 0, sizehints.width,
sizehints.height, 1, fg, bg);
iconwin =
XCreateSimpleWindow(display, win, 0, 0,
sizehints.width, sizehints.height, 1, fg, bg);
XSetWMNormalHints(display, win, &sizehints);
classhint.res_name = name;
classhint.res_class = name;
XSetClassHint(display, win, &classhint);
XSelectInput(display, win,
ExposureMask | ButtonPressMask | ButtonReleaseMask |
StructureNotifyMask);
XSelectInput(display, iconwin,
ExposureMask | ButtonPressMask | ButtonReleaseMask |
StructureNotifyMask);
XStoreName(display, win, name);
XSetIconName(display, win, name);
gcval.foreground = fg;
gcval.background = bg;
gcval.graphics_exposures = False;
gc =
XCreateGC(display, win,
GCForeground | GCBackground | GCGraphicsExposures,
&gcval);
mask = XCreateBitmapFromData(display, win, mask_data, 128, 64);
XShapeCombineMask(display, win, ShapeBounding, 0, 0,
mask, ShapeSet);
XShapeCombineMask(display, iconwin, ShapeBounding, 0,
0, mask, ShapeSet);
wmhints.initial_state = WithdrawnState;
wmhints.flags = StateHint;
wmhints.icon_window = iconwin;
wmhints.icon_x = sizehints.x;
wmhints.icon_y = sizehints.y;
wmhints.window_group = win;
wmhints.flags =
StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
XSetWMHints(display, win, &wmhints);
XMapWindow(display, win);
}
void redraw_window(void)
{
minirgb_draw(win, gc, 0, 0, 64, 64, &ui);
minirgb_draw(iconwin, gc, 0, 0, 64, 64, &ui);
}
#define copyXPMArea(x, y, w, h, dx, dy) minirgb_copy(&draw, &ui, x, y, w, h, dx, dy)
char *
get_image (int dev, int width, int height,int *size)
{
struct video_capability vid_caps;
struct video_mbuf vid_buf;
struct video_mmap vid_mmap;
char *map;
int len;
if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
perror ("ioctl (VIDIOCGCAP)");
return (NULL);
}
if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) {
struct video_window vid_win;
if (ioctl (dev, VIDIOCGWIN, &vid_win) != -1) {
vid_win.width = width;
vid_win.height = height;
if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1)
return (NULL);
}
map = malloc (width * height * 3);
len = read (dev, map, width * height * 3);
if (len <= 0) { free (map); return (NULL); }
*size = 0;
return (map);
}
map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0);
if ((unsigned char *)-1 == (unsigned char *)map) {
perror ("mmap()");
return (NULL);
}
vid_mmap.format = VIDEO_PALETTE_RGB24;
vid_mmap.frame = 0;
vid_mmap.width = width;
vid_mmap.height = height;
if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) {
perror ("VIDIOCMCAPTURE");
munmap (map, vid_buf.size);
return (NULL);
}
if (ioctl (dev, VIDIOCSYNC, &vid_mmap) == -1) {
perror ("VIDIOCSYNC");
munmap (map, vid_buf.size);
return (NULL);
}
*size = vid_buf.size;
return (map);
}
void
put_image_jpeg (char *image, int width, int height, int quality)
{
FILE *output;
int y, x, line_width;
JSAMPROW row_ptr[1];
struct jpeg_compress_struct cjpeg;
struct jpeg_error_mgr jerr;
char *line;
output = fopen("/tmp/wmwebcam.jpg","w");
if(!output) return;
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, output);
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);
fclose (output);
}
void
put_image (char *image, int width, int height)
{
int x, y, r,g,b, c;
unsigned char *p = (unsigned char *)image;
unsigned char *buf = (unsigned char *)image;
for (y = 0; y < 288; y++ ) {
c=0;
for (x = 0; x < 348; x++ ) {
r = buf[0]; g = buf[1]; b = buf[2]; buf += 3;
c++;
if (c == 6) {
c = 0;
*p++ = b; *p++ = g; *p++ = r;
}
}
}
memcpy(draw.mem, image, 352*288*3);
}
int
main (int argc, char *argv[])
{
XEvent Event;
char *image, *device = VIDEO_DEV;
int delay = SENDINGDELAY;
int width = DEF_WIDTH, height = DEF_HEIGHT, size, dev = -1;
int max_try = 5;
int quality = QUAL_DEFAULT;
display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Unable to open default display\n");
exit(1);
}
if (minirgb_init(display)) {
fprintf(stderr, "minirgb init failed!\n");
exit(1);
}
new_window("wmwebcam", wmwebcam_mask_bits);
minirgb_new(&ui, 64, 64);
minirgb_new(&draw, 352, 288);
copyXPMArea(0, 0, 64, 64, 0, 0);
while (1) {
while (max_try) {
dev = open (device, O_RDWR);
if (dev == -1) {
if (!--max_try) {
fprintf (stderr, "Can't open device %s\n", VIDEO_DEV);
exit (0);
}
sleep (1);
} else {
break;
}
}
image = get_image (dev, width, height, &size);
if (!size) close (dev);
if (image) {
if (delay == SENDINGDELAY) { put_image_jpeg(image, width, height, quality); }
put_image(image, width, height);
copyXPMArea(1, 1, 54, 47, 5, 5);
while (XPending(display)) {
XNextEvent(display, &Event);
switch (Event.type) {
case Expose:
redraw_window();
break;
case DestroyNotify:
XCloseDisplay(display);
exit(0);
break;
}
}
redraw_window();
if (size) {
munmap (image, size);
close (dev);
} else if (image) {
free (image);
}
// close device first before starting to send the image
if (delay == SENDINGDELAY) { system (CUSTOMSCRIPT); delay = 0; }
delay++;
sleep (1);
} else {
fprintf (stderr, "Error: Can't get image\n"); exit(0);
}
}
return (0);
}