📄 camsnap.c
字号:
/*
* camsnap.c
*/
#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 <sys/time.h> /* gettimeofday() */
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/videodev.h>
#define def_width 320 /* default width */
#define def_height 240 /* default height */
#define fmt_unknown 0
#define fmt_ppm 1
#define fmt_pgm 2
#define fmt_png 3
#define fmt_jpeg 4
#define fmt_yuv4mpeg 5
#define in_tv 0
#define in_composite 1
#define in_composite2 2
#define in_svideo 3
#define norm_pal 0
#define norm_ntsc 1
#define norm_secam 2
#define input_default -1
#define norm_default -1
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
char *basename (const char *s);
/* globals
*/
static int verbose = 0;
/*
*/
void
usage (char *pname)
{
fprintf (stderr,
"vidcat, version %s\n"
"usage: %s <options>\n"
" -d <device> video device (default: "video_dev")\n"
" -o <file> write output to file instead of stdout\n"
" -s nxn define size of the output image (default:"
" %dx%d)\n"
"example: vidcat | xsetbg stdin\n",
version, (char*)basename(pname), def_width, def_height);
exit (1);
}
/*
* set the input and norm for the video4linux device
*/
int
v4l_set_input (int fd, int input, int norm)
{
struct video_channel vid_chnl;
if (input != input_default || norm != norm_default) {
if (vid_chnl.channel != input_default)
vid_chnl.channel = input;
else
vid_chnl.channel = 0;
vid_chnl.norm = -1;
if (ioctl (fd, vidiocgchan, &vid_chnl) == -1) {
perror ("ioctl (vidiocgchan)");
return -1;
} else {
if (input != 0)
vid_chnl.channel = input;
if (norm != norm_default)
vid_chnl.norm = norm;
if (ioctl (fd, vidiocschan, &vid_chnl) == -1) {
perror ("ioctl (vidiocschan)");
return -1;
}
}
}
return 0;
}
/*
* check the size and readjust if necessary
*/
int
v4l_check_size (int fd, int *width, int *height)
{
struct video_capability vid_caps;
if (ioctl (fd, vidiocgcap, &vid_caps) == -1) {
perror ("ioctl (vidiocgcap)");
return -1;
}
/* readjust if necessary */
if (*width > vid_caps.maxwidth || *width < vid_caps.minwidth) {
*width = min (*width, vid_caps.maxwidth);
*width = max (*width, vid_caps.minwidth);
fprintf (stderr, "readjusting width to %d\n", *width);
}
if (*height > vid_caps.maxheight || *height < vid_caps.minheight) {
*height = min (*height, vid_caps.maxheight);
*height = max (*height, vid_caps.minheight);
fprintf (stderr, "readjusting height to %d\n", *height);
}
return 0;
}
/*
* read rgb image from v4l device
* return: mmap'ed buffer and size
*/
char *
get_image (int dev, int width, int height, int palette ,int *size)
{
struct video_mbuf vid_buf;
struct video_mmap vid_mmap;
char *map;
int len;
int bytes = 3;
if (ioctl (dev, vidiocgmbuf, &vid_buf) == -1) {
/* to do a normal read()
*/
struct video_window vid_win;
if (verbose) {
fprintf (stderr, "using read()\n");
}
if (ioctl (dev, vidiocgwin, &vid_win) != -1) {
vid_win.width = width;
vid_win.height = height;
if (ioctl (dev, vidiocswin, &vid_win) == -1) {
perror ("ioctl(vidiocswin)");
return (null);
}
}
map = malloc (width * height * bytes);
len = read (dev, map, width * height * bytes);
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 = palette;
vid_mmap.frame = 0;
vid_mmap.width = width;
vid_mmap.height = height;
if (ioctl (dev, vidiocmcapture, &vid_mmap) == -1) {
perror ("vidiocmcapture");
fprintf (stderr, "args: width=%d height=%d palette=%d\n",
vid_mmap.width, vid_mmap.height, vid_mmap.format);
munmap (map, vid_buf.size);
return (null);
}
if (ioctl (dev, vidiocsync, &vid_mmap.frame) == -1) {
perror ("vidiocsync");
munmap (map, vid_buf.size);
return (null);
}
*size = vid_buf.size;
if (verbose)
fprintf (stderr, "got picture\n");
return (map);
}
/*
* write ppm image to stdout / file
*/
void
put_image_ppm (file *out, char *image, int width, int height, int binary)
{
int x, y, ls=0;
unsigned char *p = (unsigned char *)image;
if (!binary) {
fprintf (out, "p3\n%d %d\n%d\n", width, height, 255);
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
fprintf (out, "%03d %03d %03d ", p[2], p[1], p[0]);
p += 3;
if (ls++ > 4) {
fprintf (out, "\n");
ls = 0;
}
}
}
fprintf (out, "\n");
} else {
unsigned char buff[3];
fprintf (out, "p6\n%d %d\n%d\n", width, height, 255);
for (x = 0; x < width * height; x++) {
buff[0] = p[2];
buff[1] = p[1];
buff[2] = p[0];
fwrite (buff, 1, 3, out);
p += 3;
}
}
fflush (out);
}
/*
* main()
*/
int
main (int argc, char *argv[])
{
int width = def_width, height = def_height, size, dev = -1, c;
char *image, *device = video_dev, *file = null;
int max_try = 5; /* we try 5 seconds/times to open the device */
// int quality = qual_default; /* default jpeg quality setting */
int input = input_default; /* this means take over current device settings*/
int norm = norm_default;
int palette = video_palette_rgb24;
file *out = stdout;
int format = fmt_ppm;
while ((c = getopt (argc, argv, "d:o:s:vv")) != eof) {
switch (c) {
case 'd': /* change default device */
device = optarg;
break;
case 'o':
file = optarg;
break;
case 's':
sscanf (optarg, "%dx%d", &width, &height);
break;
case 'v':
verbose++;
break;
case 'v':
printf ("vidcat, version %s\n", version);
exit (0);
break;
default:
usage (argv[0]);
break;
}
}
if (verbose) {
fprintf (stderr, "input palette: %s\n", "rgb" );
fprintf (stderr, "size: %dx%d\n", width, height);
}
if (file) {
out = fopen (file, "wb");
if (!out) {
perror (file);
return 1;
}
}
/* open the video4linux device */
while (max_try) {
dev = open (device, o_rdwr);
if (dev == -1) {
if (!--max_try) {
fprintf (stderr, "can't open device %s\n", device);
return (1);
}
sleep (1);
} else { break; }
}
if (v4l_set_input (dev, input, norm) == -1) {
return (1);
}
if (v4l_check_size (dev, &width, &height) == -1) {
return (1);
}
image = get_image (dev, width, height, palette, &size);
if (!size)
close (dev);
if (image) {
switch (format) {
case fmt_ppm:
put_image_ppm (out, image, width, height, 0);
break;
default:
fprintf (stderr, "unknown format (%d)\n", format);
break;
}
if (size) {
munmap (image, size);
close (dev);
} else if (image) {
free (image);
}
} else {
fprintf (stderr, "error: can't get image\n");
}
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -