├── .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 | 微信公众号:Qt君 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 | --------------------------------------------------------------------------------