|
@@ -0,0 +1,140 @@
|
|
|
+#include <linux/videodev2.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <sys/mman.h>
|
|
|
+#include <cstring>
|
|
|
+#include <iostream>
|
|
|
+#include <sys/mman.h>
|
|
|
+#include <fcntl.h>
|
|
|
+
|
|
|
+struct shm_data {
|
|
|
+ int width;
|
|
|
+ int height;
|
|
|
+ int format;
|
|
|
+ int size; // 新增:存储实际数据大小
|
|
|
+ char data[0]; // 柔性数组
|
|
|
+};
|
|
|
+
|
|
|
+int main() {
|
|
|
+ // 打开摄像头设备
|
|
|
+ int cam_fd = open("/dev/video0", O_RDWR);
|
|
|
+ if (cam_fd == -1) {
|
|
|
+ perror("open camera failed");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置视频格式(MJPEG)
|
|
|
+ v4l2_format fmt{};
|
|
|
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ fmt.fmt.pix.width = 640;
|
|
|
+ fmt.fmt.pix.height = 480;
|
|
|
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; // 修改为MJPEG格式
|
|
|
+ fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
|
|
+
|
|
|
+ if (ioctl(cam_fd, VIDIOC_S_FMT, &fmt) == -1) {
|
|
|
+ perror("set format failed");
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 请求缓冲区
|
|
|
+ v4l2_requestbuffers req{};
|
|
|
+ req.count = 1;
|
|
|
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ req.memory = V4L2_MEMORY_MMAP;
|
|
|
+
|
|
|
+ if (ioctl(cam_fd, VIDIOC_REQBUFS, &req) == -1) {
|
|
|
+ perror("request buffers failed");
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询并映射缓冲区
|
|
|
+ v4l2_buffer buf{};
|
|
|
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ buf.memory = V4L2_MEMORY_MMAP;
|
|
|
+ buf.index = 0;
|
|
|
+
|
|
|
+ if (ioctl(cam_fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
|
|
+ perror("query buffer failed");
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ void* cam_buffer = mmap(nullptr, buf.length, PROT_READ | PROT_WRITE,
|
|
|
+ MAP_SHARED, cam_fd, buf.m.offset);
|
|
|
+ if (cam_buffer == MAP_FAILED) {
|
|
|
+ perror("mmap camera buffer failed");
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建共享内存
|
|
|
+ int shm_fd = shm_open("/camera_shm", O_CREAT | O_RDWR, 0666);
|
|
|
+ if (shm_fd == -1) {
|
|
|
+ perror("shm_open failed");
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算共享内存大小(缓冲区长度+元数据)
|
|
|
+ size_t shm_size = sizeof(shm_data) + buf.length; // 使用实际缓冲区长度
|
|
|
+
|
|
|
+ if (ftruncate(shm_fd, shm_size) == -1) {
|
|
|
+ perror("ftruncate failed");
|
|
|
+ close(shm_fd);
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 映射共享内存
|
|
|
+ shm_data* shared_data = static_cast<shm_data*>(
|
|
|
+ mmap(nullptr, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));
|
|
|
+ if (shared_data == MAP_FAILED) {
|
|
|
+ perror("mmap shared memory failed");
|
|
|
+ close(shm_fd);
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化共享数据
|
|
|
+ shared_data->width = fmt.fmt.pix.width;
|
|
|
+ shared_data->height = fmt.fmt.pix.height;
|
|
|
+ shared_data->format = fmt.fmt.pix.pixelformat;
|
|
|
+
|
|
|
+ // 开始捕获
|
|
|
+ if (ioctl(cam_fd, VIDIOC_STREAMON, &buf.type) == -1) {
|
|
|
+ perror("start stream failed");
|
|
|
+ close(shm_fd);
|
|
|
+ close(cam_fd);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 捕获循环
|
|
|
+ while (true) {
|
|
|
+ if (ioctl(cam_fd, VIDIOC_QBUF, &buf) == -1) {
|
|
|
+ perror("queue buffer failed");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ioctl(cam_fd, VIDIOC_DQBUF, &buf) == -1) {
|
|
|
+ perror("dequeue buffer failed");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 复制数据到共享内存(带实际数据大小)
|
|
|
+ memcpy(shared_data->data, cam_buffer, buf.bytesused);
|
|
|
+ shared_data->size = buf.bytesused; // 记录实际数据大小
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理资源
|
|
|
+ ioctl(cam_fd, VIDIOC_STREAMOFF, &buf.type);
|
|
|
+ munmap(cam_buffer, buf.length);
|
|
|
+ munmap(shared_data, shm_size);
|
|
|
+ close(cam_fd);
|
|
|
+ close(shm_fd);
|
|
|
+ shm_unlink("/camera_shm");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|