Skip to content

V4L2Param_ParamControl

SweerItTer edited this page Feb 21, 2026 · 4 revisions

ParamControl API 文档

概述

ParamControl 是 utilsCore V4L2 参数模块的核心类,提供 V4L2 设备参数的查询、设置和控制功能。

职责

  • 查询 V4L2 设备的控制参数
  • 设置和获取 V4L2 参数值
  • 提供参数信息的缓存机制
  • 参数变更检测

适用场景

  • 摄像头参数调整(亮度、对比度、饱和度等)
  • 自动曝光和白平衡控制
  • 参数监控和日志记录
  • 动态参数调整

依赖关系

  • 依赖: V4L2 设备文件描述符
  • 被依赖: ParamProcessor, ParamLogger 等上层模块

类分析

ParamControl 类

职责与用途

ParamControl 是 V4L2 参数控制的封装类,提供:

  • 参数查询和信息获取
  • 参数设置和获取
  • 参数信息缓存
  • 参数变更检测

设计模式

  • RAII: 自动管理资源

V4L2ControlInfo 结构体

职责与用途

V4L2ControlInfo 存储 V4L2 控制参数的详细信息。

结构体定义

struct V4L2ControlInfo {
    __u32 id = 0;              // 控制ID
    std::string name = "";      // 控制名称
    int32_t min = 0;           // 最小值
    int32_t max = 0;           // 最大值
    int32_t step = 0;          // 步进值
    uint32_t type = 0;         // 控制类型(值调整/状态开关)
    int32_t current = 0;        // 当前值
};

字段说明

字段 类型 默认值 说明
id __u32 0 V4L2 控制ID(如 V4L2_CID_BRIGHTNESS)
name string "" 控制名称
min int32_t 0 最小值
max int32_t 0 最大值
step int32_t 0 步进值
type `uint32_t 0 控制类型(值调整/状态开关)
current int32_t 0 当前值

公共 API 方法

构造函数

explicit ParamControl(const std::string& devicePath);
explicit ParamControl(int externalFd);
~ParamControl();

参数说明:

  • devicePath (输入): V4L2 设备路径(如 "/dev/video0")
  • externalFd (输入): 外部文件描述符

返回值: 无

所有权归属:

  • devicePath 构造: ParamControl 打开设备 fd,负责关闭
  • externalFd 构造: ParamControl 不负责关闭 fd

注意事项:

  1. 构造时会查询所有可用的控制参数
  2. devicePath 构造会打开设备并拥有 fd
  3. externalFd 构造使用外部 fd,不负责关闭
  4. fd 必须有效且已打开

使用例程:

// 使用设备路径构造(ParamControl 负责打开和关闭)
ParamControl paramControl("/dev/video0");

// 使用外部 fd 构造(不负责关闭)
int camera_fd = open("/dev/video0", O_RDWR);
ParamControl paramControl(cameraFd);
// ...
close(camera_fd);  // 调用者负责关闭

setControl() - 设置控制参数值

bool setControl(__u32 id, int32_t value);

参数说明:

  • id (输入): 控制ID(如 V4L2_CID_BRIGHTNESS)
  • value (输入): 要设置的值

返回值:

  • true: 成功
  • false: 失败

所有权归属: 无所有权转移

注意事项:

  1. 值必须在 min 和 max 范围内
  2. 某些控制可能被禁用
  3. 设置后会自动更新 current 字段

使用例程:

ParamControl paramControl("/dev/video0");

// 设置亮度
if (paramControl.setControl(V4L2_CID_BRIGHTNESS, 50)) {
    printf("Brightness set to 50\n");
}

// 设置曝光
if (paramControl.setControl(V4L2_CID_EXPOSURE_ABSOLUTE, 100)) {
    printf("Exposure set to 100\n");
}

getControl() - 获取控制参数值

bool getControl(__u32 id, int32_t& value) const;

参数说明:

  • id (输入): 控制ID
  • value (输出): 控制参数值

返回值:

  • true: 成功
  • false: 失败

所有权归属:

  • 返回值由调用者持有

注意事项:

  1. 控制ID 必须有效
  2. 如果控制不存在,返回 false
  3. 使用前检查返回值

使用例程:

ParamControl paramControl("/dev/video0");

int32_t brightness;
if (paramControl.getControl(V4L2_CID_BRIGHTNESS, brightness)) {
    printf("Current brightness: %d\n", brightness);
}

int32_t exposure;
if (paramControl.getControl(V4L2_CID_EXPOSURE_ABSOLUTE, exposure)) {
    printf("Current exposure: %d\n", exposure);
}

queryControl() - 查询单个控制参数

bool queryControl(__u32 id);

参数说明:

  • id (input): 控制ID

返回值:

  • true: 控制存在
  • false: 控制不存在

注意事项:

  1. 查询单个控制参数是否存在
  2. 不返回参数信息
  3. 用于验证控制ID 是否有效

queryAllControls() - 查询所有控制参数

ControlInfos queryAllControls() const;

参数说明: 无

返回值:

  • 成功: 返回所有控制参数的列表(ControlInfos = std::vector)
  • 失败: 返回空列表

所有权归属:

  • 返回的列表由调用者持有
  • ParamControl 内部缓存参数信息

注意事项:

  1. 返回类型为 ControlInfosstd::vector<V4L2ControlInfo>
  2. 每个控制包含 id, name, min, max, step, type, current 字段
  3. 首次调用时会查询设备,后续调用使用缓存

使用例程:

ParamControl paramControl("/dev/video0");

// 查询所有控制参数
auto controls = paramControl.queryAllControls();

for (const auto& ctrl : controls) {
    printf("%s: id=%u, range=[%d, %d], current=%d, type=%u\n", 
           ctrl.name.c_str(), ctrl.id, ctrl.min, ctrl.max, ctrl.current, ctrl.type);
}

// 查找曝光控制
for (const auto& ctrl : controls) {
    if (ctrl.name.find("Exposure") != std::string::npos) {
        printf("Found exposure control: %s (id=%u)\n", ctrl.name.c_str(), ctrl.id);
    }
}

diffParamInfo() - 对比参数差异(静态方法)

static ControlInfos diffParamInfo(const ControlInfos& oldInfo, const ControlInfos& newInfo);

参数说明:

  • oldInfo (输入): 旧的参数信息列表
  • newInfo (输入): 新的参数信息列表

返回值: 返回发生变化的控制参数列表

所有权归属: 无所有权转移

注意事项:

  1. 静态方法,不需要实例
  2. 对比 current 字段是否变化
  3. 返回值包含 current 不同的 V4L2ControlInfo

使用例程:

ParamControl paramControl("/dev/video0");

// 第一次查询
auto controls1 = paramControl.queryAllControls();

// 修改参数
paramControl.setControl(V4L2_CID_BRIGHTNESS, 50);

// 第二次查询
auto controls2 = paramControl.queryAllControls();

// 对比差异
auto diff = ParamControl::diffParamInfo(controls1, controls2);

for (const auto& ctrl : diff) {
    printf("Changed: %s: %d → %d\n", ctrl.name.c_str(), ctrl.min, ctrl.max);
}

isSwitchControl() - 判断是否为开关控制(静态方法)

static bool isSwitchControl(const V4L2ControlInfo& info);

参数说明:

  • info (输入): V4L2ControlInfo 引用

返回值:

  • true: 是开关控制(如 V4L2_CID_POWER_LINE_FREQUENCY)
  • false: 不是开关控制

注意事项:

  1. 静态方法,不需要实例
  2. 根据 type 字段判断

isValueControl() - 判断是否为值控制(静态方法)

static bool isValueControl(const V4L2ControlInfo& info);

参数说明- info (输入): V4L2ControlInfo 引用

返回值:

  • true: 是值控制(如 V4L2_CID_BRIGHTNESS)
  • false: 不是值控制

注意事项:

  1. 静态方法,不需要实例
  2. 根据 type 字段判断

内部实现

数据成员

class ParamControl {
private:
    int fd_ = -1;               // V4L2 设备文件描述符
    bool ownsFd_ = false;       // 是否拥有 fd(构造时决定)
};

fd 所有权管理

  • devicePath 构造: ownsFd_ = true,析构时自动关闭 fd
  • externalFd 构造: ownsFd_ = false,析构时不关闭 fd
  • 调用者负责管理 externalFd 的生命周期

典型使用场景

场景 1: VisionPipeline 中的使用

// src/pipeline/visionPipeline.cpp:178-189
void VisionPipeline::Impl::v4l2ControllerInit() {
    int cameraFd = camera->getDeviceFd();
    v4l2Controller = std::make_unique<ParamControl>(cameraFd);

    currentControls_ = v4l2Controller->queryAllControls();
    size_t size = currentControls_.size();
    for(size_t index=0; index<size; ++index){
        auto& controlInfo = currentControls_[index];
        if (controlInfo.id != V4L2_CID_EXPOSURE) continue;
        exposureIdInControls = index;
        break;
    }
}

场景 2: 设置摄像头参数

ParamControl paramControl("/dev/video0");

// 设置镜像模式
paramControl.setControl(V4L2_CID_HFLIP, 1);  // 水平镜像
paramControl.setControl(V4L2_CID_VFLIP, 0);  // 不垂直镜像

// 设置曝光百分比(需要计算实际值)
auto controls = paramControl.queryAllControls();
for (const auto& ctrl : controls) {
    if (ctrl.id == V4L2_CID_EXPOSURE_ABSOLUTE) {
        int32_t target = ctrl.min + (ctrl.max - ctrl.min) * percentage / 100;
        paramControl.setControl(ctrl.id, target);
    }
}

场景 3: 参数变更检测

ParamControl paramControl("/dev/video0");

// 保存原始值
auto controls_old = paramControl.queryAllControls();

// 修改参数
paramControl.setControl(V4L2_CID_BRIGHTNESS, 50);

// 获取新值
auto controls_new = paramControl.queryAllControls();

// 检测变化
auto diff = ParamControl::diffParamInfo(controls_old, controls_new);
for (const auto& ctrl : diff) {
    printf("%s: %d → %d\n", ctrl.name.c_str(), ctrl.min, ctrl.current);
}

注意事项

  1. 构造方式: 两种构造方式(devicePath 和 externalFd),所有权管理不同
  2. fd 所有权: devicePath 构造时 ParamControl 拥有 fd,externalFd 构造时调用者拥有 fd
  3. 参数范围: 设置值必须在 min 和 max �范围内
  4. 控制类型: 使用 isSwitchControl() 和 isValueControl() 判断控制类型
  5. 缓存机制: queryAllControls() 使用缓存,首次调用时查询设备
  6. 线程安全: ParamControl 本身不是线程安全的,需要外部同步
  7. 错误处理: 所有方法返回 bool,调用者需要检查返回值
  8. 参数名称: name 字段可用于查找特定参数

相关文档


参考资料

主页

API 文档

DMA 模块

DRM 模块

NET 模块

V4L2 模块

V4L2Param 模块

RGA 模块

MPP 模块

Sys 模块

Mouse 模块

Utils 模块

Clone this wiki locally