├── .gitignore
├── LICENSE
├── QtCamera.cpp
├── QtCamera.h
├── QtCamera.pro
├── README.md
├── app.ico
└── main.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 | *.slo
3 | *.lo
4 | *.o
5 | *.a
6 | *.la
7 | *.lai
8 | *.so
9 | *.dll
10 | *.dylib
11 |
12 | # Qt-es
13 | object_script.*.Release
14 | object_script.*.Debug
15 | *_plugin_import.cpp
16 | /.qmake.cache
17 | /.qmake.stash
18 | *.pro.user
19 | *.pro.user.*
20 | *.qbs.user
21 | *.qbs.user.*
22 | *.moc
23 | moc_*.cpp
24 | moc_*.h
25 | qrc_*.cpp
26 | ui_*.h
27 | *.qmlc
28 | *.jsc
29 | Makefile*
30 | *build-*
31 |
32 | # Qt unit tests
33 | target_wrapper.*
34 |
35 | # QtCreator
36 | *.autosave
37 |
38 | # QtCreator Qml
39 | *.qmlproject.user
40 | *.qmlproject.user.*
41 |
42 | # QtCreator CMake
43 | CMakeLists.txt.user*
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 aeagean
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/QtCamera.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | Author: Qt君
3 | 微信公众号: Qt君(首发)
4 | QQ群: 732271126
5 | Email: 2088201923@qq.com
6 | LICENSE: MIT
7 | **********************************************************/
8 | #include "QtCamera.h"
9 | #include "QtCamera.h"
10 | #include
11 |
12 | QtCamera::QtCamera(QVideoWidget *widget) :
13 | m_videoWidget(widget),
14 | m_isStarted(false),
15 | m_camera(NULL)
16 | {
17 | selectDevice(QCameraInfo::defaultCamera());
18 | start();
19 |
20 | connect(&m_checkDeviceListTimer, SIGNAL(timeout()), this, SLOT(checkDeviceList()));
21 | connect(this, SIGNAL(deviceListChanged()), this, SLOT(autoRestore()));
22 | connect(this, SIGNAL(deviceListChanged()), this, SLOT(autoSelectDevice()));
23 |
24 | m_checkDeviceListTimer.start(3000);
25 |
26 | QList curCameraInfoList = QCameraInfo::availableCameras();
27 | for (int i = 0; i < curCameraInfoList.count(); i++) {
28 | qDebug() << curCameraInfoList.at(i).deviceName();
29 | }
30 | }
31 |
32 | QtCamera::~QtCamera()
33 | {
34 |
35 | }
36 |
37 | bool QtCamera::start()
38 | {
39 | if (! m_isStarted) {
40 | m_isStarted = true;
41 |
42 | m_camera->start();
43 | }
44 |
45 | return true;
46 | }
47 |
48 | bool QtCamera::stop()
49 | {
50 | if (m_isStarted) {
51 | m_isStarted = false;
52 |
53 | m_camera->stop();
54 | }
55 |
56 | return true;
57 | }
58 |
59 | bool QtCamera::isStarted()
60 | {
61 | return m_isStarted;
62 | }
63 |
64 | bool QtCamera::selectDevice(const QCameraInfo &cameraInfo)
65 | {
66 | bool restart = isStarted();
67 | if (isStarted()) {
68 | stop();
69 | }
70 |
71 | if (m_camera) {
72 | delete m_camera;
73 | }
74 |
75 | m_curCameraInfo = cameraInfo;
76 | m_camera = new QCamera(m_curCameraInfo);
77 | m_camera->setViewfinder(m_videoWidget);
78 |
79 | if (restart)
80 | start();
81 | }
82 |
83 | void QtCamera::autoRestore()
84 | {
85 | if (! m_isStarted) {
86 | return;
87 | }
88 |
89 | if (deviceExist(m_curCameraInfo)) {
90 | if (m_camera->status() != QCamera::ActiveStatus) {
91 | QTimer::singleShot(500, m_camera, SLOT(start()));
92 | }
93 | }
94 | else {
95 | if (m_camera->status() == QCamera::ActiveStatus) {
96 | m_camera->stop();
97 | m_camera->unload();
98 | }
99 | }
100 | }
101 |
102 | void QtCamera::autoSelectDevice()
103 | {
104 | QList curCameraInfoList = QCameraInfo::availableCameras();
105 | if (curCameraInfoList.isEmpty())
106 | return;
107 |
108 | if (curCameraInfoList.contains(m_curCameraInfo)) {
109 | selectDevice(m_curCameraInfo);
110 | return;
111 | }
112 |
113 | selectDevice(curCameraInfoList.first());
114 | }
115 |
116 | void QtCamera::checkDeviceList()
117 | {
118 | QList curCameraInfoList = QCameraInfo::availableCameras();
119 | if ( m_preCameraInfoList.count() != curCameraInfoList.count() ) {
120 | emit deviceListChanged();
121 | }
122 |
123 | m_preCameraInfoList = curCameraInfoList;
124 | }
125 |
126 | bool QtCamera::deviceExist(const QCameraInfo &cameraInfo) const
127 | {
128 | QList cameraInfoList = QCameraInfo::availableCameras();
129 | for (int i = 0; i < cameraInfoList.count(); i++) {
130 | if (cameraInfo.deviceName() == cameraInfoList.at(i).deviceName())
131 | return true;
132 | }
133 |
134 | return false;
135 | }
136 |
--------------------------------------------------------------------------------
/QtCamera.h:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | Author: Qt君
3 | 微信公众号: Qt君(首发)
4 | QQ群: 732271126
5 | Email: 2088201923@qq.com
6 | LICENSE: MIT
7 | **********************************************************/
8 | #ifndef QT_CAMERA_H
9 | #define QT_CAMERA_H
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | class QtCamera : public QObject
17 | {
18 | Q_OBJECT
19 | public:
20 | QtCamera(QVideoWidget *widget);
21 | ~QtCamera();
22 |
23 | bool start();
24 | bool stop();
25 | bool isStarted();
26 |
27 | bool selectDevice(const QCameraInfo &cameraInfo);
28 |
29 | signals:
30 | void deviceListChanged();
31 | void deviceStatusChanged();
32 |
33 | private slots:
34 | void autoRestore();
35 | void autoSelectDevice();
36 | void checkDeviceList();
37 |
38 | private:
39 | bool deviceExist(const QCameraInfo &cameraInfo) const;
40 |
41 | private:
42 | bool m_isStarted;
43 | QTimer m_checkDeviceListTimer;
44 |
45 | QVideoWidget *m_videoWidget;
46 | QCamera *m_camera;
47 | QCameraInfo m_curCameraInfo;
48 | QList m_curCameraInfoList;
49 | QList m_preCameraInfoList;
50 | };
51 |
52 | #endif // QT_CAMERA_H
53 |
--------------------------------------------------------------------------------
/QtCamera.pro:
--------------------------------------------------------------------------------
1 | #**********************************************************
2 | #Author: Qt君
3 | #微信公众号: Qt君
4 | #QQ群: 732271126
5 | #Email: 2088201923@qq.com
6 | #LICENSE: MIT
7 | #**********************************************************
8 |
9 | QT += core gui
10 | QT += multimedia multimediawidgets
11 |
12 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
13 |
14 | TARGET = QtCamera
15 | TEMPLATE = app
16 |
17 | win32: RC_ICONS += app.ico
18 |
19 | # The following define makes your compiler emit warnings if you use
20 | # any feature of Qt which has been marked as deprecated (the exact warnings
21 | # depend on your compiler). Please consult the documentation of the
22 | # deprecated API in order to know how to port your code away from it.
23 | DEFINES += QT_DEPRECATED_WARNINGS
24 |
25 | # You can also make your code fail to compile if you use deprecated APIs.
26 | # In order to do so, uncomment the following line.
27 | # You can also select to disable deprecated APIs only up to a certain version of Qt.
28 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
29 |
30 | CONFIG += c++11
31 |
32 | SOURCES += \
33 | main.cpp \
34 | QtCamera.cpp
35 |
36 | HEADERS += \
37 | QtCamera.h
38 |
39 | # Default rules for deployment.
40 | qnx: target.path = /tmp/$${TARGET}/bin
41 | else: unix:!android: target.path = /opt/$${TARGET}/bin
42 | !isEmpty(target.path): INSTALLS += target
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | > 基于Qt的Camera模块实现摄像头的热插拔。当只有一个摄像头时,被拔开后再插入能自动恢复相机状态。当有多个摄像头时,拔开当前摄像头会自动设置另外一个摄像头。
9 |
10 | ## 基于定时查询的方法
11 | * **定时查询**设备列表变化;
12 | ```cpp
13 | connect(&m_checkDeviceListTimer, SIGNAL(timeout()),
14 | this, SLOT(checkDeviceList()));
15 | ```
16 | * 如果当前设备列表**对比**上一次缓存的设备列表有变化则**发送**设备列表变化**事件**(信号)`deviceListChanged()`;
17 | ```cpp
18 | void QtCamera::checkDeviceList()
19 | {
20 | QList curCameraInfoList = QCameraInfo::availableCameras();
21 | if ( m_preCameraInfoList.count() != curCameraInfoList.count() ) {
22 | emit deviceListChanged();
23 | }
24 |
25 | m_preCameraInfoList = curCameraInfoList;
26 | }
27 | ```
28 |
29 | ## 单设备重连机制
30 | * 先前`autoRestore()`槽函数**绑定**设备列表变化信号。
31 | ```cpp
32 | connect(this, SIGNAL(deviceListChanged()), this, SLOT(autoRestore()));
33 | ```
34 | * 触发自动重连机制。
35 | 当设备**存在**则会重新启动`start()`;
36 | 当设备**不存**在则关闭该设备。
37 | ```cpp
38 | void QtCamera::autoRestore()
39 | {
40 | if (! m_isStarted) {
41 | return;
42 | }
43 |
44 | if (deviceExist(m_curCameraInfo)) {
45 | if (m_camera->status() != QCamera::ActiveStatus) {
46 | QTimer::singleShot(500, m_camera, SLOT(start()));
47 | }
48 | }
49 | else {
50 | if (m_camera->status() == QCamera::ActiveStatus) {
51 | m_camera->stop();
52 | m_camera->unload();
53 | }
54 | }
55 | }
56 | ```
57 |
58 | ## 多设备自动切换
59 | * `autoSelectDevice()`槽函数连接设备列表变化信号。
60 | ```cpp
61 | connect(this, SIGNAL(deviceListChanged()), this, SLOT(autoSelectDevice()));
62 | ```
63 |
64 | * 当设备已存在再次刷新**当前的**设备;
65 | * 当设备被**断开**,自动切换到第一个设备。
66 | ```cpp
67 | void QtCamera::autoSelectDevice()
68 | {
69 | QList curCameraInfoList = QCameraInfo::availableCameras();
70 | if (curCameraInfoList.isEmpty())
71 | return;
72 |
73 | if (curCameraInfoList.contains(m_curCameraInfo)) {
74 | selectDevice(m_curCameraInfo);
75 | return;
76 | }
77 |
78 | selectDevice(curCameraInfoList.first());
79 | }
80 | ```
81 |
82 | ## 关于更多
83 | * 源码地址:
84 | ```
85 | https://github.com/aeagean/QtCamera
86 | ```
87 | * 文章首发公众号:**Qt君**
88 |
89 |
90 |
Qt君
91 |
92 |
93 | * **后续**更新摄像头参数选择算法(自动匹配用户设置摄像头参数,**分辨率**,**帧率**,**格式**)。
94 |
--------------------------------------------------------------------------------
/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtCamera/31039f1fcd3fd6e36a6ec79a8d9b60f550832ba0/app.ico
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | Author: Qt君
3 | 微信公众号: Qt君(首发)
4 | QQ群: 732271126
5 | Email: 2088201923@qq.com
6 | LICENSE: MIT
7 | **********************************************************/
8 | #include "QtCamera.h"
9 |
10 | #include
11 |
12 | int main(int argc, char *argv[])
13 | {
14 | QApplication a(argc, argv);
15 |
16 | QVideoWidget widget;
17 | QtCamera camera(&widget);
18 | widget.show();
19 | return a.exec();
20 | }
21 |
--------------------------------------------------------------------------------