IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> V4L2+QT+USB摄像头实时显示视频(ArmLinuxwindow均适用) -> 正文阅读

[嵌入式]V4L2+QT+USB摄像头实时显示视频(ArmLinuxwindow均适用)

写在开头

笔者自从学习了Framebuffer编程和V4L2编程之后,就想实现在LCD屏上显示实时视频

笔者学习过正点I.MX6U Linux C编程中的相关内容,然而原子的例程是针对OV5640摄像头写的,像素格式是RGB

然而USB摄像头大多支持MJPEG或者YUYV格式,如果要在屏幕上显示需要进行格式转换,而转换像素格式是需要处理时间的,自然会影响视频帧率

笔者尝试写过YUYV2RGB888或者YUYV2RGB565,实际跑起来能明显感受到掉帧;
同时,笔者也考虑通过OpenCV来对JPEG或者YUYV进行编解码来显示,然而实际效果也不尽如人意

那有没有办法既能实时显示视频也不用进行图像格式转换还能有用户操作界面?

笔者结合之前所学内容最终决定用QT写界面,V4L2编程来获取实时的帧并将其显示在设计好的界面上

开发环境

  1. 虚拟机Ubuntu 16.04
  2. 编辑器VsCode
  3. 交叉编译工具 arm-linux-gnueabihf
  4. 已制作文件系统,已使能UVC相关驱动
  5. 正点原子ZYNQ7010启明星开发板
  6. USB摄像头淘宝随便买的一个
  7. QT Creator 5.9.6

必备知识

UVC驱动配置可以看我的这一篇: Linux 内核4.14添加UVC配置

QT移植并显示图片可以看我的这一篇: Qt移植正点原子ZYNQ7010-Arm平台显示图片demo,本博客的程序设计也是基于这一篇文章的

V4L2编程入门可以看我的这一篇: V4L2编程之USB摄像头采集jpeg图像

界面布局设计

在这里插入图片描述
可以先看一下运行效果,主体部分一共就三个:一个QLabel控件用于显示实时图像,两个QPushButton,一个用于控制视频流的显示,另一个用于解放资源并关闭窗口。

界面很简单,本博客只是实现最基础的功能,后续会在此基础上加控件和其他功能。

程序设计思路

  1. 界面布局初始化
  2. 获得用户输入,打开对应摄像头
  3. 摄像头初始化,包括打印摄像头支持的像素格式、分辨率、帧率
  4. 设置采集格式,包括像素格式、帧率设置
  5. 申请内存空间并建立内存映射,进行出队入队操作
  6. 开启视频流
  7. 设置定时器,等待“开始”按钮信号触发定时器开启
  8. 定时器定时获取一帧图像将其显示在QLabel上
  9. 等待“结束”按钮信号触发释放资源并关闭窗口

关键部分在于789三步,这里稍作解释,不想看的可直接去看源码——我的Github仓库: Linux C编程实战代码
我已经将源码连同V4L2编程的API用户手册一并上传了,欢迎大家学习交流

要在ARM平台跑也是可以的,需要自行移植QT到ARM开发板,移植办法详见我往期博客Qt移植正点原子ZYNQ7010-Arm平台显示图片demo

关键代码分析

获取用户输入赋值给v4l2_dev_init()初始化对应的摄像头
引入QCoreApplication获取用户输入的第二个字段,例如执行 ./Qt_V4l2 /dev/video1,device_parm[1] 的内容即/dev/video1
值得注意的是需要进行一个数据类型转换才能作为open()函数的参数

    QStringList device_parm = QCoreApplication::arguments();
    QString str = device_parm[1];

    v4l2_dev_init(str.toStdString());
    
    ......
    
	int MainWindow::v4l2_dev_init(string device_name){
	    /* 打开摄像头 */
	    v4l2_fd = open(device_name.c_str(),O_RDWR);
	    if(v4l2_fd < 0){
	        printf("open camera failed\n");
	        return -1;
	    }
	    printf("open camera success\n");
	    
	    ......
	    
	 }

两个按钮的信号连接代码

    //点击开始按钮,打开定时器
    connect(pushButton[0],SIGNAL(clicked()),this,SLOT(timer_start()));

    //每隔固定的时间显示一帧
    timer = new QTimer();
    connect(timer, SIGNAL(timeout()), this, SLOT(video_show()));

    /* 按钮窗口关闭,先释放设备,再关闭窗口 */
    connect(pushButton[1],SIGNAL(clicked()),this,SLOT(v4l2_device_release()));
    connect(pushButton[1],SIGNAL(clicked()),this,SLOT(close()));

定时器控制帧率,每个33ms触发video_show()显示一帧数据,一秒钟正好显示30帧(笔者的摄像头最大支持30fps,故如此设置)

/* 定时器控制帧 */
void MainWindow::timer_start(){
    // 1000/33约等于30,也就是每一秒显示30帧
    timer->start(33);
}

初始化select()来进行I/O端口复用

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(v4l2_fd,&fds);

    //设置等待时间为2s
    struct timeval tv;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    select(v4l2_fd+1,&fds,NULL,NULL,&tv);

此段代码摘自V4L2 API手册最后的示例代码中,相关pdf文档已上传到github

获取一帧图像的数据,见于v4l2_get_one_frame(FrameBuffer *framebuf)
首先从出队队列中取一帧视频数据的视频缓冲区,再将该帧数据拷贝到frame中

    if(0 > ioctl(v4l2_fd,VIDIOC_DQBUF,&one_buf)){
        printf("VIDIOC_DQBUF failed!\n");
        return -1;
    }
	// bytesused 表示buf中已经使用的字节数
	    memcpy(framebuf->buf,(char *)buffer_infos[one_buf.index].start,one_buf.bytesused);
	    framebuf->length = one_buf.bytesused;

Qt 提供了四个用于处理图像数据的类,而 QPixmap 正是为在屏幕上显示图像而设计和优化
最后将获取保存在frame中的数据用QPixmap转换就可以显示了

     FrameBuffer frame;
     QPixmap pix;

     //获取一帧显示
     v4l2_get_one_frame(&frame);
     pix.loadFromData(frame.buf, frame.length);
     pix.scaled(displayLabel->width(),displayLabel->height(),Qt::KeepAspectRatio);
     displayLabel->setPixmap(pix);

结束语

本博客的程序已上传到github中,往期博客有关Linux C编程的代码也一并上传,需要的自行下载

后续会继续更新,通过程序设计来实现拍照截图、图像处理、视频流的存储和推流等功能,慢慢完善了

我是爱学习的诸葛铁锤,觉得有帮助的话记得点个赞再走吧,wakuwaku!

请添加图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-14 22:50:26  更:2022-06-14 22:51:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 8:30:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计