在Linux环境下使用C语言实现拍照功能,通常需要借助一些外部库和工具,比如libv4l2
(Video4Linux2)用于访问摄像头设备,以及libjpeg
或libpng
用于图像的编码和保存。以下是一个简单的示例代码,展示了如何使用这些库来捕获并保存图像:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <jpeglib.h>
#define WIDTH 640
#define HEIGHT 480
void save_jpeg(unsigned char *data, int width, int height, const char *filename) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile;
JSAMPROW row_pointer[1];
int row_stride;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
row_stride = width * 3;
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &data[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
}
int main() {
int fd;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
void *buffers[1];
fd_set fds;
struct timeval tv;
int r, i;
fd = open("/dev/video0", O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.height = HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
perror("ioctl VIDIOC_S_FMT");
return 1;
}
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
perror("ioctl VIDIOC_REQBUFS");
return 1;
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
perror("ioctl VIDIOC_QUERYBUF");
return 1;
}
buffers[0] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
if (buffers[0] == MAP_FAILED) {
perror("mmap");
return 1;
}
for (i = 0; i < 4; ++i) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
perror("ioctl VIDIOC_QBUF");
return 1;
}
}
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
perror("ioctl VIDIOC_STREAMON");
return 1;
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
if (r == -1) {
perror("select");
return 1;
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
perror("ioctl VIDIOC_DQBUF");
return 1;
}
save_jpeg(buffers[0], WIDTH, HEIGHT, "output.jpg");
if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
perror("ioctl VIDIOC_STREAMOFF");
return 1;
}
munmap(buffers[0], buf.length);
close(fd);
return 0;
}
确保安装了必要的库:
sudo apt-get install libv4l-dev libjpeg-dev
编译代码:
gcc -o capture capture.c -lv4l2 -ljpeg
运行程序:
./capture
Permission denied
错误,可能需要以root用户运行程序或调整设备文件的权限。Permission denied
错误,可能需要以root用户运行程序或调整设备文件的权限。libv4l2
或libjpeg
,确保已正确安装相关库。通过上述步骤,你应该能够在Linux环境下使用C语言实现基本的拍照功能。
领取专属 10元无门槛券
手把手带您无忧上云