野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 262|回复: 4

[求助] OV8858

[复制链接]
发表于 2024-4-7 14:25:17 | 显示全部楼层 |阅读模式
本帖最后由 MUCHWAY 于 2024-4-8 09:32 编辑

Lubancat 1IO使用VO8858摄像头,按照野火说明资料里面的说明:鲁班猫摄像头使用,可以正常使用摄像头,保存图片和保存视频都没有问题。


但是我现在想在我的应用程序中使用V4L2提供的API调用摄像头,参照网上的教程:手把手教你使用linux摄像头(V4L2框架)进行设置:
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>

  7. #include <sys/ioctl.h>
  8. #include <linux/videodev2.h>

  9. int main(void)
  10. {
  11.     int fd = open("/dev/video0",O_RDWR);
  12.     if (fd < 0)
  13.     {
  14.         perror("打开设备失败");
  15.         return -1;
  16.     }

  17.     //获取摄像头支持格式 ioctl(文件描述符,命令,与命令对应的结构体)
  18.     struct v4l2_fmtdesc vfmt;
  19.     vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集

  20.     int i = 0;
  21.     while(1)         //使用while循环从0开始测试index索引值
  22.     {
  23.         vfmt.index = i;
  24.         i++;
  25.         int ret = ioctl(fd,VIDIOC_ENUM_FMT,&vfmt);
  26.         if (ret < 0)
  27.         {
  28.             perror("获取失败");
  29.             break;
  30.         }
  31.         printf("index=%d\n",vfmt.index);
  32.         printf("flags=%d\n",vfmt.flags);
  33.         printf("discription=%s\n",vfmt.description);
  34.         unsigned char *p = (unsigned char *)&vfmt.pixelformat;
  35.         printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
  36.         printf("reserved=%d\n",vfmt.reserved[0]);
  37.     }
  38.     close(fd);
  39.     return 0;
  40. }
复制代码
执行这段代码,总有报错:获取失败: Invalid argument
并且我参考这个链接:Linux-使用V4L2,这其其中凡是涉及用ioctl函数去设置摄像头的地方,都有 Invalid argument的报错。
而我换成一个USB免驱摄像头,做上面的同样试验,则完全没有问题。
还请教一下懂的大佬指点一下,或者有没有可以参考的例程学习一下。
回复

使用道具 举报

发表于 2024-4-7 22:34:44 | 显示全部楼层
不是"/dev/video0 ?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-8 09:30:33 | 显示全部楼层
本帖最后由 MUCHWAY 于 2024-4-8 09:31 编辑

是dev/video0的,代码也改了的,只是这里贴的代码是video1,用v4l2-ctl命令行可以正常使用的,就是写应用程序就不行,
回复 支持 反对

使用道具 举报

