Skip to content

feat: Add the logic for switching cameras by USB groups.#461

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
lichaofan2008:release/eagle
Mar 13, 2026
Merged

feat: Add the logic for switching cameras by USB groups.#461
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
lichaofan2008:release/eagle

Conversation

@lichaofan2008
Copy link
Contributor

@lichaofan2008 lichaofan2008 commented Mar 12, 2026

Add the logic for switching cameras by USB groups.
增加按USB分组切换摄像头的逻辑。
代码来自xiwo分支。

Summary by Sourcery

Add configurable USB camera grouping and update camera switching logic to respect these groups while preserving existing behavior when grouping is disabled.

New Features:

  • Introduce a DataManager flag to enable or disable USB camera grouping controlled via DConfig.
  • Add logic to group USB cameras by physical location and switch between cameras based on these groups.

Enhancements:

  • Extend camera switching flow to handle grouped and ungrouped devices, including edge cases like no devices present.
  • Log the USB grouping configuration state at startup for easier diagnostics.

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 12, 2026

Reviewer's Guide

Implements USB camera group–aware switching logic in videowidget, controlled via a new DConfig-driven flag stored in DataManager, and introduces helper logic to compute groups based on device location while preserving the old behavior when grouping is disabled.

Sequence diagram for USB group–aware camera switching

sequenceDiagram
    actor User
    participant VideoWidget as videowidget
    participant DataManager
    participant V4L2 as V4L2Devices

    User ->> VideoWidget: onChangeDev()
    VideoWidget ->> V4L2: get_device_list()
    V4L2 -->> VideoWidget: v4l2_device_list_t devlist

    VideoWidget ->> DataManager: isEnableUsbGroup()
    DataManager -->> VideoWidget: bool enableUsbGroup

    alt USB grouping disabled or only one group
        Note over VideoWidget,V4L2: Legacy device-based switching
        alt exactly 2 devices
            VideoWidget ->> VideoWidget: iterate devlist
            VideoWidget ->> VideoWidget: switchCamera(other_device)
        else 0 or more than 2 devices
            alt no devices
                VideoWidget ->> DataManager: setdevStatus(NOCAM)
                VideoWidget ->> VideoWidget: showNocam()
            else devices available
                VideoWidget ->> VideoWidget: find current device index
                alt current is last device
                    VideoWidget ->> VideoWidget: switchCamera(first_device)
                else current not last
                    VideoWidget ->> VideoWidget: switchCamera(next_device)
                end
                alt current device unknown
                    VideoWidget ->> VideoWidget: switchCamera(first_device)
                end
            end
        end
    else USB grouping enabled with multiple groups
        VideoWidget ->> VideoWidget: getUSBCameraGroup(devlist, vGroupData)
        VideoWidget ->> VideoWidget: groupNum = vGroupData.count()
        alt exactly 2 groups
            Note over VideoWidget,V4L2: Toggle between two groups
            VideoWidget ->> VideoWidget: iterate groups
            VideoWidget ->> VideoWidget: switchCamera(group[i].first_device)
        else more than 2 groups
            alt no devices
                VideoWidget ->> DataManager: setdevStatus(NOCAM)
                VideoWidget ->> VideoWidget: showNocam()
            else devices available
                VideoWidget ->> VideoWidget: find current group index
                alt current is last group
                    VideoWidget ->> VideoWidget: switchCamera(first_group.first_device)
                else current not last
                    VideoWidget ->> VideoWidget: switchCamera(next_group.first_device)
                end
                alt current device unknown
                    VideoWidget ->> VideoWidget: switchCamera(first_group.first_device)
                end
            end
        end
    end
Loading

Class diagram for updated DataManager and videowidget USB group logic

classDiagram
    class DataManager {
        - static DataManager *m_dataManager
        - bool m_H264EncoderExists
        - bool m_isSupportCameraSwitch
        - bool m_isPreviewNoDelay
        - bool m_enableUsbGroup
        + static DataManager *instance()
        + void setPreviewNoDelay(bool enable)
        + bool isPreviewNoDelay()
        + void setEnableUsbGroup(bool enable)
        + bool isEnableUsbGroup() const
        + void setdevStatus(int status)
    }

    class v4l2_dev_sys_data_t {
        + const char *device
        + const char *name
        + const char *location
    }

    class v4l2_device_list_t {
        + int num_devices
        + v4l2_dev_sys_data_t *list_devices
    }

    class videowidget {
        + void onChangeDev()
        - int switchCamera(const char *device, const char *devName)
        - int getUSBCameraGroup(v4l2_device_list_t *devlist, QVector_QPair_QString_QVector_v4l2_dev_sys_data_t_ptr & vGroupData)
    }

    DataManager <.. videowidget : uses
    v4l2_device_list_t <.. videowidget : uses
    v4l2_dev_sys_data_t <.. v4l2_device_list_t : contains

    class QVector_QPair_QString_QVector_v4l2_dev_sys_data_t_ptr {
    }

    QVector_QPair_QString_QVector_v4l2_dev_sys_data_t_ptr <.. videowidget : groups
