⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vidcat.c

📁 此程序是一个通用的摄像头抓图程序
💻 C
📖 第 1 页 / 共 2 页
字号:

#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 + -