Skip to content

fix: 将摄像头卡片过滤关键字改为 DConfig 配置#481

Open
Resurgamz wants to merge 1 commit into
linuxdeepin:release/eaglefrom
Resurgamz:release/eagle
Open

fix: 将摄像头卡片过滤关键字改为 DConfig 配置#481
Resurgamz wants to merge 1 commit into
linuxdeepin:release/eaglefrom
Resurgamz:release/eagle

Conversation

@Resurgamz
Copy link
Copy Markdown

@Resurgamz Resurgamz commented Jun 5, 2026

将原先在 enum_v4l2_devices 中硬编码的摄像头卡片关键字迁移到
org.deepin.camera.encode.json 的 CardKeywords 配置项中,并在启动时
从 DConfig 读取后动态传递给 libcam 使用,支持后续通过配置增删过滤关键字。

Log: 将摄像头卡片过滤关键字设置为DConfig配置

Summary by Sourcery

Move camera card filter keywords from hardcoded v4l2 enumeration logic to a dynamic, DConfig-driven configuration and propagate them into libcam for runtime filtering.

Enhancements:

  • Add libcam APIs and internal storage to set and retrieve camera card keywords at runtime.
  • Load CardKeywords from org.deepin.camera.encode DConfig on startup and pass them to libcam for device filtering.
  • Update v4l2 device enumeration to filter devices based on the configured card keywords instead of hardcoded strings.
  • Extend the encode configuration JSON to define CardKeywords used for camera card filtering.

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Resurgamz

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

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Jun 5, 2026

Reviewer's Guide

This PR moves camera card filter keywords from being hardcoded in the V4L2 device enumeration to a DConfig-driven configuration (CardKeywords), adding a libcam API to receive keywords from the Qt main process and using them to skip matching V4L2 devices.

Sequence diagram for DConfig-driven camera card keyword filtering

sequenceDiagram
    participant MainProcess
    participant DConfig
    participant libcam_camview
    participant V4L2Devices

    MainProcess->>DConfig: value(CardKeywords)
    DConfig-->>MainProcess: QStringList
    MainProcess->>libcam_camview: set_card_keywords(keywords, count)

    MainProcess->>V4L2Devices: enum_v4l2_devices()
    V4L2Devices->>libcam_camview: get_card_keywords(count)
    libcam_camview-->>V4L2Devices: const char** card_keywords

    loop each V4L2 device
        V4L2Devices->>V4L2Devices: [card matches card_keywords]
        alt match
            V4L2Devices->>V4L2Devices: m_v4l2_close(fd)
            V4L2Devices->>V4L2Devices: continue
        else no match
            V4L2Devices->>V4L2Devices: keep device
        end
    end
Loading

File-Level Changes

Change Details Files
Introduce dynamic storage and accessors for camera card filter keywords in libcam.
  • Add global storage for card keywords and count in camview.c with proper allocation and cleanup logic
  • Implement set_card_keywords to copy keyword strings into internal storage and clear_card_keywords to free them
  • Implement get_card_keywords to expose the stored keywords and their count to other libcam components
  • Declare the new set_card_keywords and get_card_keywords APIs in camview.h with documentation comments
libcam/libcam/camview.c
libcam/libcam/camview.h
Load CardKeywords from DConfig at startup and pass them into libcam.
  • Include QByteArray and QVector in main.cpp to manage UTF-8 conversions and C string arrays
  • Read the CardKeywords key from DConfig if present, convert QStringList to UTF-8 byte arrays, and build a const char* array
  • Call set_card_keywords with the constructed C string array and log the resulting keyword count
src/main.cpp
Use configured card keywords to filter out matching V4L2 devices instead of hardcoded checks.
  • Call get_card_keywords in enum_v4l2_devices to retrieve configured keywords and their count
  • Iterate over keywords and mark devices whose v4l2_cap.card contains any keyword as filtered
  • Close the device fd and continue enumeration when a device matches configured keywords, before existing project_id-specific filtering
libcam/libcam_v4l2core/v4l2_devices.c
Introduce CardKeywords configuration entry in camera encode JSON config.
  • Add CardKeywords entry to org.deepin.camera.encode.json to hold the list of configurable camera card filter keywords
src/assets/org.deepin.camera.encode.json

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
Copy Markdown