发表于 2024-4-15 17:45:47 | 显示全部楼层
我也在弄这个,刚拿到手,资料翻了个遍,就是没找到官方例子,你搞定了吗,只要读取数据,设置参数
回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
鲁班猫的例程是比t-firefly要少,贴下我的代码,直接从摄像头取数据刷屏fb0和保存nv12的。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/time.h>
  9. #include <sys/mman.h>
  10. #include <sys/ioctl.h>
  11. #include <asm/types.h>
  12. #include <linux/videodev2.h>
  13. #include <linux/v4l2-subdev.h>

  14. #define FMT_NUM_PLANES 1

  15. struct buffer
  16. {
  17.     void *start;
  18.     size_t length;
  19. };

  20. struct v4l2_dev
  21. {
  22.     int fd;
  23.     int sub_fd;
  24.     const char *path;
  25.     const char *name;
  26.     const char *subdev_path;
  27.     const char *out_type;
  28.     enum v4l2_buf_type buf_type;
  29.     int format;
  30.     int width;
  31.     int height;
  32.     unsigned int req_count;
  33.     enum v4l2_memory memory_type;
  34.     struct buffer *buffers;
  35.     unsigned long int timestamp;
  36.     int data_len;
  37.     unsigned char *out_data;
  38. };

  39. struct v4l2_dev ov8858 = {
  40.     .fd = -1,
  41.     .sub_fd = -1,
  42.     .path = "/dev/video0",
  43.     .name = "ov8858",
  44.     .subdev_path = "/dev/v4l-subdev3",
  45.     .out_type = "nv12",
  46.     .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
  47.     .format = V4L2_PIX_FMT_NV12,
  48.     .width = 1024,
  49.     .height = 800,
  50.     .req_count = 3,
  51.     .memory_type = V4L2_MEMORY_MMAP,
  52.     .buffers = NULL,
  53.     .timestamp = 0,
  54.     .data_len = 0,
  55.     .out_data = NULL,
  56. };


  57. void close_device(struct v4l2_dev *dev)
  58. {
  59.     if (dev->buffers) {
  60.         for (unsigned int i = 0; i < dev->req_count; ++i) {
  61.             if (dev->buffers[i].start) {
  62.                 munmap(dev->buffers[i].start, dev->buffers[i].length);
  63.             }
  64.         }
  65.         free(dev->buffers);
  66.     }
  67.     if (-1 != dev->fd) {
  68.         close(dev->fd);
  69.     }
  70.     if (-1 != dev->sub_fd) {
  71.         close(dev->sub_fd);
  72.     }
  73.     return;
  74. }

  75. void exit_failure(struct v4l2_dev *dev)
  76. {
  77.     close_device(dev);
  78.     exit(EXIT_FAILURE);
  79. }

  80. void open_device(struct v4l2_dev *dev)
  81. {
  82.     dev->fd = open(dev->path, O_RDWR | O_CLOEXEC, 0);
  83.     if (dev->fd < 0) {
  84.         printf("Cannot open %s\n\n", dev->path);
  85.         exit_failure(dev);
  86.     }
  87.     printf("Open %s succeed - %d\n\n", dev->path, dev->fd);

  88.     dev->sub_fd = open(dev->subdev_path, O_RDWR|O_CLOEXEC, 0);
  89.     if (dev->sub_fd < 0) {
  90.         printf("Cannot open %s\n\n", dev->subdev_path);
  91.         exit_failure(dev);
  92.     }
  93.     printf("Open %s succeed\n\n", dev->subdev_path);
  94.     return;
  95. }

  96. void get_capabilities(struct v4l2_dev *dev)
  97. {
  98.     struct v4l2_capability cap;
  99.     if (ioctl(dev->fd, VIDIOC_QUERYCAP, &cap) < 0) {
  100.         printf("VIDIOC_QUERYCAP failed\n");
  101.         return;
  102.     }
  103.     printf("------- VIDIOC_QUERYCAP ----\n");
  104.     printf("  driver: %s\n", cap.driver);
  105.     printf("  card: %s\n", cap.card);
  106.     printf("  bus_info: %s\n", cap.bus_info);
  107.     printf("  version: %d.%d.%d\n",
  108.            (cap.version >> 16) & 0xff,
  109.            (cap.version >> 8) & 0xff,
  110.            (cap.version & 0xff));
  111.     printf("  capabilities: %08X\n", cap.capabilities);

  112.     if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
  113.         printf("        Video Capture\n");
  114.     if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
  115.         printf("        Video Output\n");
  116.     if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
  117.         printf("        Video Overly\n");
  118.     if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
  119.         printf("        Video Capture Mplane\n");
  120.     if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
  121.         printf("        Video Output Mplane\n");
  122.     if (cap.capabilities & V4L2_CAP_READWRITE)
  123.         printf("        Read / Write\n");
  124.     if (cap.capabilities & V4L2_CAP_STREAMING)
  125.         printf("        Streaming\n");
  126.     printf("\n");
  127.     return;
  128. }



  129. void set_fmt(struct v4l2_dev *dev)
  130. {
  131.     struct v4l2_format fmt;
  132.     memset(&fmt, 0, sizeof(fmt));
  133.     fmt.type = dev->buf_type;
  134.     fmt.fmt.pix.pixelformat = dev->format;
  135.     fmt.fmt.pix.width = dev->width;
  136.     fmt.fmt.pix.height = dev->height;
  137.     if (ioctl(dev->fd, VIDIOC_S_FMT, &fmt) < 0) {
  138.         printf("VIDIOC_S_FMT failed - [%d]!\n", errno);
  139.         exit_failure(dev);
  140.     }
  141.     printf("VIDIOC_S_FMT succeed!\n");
  142.     dev->data_len = fmt.fmt.pix.sizeimage;
  143.     printf("width %d, height %d, size %d, bytesperline %d, format %c%c%c%c\n\n",
  144.            fmt.fmt.pix.width, fmt.fmt.pix.height, dev->data_len,
  145.            fmt.fmt.pix.bytesperline,
  146.            fmt.fmt.pix.pixelformat & 0xFF,
  147.            (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
  148.            (fmt.fmt.pix.pixelformat >> 16) & 0xFF,
  149.            (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
  150.     return;
  151. }



  152. void require_buf(struct v4l2_dev *dev)
  153. {
  154.     // 申请缓冲区
  155.     struct v4l2_requestbuffers req;
  156.     memset(&req, 0, sizeof(req));
  157.     req.count = dev->req_count;
  158.     req.type = dev->buf_type;
  159.     req.memory = dev->memory_type;
  160.     if (ioctl(dev->fd, VIDIOC_REQBUFS, &req) == -1) {
  161.         printf("VIDIOC_REQBUFS failed!\n\n");
  162.         exit_failure(dev);
  163.     }
  164.     if (dev->req_count != req.count) {
  165.         printf("!!! req count = %d\n", req.count);
  166.         dev->req_count = req.count;
  167.     }
  168.     printf("VIDIOC_REQBUFS succeed!\n\n");
  169.     return;
  170. }

  171. void alloc_buf(struct v4l2_dev *dev)
  172. {
  173.     dev->buffers = (struct buffer *)calloc(dev->req_count, sizeof(*(dev->buffers)));
  174.     for (unsigned int i = 0; i < dev->req_count; ++i) {
  175.         struct v4l2_buffer buf;
  176.         struct v4l2_plane planes[FMT_NUM_PLANES];
  177.         memset(&buf, 0, sizeof(buf));
  178.         memset(&planes, 0, sizeof(planes));
  179.         buf.type = dev->buf_type;
  180.         buf.memory = dev->memory_type;
  181.         buf.index = i;

  182.         if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
  183.             buf.m.planes = planes;
  184.             buf.length = FMT_NUM_PLANES;
  185.         }

  186.         if (ioctl(dev->fd, VIDIOC_QUERYBUF, &buf) == -1) {
  187.             printf("VIDIOC_QUERYBUF failed!\n\n");
  188.             exit_failure(dev);
  189.         }
  190.         if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
  191.             dev->buffers[i].length = buf.m.planes[0].length;
  192.             dev->buffers[i].start =
  193.                 mmap(NULL /* start anywhere */,
  194.                      buf.m.planes[0].length,
  195.                      PROT_READ | PROT_WRITE /* required */,
  196.                      MAP_SHARED /* recommended */,
  197.                      dev->fd, buf.m.planes[0].m.mem_offset);
  198.         } else {
  199.             dev->buffers[i].length = buf.length;
  200.             dev->buffers[i].start = mmap(NULL,
  201.                                          buf.length,
  202.                                          PROT_READ | PROT_WRITE,
  203.                                          MAP_SHARED,
  204.                                          dev->fd,
  205.                                          buf.m.offset);
  206.         }

  207.         if (dev->buffers[i].start == MAP_FAILED) {
  208.             printf("Memory map failed!\n\n");
  209.             exit_failure(dev);
  210.         }
  211.     }
  212.     printf("Memory map succeed!\n\n");
  213.     return;
  214. }

  215. void queue_buf(struct v4l2_dev *dev)
  216. {
  217.     for (unsigned int i = 0; i < dev->req_count; ++i) {
  218.         struct v4l2_buffer buf;
  219.         struct v4l2_plane planes[FMT_NUM_PLANES];
  220.         memset(&buf, 0, sizeof(buf));
  221.         memset(&planes, 0, sizeof(planes));
  222.         buf.type = dev->buf_type;
  223.         buf.memory = dev->memory_type;
  224.         buf.index = i;

  225.         if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
  226.             buf.m.planes = planes;
  227.             buf.length = FMT_NUM_PLANES;
  228.         }

  229.         if (ioctl(dev->fd, VIDIOC_QBUF, &buf) < 0) {
  230.             printf("VIDIOC_QBUF failed!\n\n");
  231.             exit_failure(dev);
  232.         }
  233.     }
  234.     printf("VIDIOC_QBUF succeed!\n\n");
  235.     return;
  236. }

  237. void stream_on(struct v4l2_dev *dev)
  238. {
  239.     enum v4l2_buf_type type = dev->buf_type;
  240.     if (ioctl(dev->fd, VIDIOC_STREAMON, &type) == -1) {
  241.         printf("VIDIOC_STREAMON failed!\n\n");
  242.         exit_failure(dev);
  243.     }
  244.     printf("VIDIOC_STREAMON succeed!\n\n");
  245.     return;
  246. }

  247. int64_t get_ts_us( void )
  248. {
  249. #if HAVE_CLOCK_GETTIME
  250.         struct timespec ts;
  251.         clock_gettime( CLOCK_REALTIME, &ts );
  252.         return (int64_t)ts.tv_sec * 1000000 + (int64_t)ts.tv_nsec / 1000;
  253. #else
  254.         struct timeval tv_date;
  255.         gettimeofday( &tv_date, NULL );
  256.         return (int64_t)tv_date.tv_sec * 1000000 + (int64_t)tv_date.tv_usec;
  257. #endif
  258. }
  259. #include <linux/fb.h>
  260. void NV12ToRGB(unsigned char *nv12, unsigned int *rgb, int width, int height) {
  261.     int size = width * height;
  262.     int w, h, x, y, u, v, yIndex, uvIndex;
  263.     int y1192, r, g, b, uv448, uv_128, rgb_idx;
  264. rgb_idx = 0;
  265.     for (h = 0; h < height; h++) {
  266.         for (w = 0; w < width; w++) {
  267.             yIndex = h * width + w;
  268.             uvIndex = (h / 2) * width + (w & (-2)) + size;
  269.             u = nv12[uvIndex];
  270.             v = nv12[uvIndex + 1];

  271.             // YUV to RGB
  272.             y1192 = 1192 * (nv12[yIndex] - 16);
  273.             uv448 = 448 * (u - 128);
  274.             uv_128 = 128 * (v - 128);
  275.             r = (y1192 + uv448) >> 10;
  276.             g = (y1192 - uv_128 - uv448) >> 10;
  277.             b = (y1192 + uv_128) >> 10;

  278.             // RGB clipping
  279.             if (r < 0) r = 0;
  280.             if (g < 0) g = 0;
  281.             if (b < 0) b = 0;
  282.             if (r > 255) r = 255;
  283.             if (g > 255) g = 255;
  284.             if (b > 255) b = 255;

  285.             rgb[rgb_idx ++] = ((unsigned int)r << 16) | ((unsigned int)g << 8) | ((unsigned int)b << 0);
  286.         }
  287.     }
  288. }
  289. void get_frame(struct v4l2_dev *dev, int skip_frame)
  290. {
  291. int fd;
  292. unsigned int *fb_mem  = NULL;        //设置显存的位数为32位
  293. struct fb_var_screeninfo var;
  294. struct fb_fix_screeninfo fix;

  295.     int64_t detal_ts = 0;
  296.     struct v4l2_buffer buf;
  297.     struct v4l2_plane planes[FMT_NUM_PLANES];
  298.     fd = open("/dev/fb0",O_RDWR);                        //打开framebuffer设备
  299.         if(fd == -1){
  300.                 perror("Open LCD");
  301.         }
  302.         ioctl(fd, FBIOGET_VSCREENINFO, &var);
  303.         //获取屏幕的固定参数
  304.         ioctl(fd, FBIOGET_FSCREENINFO, &fix);
  305.         //设置屏幕,需要开启才能使用屏幕
  306.         ioctl(fd, FBIOPAN_DISPLAY, &var);
  307.         //打印分辨率
  308.         printf("xres= %d,yres= %d \n",var.xres,var.yres);
  309.     //打印总字节数和每行的长度
  310.         printf("line_length=%d,smem_len= %d \n",fix.line_length,fix.smem_len);
  311.         printf("xpanstep=%d,ypanstep= %d \n",fix.xpanstep,fix.ypanstep);
  312.                        
  313.         /*--------------第二步--------------*/
  314.     fb_mem = (unsigned int *)mmap(NULL, fix.smem_len,                 //获取显存,映射内存
  315.                         PROT_READ |  PROT_WRITE, MAP_SHARED, fd, 0);   
  316.                                                                   
  317.         if(fb_mem == MAP_FAILED){
  318.                 perror("Mmap LCD");
  319.         }
  320. //    memset(fb_mem, 0, fix.smem_len);
  321. /*    for (int i = 0; i < 800; i ++)
  322.         for (int j = 0; j < 1080; j ++)
  323.             if (j < 500)
  324.                 fb_mem[i * 1080 + j] = 0xffffff;
  325.             else if (j > 500 && j < 600)
  326.                 fb_mem[i * 1080 + j] = 0xff00;
  327.             else if (j > 600 && j < 800)
  328.                 fb_mem[i * 1080 + j] = 0xff;
  329.             else
  330.                 fb_mem[i * 1080 + j] = 0xff0000;
  331.     return;*/
  332.     unsigned int *rgb_buf = malloc(fix.smem_len);
  333.     for (int i = 0; i < skip_frame; i ++) {
  334.         memset(&buf, 0, sizeof(buf));
  335.         buf.type = dev->buf_type;
  336.         buf.memory = dev->memory_type;

  337.         if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
  338.             buf.m.planes = planes;
  339.             buf.length = FMT_NUM_PLANES;
  340.         }
  341. //printf("VIDIOC_DQBUF timestamp = %ld\n", get_ts_us());
  342. detal_ts = get_ts_us();
  343.         if (ioctl(dev->fd, VIDIOC_DQBUF, &buf) == -1) {
  344.             printf("VIDIOC_DQBUF failed!\n\n");
  345.             exit_failure(dev);
  346.         }
  347. printf("VIDIOC_DQBUF %.02fms, ", (float)(get_ts_us() - detal_ts) / 1000.0 );

  348.         dev->out_data = (unsigned char *)dev->buffers[buf.index].start;
  349. //       memcpy(fb_mem, dev->out_data, dev->data_len);
  350. detal_ts = get_ts_us();
  351.         NV12ToRGB(dev->out_data, rgb_buf, dev->width, dev->height);
  352. printf("NV12ToRGB %.02fms, ", (float)(get_ts_us() - detal_ts) / 1000.0 );
  353. detal_ts = get_ts_us();
  354.         int cam_idx = 0;
  355.         for(int cam_h = 0; cam_h < dev->height; cam_h ++) {
  356.             int screen_w = cam_h * (var.xres + 8);
  357.             for(int cam_w = 0; cam_w < dev->width; cam_w ++) {//printf("screen_w %d, cam_idx %d\n", screen_w, cam_idx);
  358.                fb_mem[screen_w ++] = rgb_buf[cam_idx ++];
  359.             }
  360.         }
  361. printf("flash %.02fms\n", (float)(get_ts_us() - detal_ts) / 1000.0);
  362.         dev->timestamp = buf.timestamp.tv_sec * 1000000 + buf.timestamp.tv_usec;
  363. //        printf("image: sequence = %d, timestamp = %lu, detal = %lu\r", buf.sequence, dev->timestamp, dev->timestamp - detal_ts);
  364. //        detal_ts = dev->timestamp;

  365.         if (ioctl(dev->fd, VIDIOC_QBUF, &buf) == -1) {
  366.             printf("VIDIOC_QBUF failed!\n");
  367.             exit_failure(dev);
  368.         }
  369.     }
  370.         munmap(fb_mem,fix.smem_len); //映射后的地址,通过mmap返回的值       
  371.         close(fd);                         //关闭fb0设备文件
  372.     return;
  373. }

  374. void save_picture(const char *filename, unsigned char *file_data, unsigned int len, int is_overwrite)
  375. {
  376.     FILE *fp;
  377.     if (is_overwrite)
  378.         fp = fopen(filename, "wb");
  379.     else
  380.         fp = fopen(filename, "ab");
  381.     if (fp < 0) {
  382.         printf("Open frame data file failed\n\n");
  383.         return;
  384.     }printf("file: %s, len: %d\n", filename, len);
  385.     if (fwrite(file_data, 1, len, fp) < len) {
  386.         printf("Out of memory!\n");
  387. //        is_running = 0;
  388.     }
  389.     fflush(fp);
  390.     fclose(fp);
  391.     printf("Save one frame to %s succeed!\n\n", filename);
  392.     return;
  393. }

  394. void stream_off(struct v4l2_dev *dev)
  395. {
  396.     enum v4l2_buf_type type;
  397.     type = dev->buf_type;
  398.     if (ioctl(dev->fd, VIDIOC_STREAMOFF, &type) == -1) {
  399.         printf("VIDIOC_STREAMOFF failed!\n\n");
  400.         exit_failure(dev);
  401.     }
  402.     printf("VIDIOC_STREAMOFF succeed!\n\n");
  403.     return;
  404. }



  405. void set_fps(struct v4l2_dev *dev, unsigned int fps)
  406. {
  407.         int ret;
  408.         struct v4l2_subdev_frame_interval frame_int;

  409.     if (fps == 0) return;

  410.         memset(&frame_int, 0x00, sizeof(frame_int));

  411.         frame_int.interval.numerator = 10000;
  412.         frame_int.interval.denominator = fps * 10000;       

  413.         ret = ioctl(dev->sub_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &frame_int);
  414.         if (ret < 0) {
  415.                 printf("VIDIOC_SUBDEV_S_FRAME_INTERVAL error\n");
  416.         goto set_fps_err;
  417.         }
  418.     printf("VIDIOC_SUBDEV_S_FRAME_INTERVAL [%u fps] OK\n", fps);
  419. set_fps_err:
  420.     return;
  421. }


  422. int main(int argc, char *argv[])
  423. {
  424.     struct v4l2_dev *camdev = &ov8858;
  425.         unsigned int fps = 0;
  426.     unsigned int mode = 4;
  427.     char name[40] = {0};
  428.        
  429.     if (argc > 1)
  430.         fps = atoi(argv[1]);

  431.     open_device(camdev); // 1 打开摄像头设备
  432.     get_capabilities(camdev);
  433.     set_fmt(camdev);                 // 2 设置出图格式
  434.     require_buf(camdev);          // 3 申请缓冲区
  435.     alloc_buf(camdev);            // 4 内存映射
  436.     queue_buf(camdev);            // 5 将缓存帧加入队列
  437.     set_fps(camdev, fps);

  438.     stream_on(camdev);            // 6 开启视频流
  439.     get_frame(camdev, 100); // 7 取一帧数据

  440.     snprintf(name, sizeof(name), "%s.%s", camdev->name, camdev->out_type);
  441.     save_picture(name, camdev->out_data, camdev->data_len, 1);

  442.     stream_off(camdev);   // 8 关闭视频流
  443.     close_device(camdev); // 9 释放内存关闭文件
  444.     return 0;
  445. }

复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-7 00:22 , Processed in 0.117445 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表