Loading

Flow diagram for DConfig-driven USB group enable flag

flowchart LR
    A[DConfig enableUsbGroup key] --> B[main reads enableUsbGroup]
    B --> C{enableUsbGroup value}
    C -->|true or false| D[DataManager::setEnableUsbGroup]
    D --> E[videowidget::onChangeDev]
    E --> F{DataManager::isEnableUsbGroup}
    F -->|false or groupNum == 1| G[Legacy device-based switching]
    F -->|true and groupNum > 1| H[USB group-based switching via getUSBCameraGroup]
    H --> I[switchCamera using group representatives]
    G --> I
Loading

File-Level Changes

Change Details Files
Make camera switching logic conditional on USB grouping configuration and support group-based cycling.
  • Wrap existing camera switching logic in a branch used when USB grouping is disabled (single group case).
  • When USB grouping is enabled and exactly two groups exist, switch between the first device of each group based on the current active device.
  • When USB grouping is enabled and more than two groups exist, cycle the active camera through the first device of each group, handling wrap-around and empty-current-device cases.
  • Preserve existing behavior for zero devices, still setting devStatus to NOCAM and showing the no-camera UI.
src/src/videowidget.cpp
Introduce helper to compute USB camera groups from v4l2 device list.
  • Add getUSBCameraGroup method that groups v4l2 devices by their location field into a QVector of pairs: location string and list of devices for that location.
  • Return the number of groups found via the size of the vector.
src/src/videowidget.cpp
src/src/videowidget.h
Add configuration flag and plumbing to enable or disable USB camera grouping via DConfig.
  • Extend DataManager with m_enableUsbGroup flag plus getter and setter for USB grouping enablement.
  • Read the enableUsbGroup key from DConfig in main(), log its value, and store it in DataManager if present.
src/src/basepub/datamanager.h
src/main.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The getUSBCameraGroup return value is documented as 0 成功 其他 失败, but it actually returns the number of groups (vGroupData.count()); consider updating the comment or changing the return semantics to avoid confusion.
  • The camera-switching logic for grouped and ungrouped devices has a lot of duplicated patterns (e.g. handling no devices and cycling to the next item); extracting a shared helper or normalizing on an index-based iteration would make this easier to maintain.
  • When groupNum == 2 you use a different branch than for other groupNum > 1 values even though the selection logic is very similar; it may be clearer to unify the code path for all groupNum >= 2 and just rely on vGroupData.count().
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `getUSBCameraGroup` return value is documented as `0 成功 其他 失败`, but it actually returns the number of groups (`vGroupData.count()`); consider updating the comment or changing the return semantics to avoid confusion.
- The camera-switching logic for grouped and ungrouped devices has a lot of duplicated patterns (e.g. handling no devices and cycling to the next item); extracting a shared helper or normalizing on an index-based iteration would make this easier to maintain.
- When `groupNum == 2` you use a different branch than for other `groupNum > 1` values even though the selection logic is very similar; it may be clearer to unify the code path for all `groupNum >= 2` and just rely on `vGroupData.count()`.

## Individual Comments