@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 left some high level feedback:

  • In enum_v4l2_devices(), get_card_keywords() is called on every directory entry; consider moving the call (and associated keyword lookup setup) outside the loop so the keyword array is fetched once per enumeration instead of once per device.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In enum_v4l2_devices(), get_card_keywords() is called on every directory entry; consider moving the call (and associated keyword lookup setup) outside the loop so the keyword array is fetched once per enumeration instead of once per device.

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.

  将原先在 enum_v4l2_devices 中硬编码的摄像头卡片关键字迁移到
  org.deepin.camera.encode.json 的 CardKeywords 配置项中,并在启动时
  从 DConfig 读取后动态传递给 libcam 使用,支持后续通过配置增删过滤关键字。

Log: 将摄像头卡片过滤关键字设置为DConfig配置
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX,我已经仔细审查了你提供的Git Diff。本次代码变更的主要目的是通过DConfig配置一组关键字(CardKeywords),在枚举V4L2设备时,如果设备的card名称包含这些关键字,则将其过滤掉(通常用于隐藏红外摄像头等特定设备)。

整体来看,代码逻辑清晰,C和C++的边界处理得当,内存管理也考虑了空指针和释放问题。但是,在代码性能、代码质量和代码安全方面,还有一些可以改进和优化的空间。以下是详细的审查意见:

1. 代码性能

问题:strstr 大小写敏感导致配置项极易失效

  • 位置: libcam/libcam_v4l2core/v4l2_devices.c 第355行
    if(card_keywords[i] != NULL && strstr((const char *)v4l2_cap.card, card_keywords[i]) != NULL)
  • 分析: strstr 是大小写敏感的。而在配置文件 org.deepin.camera.encode.json 中,你的关键字包含了 "IR Cam", "Infrared", "ir_cam" 等。硬件厂商在填写 v4l2_cap.card 时,大小写往往不规范(比如写成 ir CAM, INFRARED 等)。这会导致由于大小写不匹配而过滤失效。
  • 改进意见: 建议使用大小写不敏感的字符串匹配,或者在匹配前将两者统一转换为小写/大写。可以使用 strcasestr(需定义 _GNU_SOURCE),或者自己实现一个简单的转小写比较逻辑。

2. 代码质量

问题一:C++侧的悬垂指针风险

  • 位置: src/main.cpp 第215-224行
    QVector<QByteArray> keywordBytes;
    QVector<const char *> keywordData;
    // ... 循环填充 ...
    set_card_keywords(keywordData.data(), keywordData.size());
  • 分析: keywordData 存储的是 keywordBytesQByteArray 对象的内部数据指针(constData())。虽然目前 set_card_keywords 内部使用了 strdup 进行了深拷贝,所以当前代码是安全的。但是,这种将容器内部指针传递给外部的写法非常脆弱。如果未来有人修改 set_card_keywords 忘记做深拷贝,或者在这段代码后面对 keywordBytes 进行了追加/修改导致重新分配内存,就会产生严重的悬垂指针问题。
  • 改进意见: 建议添加明确的注释说明 set_card_keywords 内部做了深拷贝,或者更安全地直接在循环中调用 C 接口进行追加(如果后续考虑将 set_card_keywords 拆分成 clear + add 的设计)。

问题二:C与C++侧对空格字符串的重复过滤

  • 位置: src/src/globalutils.cpp 第111行 与 libcam/libcam/camview.c 第127行
  • 分析: C++侧的 parseStringListConfig 已经使用 keyword.trimmed().isEmpty() 过滤了纯空格字符串;而C侧的 is_invalid_card_keyword 又使用 isspace 重新遍历检查了一遍纯空格字符串。虽然双重防御不是坏事,但这增加了维护成本。
  • 改进意见: 建议统一在一侧做合法性校验即可。既然C语言是最终的守门员,C++侧可以只做基本的JSON解析,去掉C++侧的 trimmed().isEmpty() 检查,或者保留C++侧检查,简化C侧检查为只判断 NULL\0

