From 90998c7b0773de829e9523bff16a0b41741373ed Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 12 Mar 2026 21:03:38 +0800 Subject: [PATCH] feat: Add the logic for switching cameras by USB groups. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the logic for switching cameras by USB groups. 增加按USB分组切换摄像头的逻辑。 代码来自xiwo分支。 --- src/assets/org.deepin.camera.encode.json | 10 ++ src/main.cpp | 6 ++ src/src/basepub/datamanager.h | 11 ++ src/src/videowidget.cpp | 127 +++++++++++++++++++---- src/src/videowidget.h | 8 ++ 5 files changed, 140 insertions(+), 22 deletions(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 7370ce3d..90ad17b9 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -71,6 +71,16 @@ "description": "is preview no delay or not", "permissions": "readwrite", "visibility": "private" + }, + "enableUsbGroup": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "enable USB group", + "name[zh_CN]": "是否启用USB摄像头分组", + "description": "Enable USB group", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index 252a11c8..c40765ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -182,6 +182,12 @@ int main(int argc, char *argv[]) DataManager::instance()->setPreviewNoDelay(dconfig->value("previewNoDelay").toBool()); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("enableUsbGroup")) { + bool enable = dconfig->value("enableUsbGroup").toBool(); + qInfo() << "enable USB group:" << enable; + DataManager::instance()->setEnableUsbGroup(enable); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index db704291..fafa8068 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -165,6 +165,16 @@ class DataManager: public QObject */ bool isPreviewNoDelay() { return m_isPreviewNoDelay; }; + /** + * @brief 设置是否启用USB摄像头分组 + * @param enable + */ + void setEnableUsbGroup(bool enable) { m_enableUsbGroup = enable; }; + /** + * @brief 获取是否启用USB摄像头分组 + * @return + */ + bool isEnableUsbGroup() const { return m_enableUsbGroup; }; private: DataManager(); static DataManager *m_dataManager; @@ -176,5 +186,6 @@ class DataManager: public QObject bool m_H264EncoderExists; bool m_isSupportCameraSwitch = false; // 是否带有摄像头开关 bool m_isPreviewNoDelay = false; // 是否预览无延迟 + bool m_enableUsbGroup = false; // 是否启用USB摄像头分组 }; #endif // DATAMANAGER_H diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index c084e867..ec2dac2f 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -1118,37 +1118,89 @@ void videowidget::onChangeDev() } v4l2_device_list_t *devlist = get_device_list(); - if (devlist->num_devices == 2) { - for (int i = 0 ; i < devlist->num_devices; i++) { - QString str1 = QString(devlist->list_devices[i].device); - if (str != str1) { - if (E_OK == switchCamera(devlist->list_devices[i].device, devlist->list_devices[i].name)) { - break; + if (devlist == nullptr) { + qWarning() << "get device list FAILED"; + return; + } + + // USB摄像头分组相关逻辑来自xiwo分支,是否开启由DConfig控制 + int groupNum = 1; + QVector>> vGroupData; + // 如果未启用USB摄像头分组,则分组数默认为1,保持原有逻辑; + // 如果启用USB摄像头分组,则实际获取USB分组情况,根据分组结果进行处理; + if (DataManager::instance()->isEnableUsbGroup()) { + // 必须确保 devlist 的生命周期长于 vGroupData 的使用周期。 + // 如果 devlist 在 vGroupData 使用完毕前被释放,将导致悬空指针,引发崩溃。 + // 好在 vGroupData 只在本函数中使用,不会在其他地方被引用,所以不会导致悬空指针问题。 + groupNum = getUSBCameraGroup(devlist, vGroupData); + qInfo() << __func__ << "groupNum:" << groupNum; + } + if (groupNum == 1) { + if (devlist->num_devices == 2) { + for (int i = 0 ; i < devlist->num_devices; i++) { + const char *curDev = devlist->list_devices[i].device; + if (str != curDev) { + if (E_OK == switchCamera(curDev, devlist->list_devices[i].name)) { + break; + } } } - } - } else { - if (devlist->num_devices == 0) { - DataManager::instance()->setdevStatus(NOCAM); - showNocam(); - } + } else { + if (devlist->num_devices == 0) { + DataManager::instance()->setdevStatus(NOCAM); + showNocam(); + } - for (int i = 0 ; i < devlist->num_devices; i++) { - QString str1 = QString(devlist->list_devices[i].device); + for (int i = 0 ; i < devlist->num_devices; i++) { + const char *curDev = devlist->list_devices[i].device; + if (str == curDev) { + if (i == devlist->num_devices - 1) { + switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); + break; + } else { + switchCamera(devlist->list_devices[i + 1].device, devlist->list_devices[i + 1].name); + break; + } + } - if (str == str1) { - if (i == devlist->num_devices - 1) { + if (str.isEmpty()) { switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); break; - } else { - switchCamera(devlist->list_devices[i + 1].device, devlist->list_devices[i + 1].name); - break; } } + } + } else { + if (groupNum == 2) { + for (int i = 0 ; i < vGroupData.count(); i++) { + const char *curDev = vGroupData[i].second[0]->device; + if (str != curDev) { + if (E_OK == switchCamera(curDev, vGroupData[i].second[0]->name)) { + break; + } + } + } + } else { + if (devlist->num_devices == 0) { + DataManager::instance()->setdevStatus(NOCAM); + showNocam(); + } - if (str.isEmpty()) { - switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); - break; + for (int i = 0 ; i < vGroupData.count(); i++) { + const char *curDev = vGroupData[i].second[0]->device; + if (str == curDev) { + if (i == vGroupData.count() - 1) { + switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); + break; + } else { + switchCamera(vGroupData[i + 1].second[0]->device, vGroupData[i + 1].second[0]->name); + break; + } + } + + if (str.isEmpty()) { + switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); + break; + } } } } @@ -1200,6 +1252,37 @@ int videowidget::switchCamera(const char *device, const char *devName) return ret; } +int videowidget::getUSBCameraGroup(v4l2_device_list_t *devlist, QVector>> &vGroupData) +{ + // 来自xiwo分支,根据location进行分组 + // 收到建议使用 QMap> 来存储分组数据,但我们担心影响现有代码逻辑, + // 所以暂时保留 QVector>> 来存储分组数据。 + if (devlist == nullptr) { + qWarning() << __func__ << "devlist is NULL!"; + return 0; + } + + for (int i = 0 ; i < devlist->num_devices; i++) { + QString location = QString(devlist->list_devices[i].location); + + int j = 0; + for (; j < vGroupData.count(); j++) { + if (location == vGroupData.at(j).first) { + break; + } + } + if (j == vGroupData.count()) { + QVector vList; + vList.append(&devlist->list_devices[i]); + vGroupData.append(qMakePair(location, vList)); + } else { + QVector &vlist = vGroupData[j].second; + vlist.append(&devlist->list_devices[i]); + } + } + return vGroupData.count(); +} + QString videowidget::getSaveFilePrefix() { QString filePrefix = "Camera_"; diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 56bb0e37..54b03c12 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -420,6 +420,14 @@ private slots: */ int switchCamera(const char *device, const char *devName); + /** + * @brief 获取USB摄像头分组 + * @param devlist 设备列表 + * @param vGroupData 分组 + * @return 分组个数 + */ + int getUSBCameraGroup(v4l2_device_list_t *devlist, QVector>> &vGroupData); + /** * @brief getSaveFilePrefix * @return UOS_ 专业版 DEEPIN_ 社区版 CAMERA_ 其他