📄 vidcat.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>
#ifdef HAVE_LIBZ
#include <zlib.h>
#endif
#ifdef HAVE_LIBPNG
#include <png.h>
#endif
#ifdef HAVE_LIBJPEG
#include <jpeglib.h>
#endif
#include "v4l.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 QUAL_DEFAULT 80
char *basename (const char *s);
/* globals
*/
static int verbose = 0;
/*
*/
void
usage (char *pname)
{
fprintf (stderr,
"VidCat, Version %s\n"
"Usage: %s <options>\n"
" -b make a raw PPM instead of an ASCII one\n"
" -d <device> video device (default: "VIDEO_DEV")\n"
" -f {ppm|jpeg|png|yuv4mpeg} output format of the image\n"
" -g greayscale instead of color\n"
" -i {tv|comp1|comp2|s-video} which input channel to use\n"
" -l loop on, doesn't make sense in most cases\n"
" -n {pal|ntsc|secam} select video norm\n"
" -o <file> write output to file instead of stdout\n"
" -p c|g|y|Y videopalette to use\n"
" -q <quality> only for jpeg: quality setting (1-100,"
" default: %d)\n"
" -s NxN define size of the output image (default:"
" %dx%d)\n"
"Example: vidcat | xsetbg stdin\n",
VERSION, (char*)basename(pname), QUAL_DEFAULT, DEF_WIDTH, DEF_HEIGHT);
exit (1);
}
/*
*/
double
ms_time (void)
{
static struct timeval tod;
gettimeofday (&tod, NULL);
return ((double)tod.tv_sec * 1000.0 + (double)tod.tv_usec / 1000.0);
}
/*
* read rgb image from v4l device 从v4l设备获取rgb图像
* 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, *convmap; //map指向抓到的图片所存空间
int len;
int bytes = 3; //比特每像素
if (palette == VIDEO_PALETTE_GREY) //若为灰度图象
bytes = 1; /* bytes per pixel */
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)"); //ioctl函数功能??
return (NULL);
}
}
map = malloc (width * height * bytes); //分配空间
len = read (dev, map, width * height * bytes); //从v41设备读取图像信息到map所指向的空间
if (len <= 0) {
free (map);
return (NULL);
}
*size = 0;
if (palette == VIDEO_PALETTE_YUV420P) {
convmap = malloc ( width * height * bytes );
v4l_yuv420p2rgb (convmap, map, width, height, bytes * 8);//颜色空间的转换
memcpy (map, convmap, (size_t) width * height * bytes); //将convmap指向的图像的值复制
//到map指向的一段连续的空间
free (convmap);
} else if (palette == VIDEO_PALETTE_YUV422P) {
convmap = malloc ( width * height * bytes );
v4l_yuv422p2rgb (convmap, map, width, height, bytes * 8);
memcpy (map, convmap, (size_t) width * height * bytes);
free (convmap);
}
return (map); //返回map,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 (palette == VIDEO_PALETTE_YUV420P) {
if (verbose)
fprintf (stderr, "converting from YUV to RGB\n");
convmap = malloc ( width * height * bytes );
v4l_yuv420p2rgb (convmap, map, width, height, bytes * 8);
memcpy (map, convmap, (size_t) width * height * bytes);
free (convmap);
} else if (palette == VIDEO_PALETTE_YUV422P) {
if (verbose)
fprintf (stderr, "converting from YUV to RGB\n");
convmap = malloc ( width * height * bytes );
v4l_yuv422p2rgb (convmap, map, width, height, bytes * 8);
memcpy (map, convmap, (size_t) width * height * bytes);
free (convmap);
}
return (map);
if (verbose)
fprintf (stderr, "got picture\n");
}
/*将get_image函数抓到的图片压缩成不同的格式
*/
void
put_image_jpeg (FILE *out, char *image, int width, int height, int quality, int palette)
{
#ifdef HAVE_LIBJPEG
int y, x, line_width;
JSAMPROW row_ptr[1];
struct jpeg_compress_struct cjpeg;
struct jpeg_error_mgr jerr;
char *line;
line = malloc (width * 3);
if (!line)
return;
if (verbose)
fprintf (stderr, "writing JPEG data\n");
cjpeg.err = jpeg_std_error(&jerr);
jpeg_create_compress (&cjpeg); //创建jpge压缩结构体
cjpeg.image_width = width;
cjpeg.image_height= height;
if (palette == VIDEO_PALETTE_GREY) {
cjpeg.input_components = 1; //若为灰度图象,每像素一个bit
cjpeg.in_color_space = JCS_GRAYSCALE;
// jpeg_set_colorspace (&cjpeg, JCS_GRAYSCALE);
} else {
cjpeg.input_components = 3; //若不是灰度图象,每像素3个bit
cjpeg.in_color_space = JCS_RGB; //rgb的颜色空间
}
jpeg_set_defaults (&cjpeg);
jpeg_set_quality (&cjpeg, quality, TRUE);
cjpeg.dct_method = JDCT_FASTEST;
jpeg_stdio_dest (&cjpeg, out);
jpeg_start_compress (&cjpeg, TRUE);
row_ptr[0] = line;
if (palette == VIDEO_PALETTE_GREY) {
line_width = width;
for ( y = 0; y < height; y++) {
row_ptr[0] = image;
jpeg_write_scanlines (&cjpeg, row_ptr, 1);
image += line_width;
}
} else {
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);
#endif
}
/*
* write png image to stdout
*/
void
put_image_png (FILE *out, char *image, int width, int height, int palette)
{
#ifdef HAVE_LIBPNG
int y, bpp;
char *p;
png_infop info_ptr;
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!png_ptr)
return;
info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
return;
png_init_io (png_ptr, out);
if (palette == VIDEO_PALETTE_GREY) {
png_set_IHDR (png_ptr, info_ptr, width, height,
8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
bpp = 1;
} else {
png_set_IHDR (png_ptr, info_ptr, width, height,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
bpp = 3;
}
png_set_bgr (png_ptr);
png_write_info (png_ptr, info_ptr);
p = image;
for (y = 0; y < height; y++) {
png_write_row (png_ptr, p);
p += width * bpp;
}
png_write_end (png_ptr, info_ptr);
#endif
}
/*
* 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -