• 245阅读
  • 3回复

Qt音视频开发36-USB摄像头解码qcamera方案 [复制链接]

上一主题 下一主题
离线liudianwu
 

## 一、前言
除了监控专用的摄像头以外,有一些应用场景用的还是USB摄像头,甚至还有一些单片机或者开发板上用的CMOS摄像头,而Qt在嵌入式领域应用相当广,所以用Qt来读取加载显示USB摄像头和CMOS摄像头,也是非常多Qter做过的事情,qt本身就封装了qcamera类,专用于本地摄像头的读取显示,这个类主要是在windows系统和安卓系统比较好使,在嵌入式上歇菜,而且安卓上widget的qcamera也不好使,要用qml的camera才好使,所以开发人员很多时候,就是在找坑填坑,找到一种最佳的适中方案,比如我自己做过的一个手机app,需要调用手机的摄像头,前置后置还要能切换,抓图做一些处理,用的就是qml嵌入到widget,通过信号槽来通信。

用Qt来加载USB摄像头解码,主要就三种方案,一种是Qt自带的,一种是ffmpeg来处理,一种是v4l2框架,每种方案都各自有优缺点和对应的应用场景,比如Qt自带的就非常适合windows下的只需要显示摄像头的场景,代码简单Qt内置使用方便,如果是需要拿到每张图片自己还要做分析处理比如人脸识别啥的,用ffmpeg是最好的,速度快资源占用低,可以自己GPU绘制,爽得很,如果是嵌入式linux的话,那用v4l2框架处理是最适合的,原生的通用api框架。

QCamera方案处理流程:
1. 实例化QCamera对象,绑定stateChanged信号用于调整尺寸大小。
2. 实例化QCameraViewfinder画布,将QCamera对象设置画布。默认采用类似句柄的形式显示画面,被系统接管绘制。
3. 实例化QCameraImageCapture对象用来抓图,如果有需要的话。

## 二、功能特点
1. 同时支持windows、linux、嵌入式linux上的USB摄像头实时采集。
2. 支持多路USB摄像头多线程实时采集。
3. 在嵌入式linux设备上,自动查找USB设备文件并加载。
4. 可手动设置设备文件名称,手动设置后按照手动设置的设备文件加载。
5. 在嵌入式linux设备上支持人脸识别接口,实时绘制人脸框。
6. 具有打开、暂停、继续、关闭、截图等常规功能。
7. 可设置两路OSD标签,分别设置文本、颜色、字号、位置等。
8. 可作为视频监控系统使用。

## 三、效果图
window.open('http://www.qtcn.org/bbs/attachment/Mon_2010/44_110085_45fa5600d0fff4a.jpg?60');" style="max-width:700px;max-height:700px;" onload="if(is_ie6&&this.offsetWidth>700)this.width=700;" >



## 四、相关站点
1. 国内站点:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)
2. 国际站点:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)
3. 个人主页:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
4. 知乎主页:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
5. 体验地址:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)

## 五、核心代码
```cpp
//widget版本
static void getCameraInfo(QStringList &deviceNames, QStringList &descriptions)
{
#ifndef __arm__
#if (QT_VERSION > QT_VERSION_CHECK(5,5,0))
    deviceNames.clear();
    descriptions.clear();
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    if (cameras.count() == 0) {
        qDebug() << TIMEMS << "not find USBCamera";
    } else {
        foreach (QCameraInfo camera, cameras) {
            deviceNames << camera.deviceName();
            descriptions << camera.description();
        }
    }
#endif
#endif
}

void CameraThread::stateChanged()
{
#ifdef __arm__
#else
#if (QT_VERSION > QT_VERSION_CHECK(5,5,0))
    if (camera->state() == QCamera::ActiveState) {
        //输出当前设备支持的分辨率
        QList<QSize> sizes = camera->supportedViewfinderResolutions();
        emit resolutions(sizes);
        //重新设置分辨率
        QCameraViewfinderSettings set;
        set.setResolution(cameraWidth, cameraHeight);
        camera->setViewfinderSettings(set);
    }
#endif
#endif
}

bool CameraThread::init()
{
#ifdef __arm__    
#else
#if (QT_VERSION > QT_VERSION_CHECK(5,5,0))
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    if (cameras.count() == 0) {
        qDebug() << TIMEMS << "not find USBCamera";
        return false;
    } else {
        QWidget *frm = (QWidget *)parent();
        camera = new QCamera(frm);
        connect(camera, SIGNAL(stateChanged(QCamera::State)), this, SLOT(stateChanged()));

        viewfinder = new QCameraViewfinder(frm);
        viewfinder->installEventFilter(this);
        camera->setViewfinder(viewfinder);

        QRect rect = frm->rect();
        viewfinder->setAspectRatioMode(fillImage ? Qt::IgnoreAspectRatio : Qt::KeepAspectRatio);
        int offset = borderWidth * 1 + 0;
        viewfinder->setGeometry(offset / 2, offset / 2, rect.width() - offset, rect.height() - offset);
        viewfinder->setVisible(true);

        imageCapture = new QCameraImageCapture(camera);
        connect(imageCapture, SIGNAL(imageCaptured(int, QImage)), this, SLOT(displayImage(int, QImage)));
        return true;
    }
#endif
#endif
}

//qml版本
import QtQuick 2.0
import QtMultimedia 5.6

Item {
    signal receiveImage();

    Video {
        id: video
        anchors.fill: parent
        //source: "rtsp://192.168.1.247:554/av0_0"
        source: "g:/mp4/1.mp4"

        MouseArea {
            anchors.fill: parent
            onClicked: {
                video.play()
            }
        }

        focus: true
        Keys.onSpacePressed: video.playbackState == MediaPlayer.PlayingState ? video.pause() : video.play()
        Keys.onLeftPressed: video.seek(video.position - 5000)
        Keys.onRightPressed: video.seek(video.position + 5000)
    }
}

```
专业各种自定义控件编写+UI定制+输入法定制+视频监控+工业控制+仪器仪表+嵌入式linux+各种串口网络通信,童叟无欺,量大从优,欢迎咨询购买定制!你正好需要,我正好专业!QQ:517216493 微信:feiyangqingyun Email:feiyangqingyun@163.com
群号:853086607(Qt交流大会,雨田哥群,不定期上传作品,解答作品中相关问题!) 312125701(QtQML多多指教群) 46679801(Qt开发技术交流群-5000人大群)
离线mengkun

只看该作者 1楼 发表于: 10-18
刘老师,USB 的视频录制有没有什么比较好的方案呢?
离线liudianwu

只看该作者 2楼 发表于: 10-19
回 mengkun 的帖子
mengkun:刘老师,USB 的视频录制有没有什么比较好的方案呢? (2020-10-18 10:30) 

终极大法,ffmpeg,搜索ffmpeg录制USB摄像头
专业各种自定义控件编写+UI定制+输入法定制+视频监控+工业控制+仪器仪表+嵌入式linux+各种串口网络通信,童叟无欺,量大从优,欢迎咨询购买定制!你正好需要,我正好专业!QQ:517216493 微信:feiyangqingyun Email:feiyangqingyun@163.com
群号:853086607(Qt交流大会,雨田哥群,不定期上传作品,解答作品中相关问题!) 312125701(QtQML多多指教群) 46679801(Qt开发技术交流群-5000人大群)
离线mengkun

只看该作者 3楼 发表于: 10-21
回 liudianwu 的帖子
liudianwu:终极大法,ffmpeg,搜索ffmpeg录制USB摄像头 (2020-10-19 19:45) 

好的,非常感谢!
快速回复
限100 字节
 
上一个 下一个