问题三:C++侧的废弃API使用

  • 位置: src/src/globalutils.cpp 第94行、第98行
    if (value.type() == QVariant::StringList) {
    // ...
    } else if (value.type() == QVariant::List) {
  • 分析: 在 Qt5 及以上版本中,QVariant::type() 已被标记为废弃,建议使用 QVariant::userType() 或与特定类型 ID 比较。
  • 改进意见: 改为 value.userType() == QMetaType::QStringListvalue.userType() == QMetaType::QVariantList。同样,item.type() 也应改为 item.userType() == QMetaType::QString

3. 代码安全

问题一:isspace 的未定义行为风险

  • 位置: libcam/libcam/camview.c 第133行
    if (!isspace((unsigned char)*p)) {
  • 分析: 这里的强制类型转换 (unsigned char) 非常好!这是标准库字符处理函数的正确用法。因为 isspace(以及其他 isxxx 函数)如果接收到负值的 char(某些扩展ASCII字符),会导致未定义行为。你在代码中已经做了正确的处理,这里提出是表扬并确认这个写法是安全且必须保留的。

问题二:strdup 的内存分配失败检查

  • 位置: libcam/libcam/camview.c 第176行
    card_keywords[card_keyword_count] = strdup(keywords[i]);
    if (card_keywords[card_keyword_count] != NULL) {
        card_keyword_count++;
    }
  • 分析:strdup 返回 NULL 时(内存不足),当前逻辑是静默跳过该关键字,继续处理下一个。
  • 改进意见: 虽然在嵌入式或极度缺内存的情况下这是合理的降级,但最好加上一行 fprintf(stderr, "deepin-camera: failed to duplicate card keyword\n"); 打印警告,与上面 calloc 失败的日志保持一致,方便排查问题。

4. 修改建议代码示例

针对上述主要问题,提供以下修改后的代码片段供参考:

v4l2_devices.c (引入大小写不敏感匹配):

// 如果平台支持 GNU extension,可以直接使用 strcasestr
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>

// ... 在 enum_v4l2_devices 函数中 ...
        int is_card_keyword_device = 0;
        for (int i = 0; i < num_card_keywords; i++) {
            if(card_keywords[i] != NULL && strcasestr((const char *)v4l2_cap.card, card_keywords[i]) != NULL) {
                is_card_keyword_device = 1;
                break;
            }
        }

globalutils.cpp (修复废弃API):

QStringList GlobalUtils::parseStringListConfig(const QVariant &value)
{
    QStringList rawList;

    // 使用 userType 替代废弃的 type()
    if (value.userType() == QMetaType::QStringList) {
        rawList = value.toStringList();
    } else if (value.userType() == QMetaType::QVariantList) {
        const QVariantList variantList = value.toList();
        for (const QVariant &item : variantList) {
            if (item.userType() == QMetaType::QString) {
                rawList.append(item.toString());
            }
        }
    } else {
        return QStringList();
    }

    QStringList result;
    for (const QString &keyword : rawList) {
        if (!keyword.trimmed().isEmpty()) {
            result.append(keyword);
        }
    }
    return result;
}

camview.c (补充错误日志):

        card_keywords[card_keyword_count] = strdup(keywords[i]);
        if (card_keywords[card_keyword_count] != NULL) {
            card_keyword_count++;
        } else {
            fprintf(stderr, "deepin-camera: failed to duplicate card keyword: %s\n", keywords[i]);
        }

main.cpp (添加安全注释):

    if (dconfig && dconfig->isValid() && dconfig->keyList().contains("CardKeywords")) {
        QStringList cardKeywords = GlobalUtils::parseStringListConfig(dconfig->value("CardKeywords"));
        QVector<QByteArray> keywordBytes;
        QVector<const char *> keywordData;
        keywordBytes.reserve(cardKeywords.size());
        keywordData.reserve(cardKeywords.size());
        for (const QString &keyword : cardKeywords) {
            keywordBytes.append(keyword.toUtf8());
            keywordData.append(keywordBytes.last().constData());
        }
        qInfo() << "card keywords:" << cardKeywords;
        // 注意: set_card_keywords 内部对传入的字符串使用了 strdup 进行深拷贝,
        // 因此虽然 keywordData 是临时指针,在此处生命周期结束后不会导致悬垂指针问题。
        set_card_keywords(keywordData.data(), keywordData.size());
    }

希望这些审查意见对你有所帮助!如果有任何疑问,欢迎继续探讨。

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.

2 participants