### Comment 1
<location path="src/src/videowidget.h" line_range="429" />
<code_context>
+     * @param vGroupData 分组
+     * @return 0 成功 其他 失败
+     */
+    int getUSBCameraGroup(v4l2_device_list_t *devlist, QVector<QPair<QString, QVector<v4l2_dev_sys_data_t *>>> &vGroupData);
+
     /**
</code_context>
<issue_to_address>
**issue (bug_risk):** The documented return semantics for getUSBCameraGroup disagree with the implementation.

The comment documents a 0/非0 success/failure contract, but the function actually returns `vGroupData.count()`, where 0 means “no groups” and a positive value is the number of groups. Please either align the implementation with the documented contract or update the comment to state that the return value is the number of USB groups found (0 if none).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@lichaofan2008 lichaofan2008 force-pushed the release/eagle branch 4 times, most recently from 90e0712 to 3bd6ba0 Compare March 13, 2026 05:32
Add the logic for switching cameras by USB groups.
增加按USB分组切换摄像头的逻辑。
代码来自xiwo分支。
@deepin-ci-robot
Copy link

deepin pr auto review

代码审查报告

1. 语法与逻辑

  1. 空指针检查顺序

    • videowidget::onChangeDev() 中,get_device_list() 返回值检查在调用之后,存在潜在空指针解引用风险。
    • 建议:将空指针检查移至函数开头:
      v4l2_device_list_t *devlist = get_device_list();
      if (devlist == nullptr) {
          qWarning() << "get device list FAILED";
          return;
      }
  2. 字符串比较优化

    • videowidget::onChangeDev() 中多次使用 QString 构造和比较,效率较低:
      QString str1 = QString(devlist->list_devices[i].device);
      if (str != str1) { ... }
    • 建议:直接使用 const char* 比较:
      const char *curDev = devlist->list_devices[i].device;
      if (str != curDev) { ... }
  3. 分组逻辑重复

    • onChangeDev()groupNum == 1groupNum == 2 的逻辑存在大量重复代码。
    • 建议:提取公共逻辑为独立函数,减少代码重复。

2. 代码质量

  1. 数据结构选择

    • getUSBCameraGroup() 使用 QVector<QPair<QString, QVector<v4l2_dev_sys_data_t *>>> 存储分组数据,查找效率为 O(n)。
    • 建议:改用 QMap<QString, QVector<v4l2_dev_sys_data_t *>>,查找效率提升至 O(log n):
      QMap<QString, QVector<v4l2_dev_sys_data_t *>> groupMap;
      for (int i = 0; i < devlist->num_devices; i++) {
          QString location = QString(devlist->list_devices[i].location);
          groupMap[location].append(&devlist->list_devices[i]);
      }
  2. 命名规范

    • vGroupData 命名不够清晰,建议改为 cameraGroupsusbCameraGroups
    • getUSBCameraGroup 函数名应改为 groupUSBCameras 更符合动宾结构。
  3. 注释冗余

    • getUSBCameraGroup() 中关于数据结构选择的注释过长且包含无关信息。
    • 建议:简化注释,仅说明分组依据(location)。

3. 性能优化

  1. 减少临时对象

    • getUSBCameraGroup() 中多次构造 QString 对象。
    • 建议:使用 QString::fromUtf8()QLatin1String 优化字符串构造。
  2. 提前终止循环

    • onChangeDev() 中找到匹配设备后应立即终止循环,避免不必要的遍历。

4. 安全性

  1. 指针生命周期

    • vGroupData 存储 devlist 中设备的指针,需确保 devlist 生命周期长于 vGroupData
    • 建议:在注释中明确说明,或考虑深拷贝设备数据。
  2. 边界检查

    • getUSBCameraGroup() 未检查 devlist->num_devices 是否合法。
    • 建议:添加边界检查:
      if (devlist == nullptr || devlist->num_devices <= 0) {
          qWarning() << __func__ << "Invalid device list!";
          return 0;
      }

5. 其他建议

  1. 日志输出

    • 关键操作(如切换摄像头)应增加更详细的日志,便于调试。
  2. 单元测试

    • 建议为 getUSBCameraGroup()onChangeDev() 添加单元测试,覆盖以下场景:
      • 空设备列表
      • 单设备
      • 多设备同分组
      • 多设备不同分组

改进后的代码示例

int videowidget::groupUSBCameras(v4l2_device_list_t *devlist, QMap<QString, QVector<v4l2_dev_sys_data_t *>> &cameraGroups)
{
    if (devlist == nullptr || devlist->num_devices <= 0) {
        qWarning() << __func__ << "Invalid device list!";
        return 0;
    }

    for (int i = 0; i < devlist->num_devices; i++) {
        QString location = QString::fromUtf8(devlist->list_devices[i].location);
        cameraGroups[location].append(&devlist->list_devices[i]);
    }

    return cameraGroups.size();
}

总结

本次代码修改主要实现了USB摄像头分组功能,整体逻辑正确,但在性能优化、代码质量和安全性方面仍有改进空间。建议优先解决空指针检查和字符串比较问题,后续可考虑重构分组逻辑以提升可维护性。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lichaofan2008, max-lvs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@lichaofan2008
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Mar 13, 2026

This pr force merged! (status: unstable)

@deepin-bot deepin-bot bot merged commit 6934da1 into linuxdeepin:release/eagle Mar 13, 2026
17 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants