Skip to content

V4L2_Exception

SweerItTer edited this page Feb 1, 2026 · 3 revisions

V4L2Exception API 文档

概述

V4L2Exception 是 utilsCore V4L2 模块的异常类,提供 V4L2 操作错误的异常处理机制。

职责

  • 封装 V4L2 操作错误
  • 提供错误信息
  • 支持异常抛出和捕获
  • 错误码和错误消息

适用场景

  • V4L2 操作失败时的异常处理
  • 错误诊断和调试
  • 异常安全的代码设计

依赖关系

  • 依赖: C++ STL
  • 被依赖: CameraController, Frame 等所有 V4L2 相关类

类分析

V4L2Exception 类

职责与用途

V4L2Exception 是 V4L2 异常的封装类,提供:

  • 错误码和错误消息
  • 异常抛出和捕获
  • 详细的错误信息
  • 静态日志方法

设计模式

  • 异常模式: 标准异常类

公共 API 方法

构造函数

V4L2Exception(const std::string& msg, int err = 0);

参数说明:

  • msg (输入): 错误消息
  • err (输入): 错误码(可选,默认 0)

返回值: 无

所有权归属:

  • V4L2Exception 持有错误消息的所有权

注意事项:

  1. 异常对象会在抛出时复制
  2. 使用标准异常接口
  3. 错误码通常是 errno
  4. 错误码会被包含在 what() 返回的消息中

使用例程:

// 抛出异常(无错误码)
throw V4L2Exception("Failed to open device");

// 抛出异常(带错误码)
throw V4L2Exception("Failed to open device", errno);

what() - 获取错误消息

const char* what() const noexcept override;

参数说明: 无

返回值: 错误消息(包含错误码描述)

所有权归属:

  • 只读访问

注意事项:

  1. 标准异常接口
  2. 返回的指针在异常对象生命周期内有效
  3. 如果提供了错误码,消息格式为 "msg: strerror(err)"

使用例程:

try {
    // ... V4L2 操作
} catch (const V4L2Exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
    // 输出: "Failed to open device: Permission denied" (如果有错误码)
}

log() - 静态日志方法

static void log(const std::string& msg, int err = 0);

参数说明:

  • msg (输入): 错误消息
  • err (输入): 错误码(可选,默认 0)

返回值: 无

所有权归属:

  • 无所有权转移

注意事项:

  1. 静态方法,不需要创建异常对象
  2. 直接将错误信息输出到 stderr
  3. 格式: [V4L2Exception] msg: strerror(err)

使用例程:

// 记录错误(无错误码)
V4L2Exception::log("Device not found");

// 记录错误(带错误码)
V4L2Exception::log("Failed to open device", errno);
// 输出: [V4L2Exception] Failed to open device: Permission denied

完整代码

class V4L2Exception : public std::runtime_error {
public:
    V4L2Exception(const std::string& msg, int err = 0)
        : std::runtime_error(msg + (err ? (": " + std::string(strerror(err))) : "")) {}

    static void log(const std::string& msg, int err = 0) {
        std::string full = msg;
        if (err) {
            full += ": ";
            full += strerror(err);
        }
        fprintf(stderr, "[V4L2Exception] %s\n", full.c_str());
    }
};

使用方式

抛出异常

// 抛出异常(无错误码)
if (fd < 0) {
    throw V4L2Exception("Failed to open device");
}

// 抛出异常(带错误码)
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
    throw V4L2Exception("Failed to query device capabilities", errno);
}

捕获异常

try {
    CameraController camera(cfg);
    camera.start();
} catch (const V4L2Exception& e) {
    fprintf(stderr, "V4L2 Error: %s\n", e.what());
} catch (const std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
}

使用日志方法

// 直接记录错误,不抛出异常
if (fd < 0) {
    V4L2Exception::log("Failed to open device", errno);
    return -1;
}

常见错误码

错误码 说明 常见原因
EBUSY 设备忙 设备已被其他进程打开
ENOENT 设备不存在 设备路径错误
EACCES 权限不足 没有访问设备的权限
EINVAL 参数无效 传入的参数不正确
ENOMEM 内存不足 系统内存不足
EIO IO 错误 设备通信失败
ENOTTY 不合适的 IO 设备不支持该操作

典型使用场景

场景 1: 设备打开失败

int fd = open(device.c_str(), O_RDWR);
if (fd < 0) {
    throw V4L2Exception("Failed to open device: " + device, errno);
}

场景 2: 查询能力失败

struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
    throw V4L2Exception("Failed to query device capabilities", errno);
}

场景 3: 格式设置失败

struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
fmt.fmt.pix.pixelformat = format;

if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
    throw V4L2Exception("Failed to set format", errno);
}

场景 4: 缓冲区分配失败

struct v4l2_requestbuffers req;
req.count = buffer_count;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_DMABUF;

if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
    throw V4L2Exception("Failed to request buffers", errno);
}

场景 5: 流操作失败

// 启动流
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
    throw V4L2Exception("Failed to start stream", errno);
}

// 停止流
if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) {
    throw V4L2Exception("Failed to stop stream", errno);
}

场景 6: 使用日志方法

// 直接记录错误
if (fd < 0) {
    V4L2Exception::log("Failed to open device", errno);
    return -1;
}

// 记录错误信息
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
    V4L2Exception::log("Failed to query device capabilities", errno);
    return -1;
}

注意事项

  1. 异常传播: 异常会沿着调用栈传播,直到被捕获
  2. 资源泄漏: 使用 RAII 确保资源正确释放
  3. 错误码: 错误码包含在 what() 返回的消息中
  4. 日志方法: log() 是静态方法,不抛出异常
  5. 异常安全: 确保代码是异常安全的
  6. 性能: 异常处理有性能开销,不要用于正常流程
  7. 文档: 记录可能抛出的异常
  8. what() 返回: 返回完整的错误消息(包含错误码描述)

相关文档


参考资料

主页

API 文档

DMA 模块

DRM 模块

NET 模块

V4L2 模块

V4L2Param 模块

RGA 模块

MPP 模块

Sys 模块

Mouse 模块

Utils 模块

Clone this wiki locally