You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cv::VideoWriter无法写入帧至MKV文件的问题排查求助

问题分析与解决方案

核心问题排查

1. 错误创建VideoCapture抢占文件资源

你代码中创建了cv::VideoCapture cap(out_vid_name + ".mkv", cv::CAP_FFMPEG);,这会尝试读取你正在写入的MKV文件,导致文件句柄被占用,VideoWriter无法正常写入帧数据。这是无帧写入的最直接原因。

2. 未检查VideoWriter初始化状态

OpenCV的VideoWriter如果初始化失败(比如编码器不支持、参数不匹配)会静默失败,后续write()调用不会产生任何效果。你没有检查writer.isOpened()的返回值,无法及时发现初始化问题。

3. 未明确指定FFmpeg作为编码后端

你的VideoWriter构造函数未指定编码后端,OpenCV可能默认使用了不支持FFV1编码的后端(如V4L2),导致无法生成FFV1编码的MKV文件。

4. 帧格式/尺寸不匹配风险

虽然imwrite正常,但需确认写入的Mat是否为3通道BGR格式(对应CV_8UC3)——你构造Writer时最后一个参数设为true(彩色模式),如果帧是单通道或其他格式,Writer会拒绝写入。


分步解决方案

1. 删除无效的VideoCapture代码

直接移除cv::VideoCapture cap(out_vid_name + ".mkv", cv::CAP_FFMPEG);这一行,释放文件资源给VideoWriter使用。

2. 检查VideoWriter初始化状态

构造Writer后立即检查是否成功打开,添加错误处理:

cv::VideoWriter writer(out_vid_name + ".mkv", cv::CAP_FFMPEG, cv::VideoWriter::fourcc('F','F','V','1'), cam_fps, frame_double_size, true);
if (!writer.isOpened()) {
    std::cerr << "Failed to initialize VideoWriter! Check encoder support and parameters." << std::endl;
    return -1; // 添加退出逻辑,避免后续无效执行
}

3. 明确指定FFmpeg后端

在构造VideoWriter时,第二个参数传入cv::CAP_FFMPEG,强制使用FFmpeg API编码,确保支持FFV1和MKV容器:

// 修正后的构造函数
cv::VideoWriter writer(
    out_vid_name + ".mkv", 
    cv::CAP_FFMPEG,  // 明确指定FFmpeg后端
    cv::VideoWriter::fourcc('F','F','V','1'), 
    cam_fps, 
    frame_double_size, 
    true
);

4. 验证并修正帧格式与尺寸

在写入前添加帧信息验证,确保与Writer设置一致:

cv::Mat frame = doubleSaveFrame->getHost();
// 打印帧尺寸(确认和frame_double_size一致:3840x1080)
std::cout << "Frame size: " << frame.size() << std::endl;
// 打印帧格式(CV_8UC3对应值为16,彩色BGR)
std::cout << "Frame type: " << frame.type() << std::endl;

// 格式/尺寸不匹配时自动修正
if (frame.channels() != 3) {
    cv::cvtColor(frame, frame, cv::COLOR_GRAY2BGR);
}
if (frame.size() != frame_double_size) {
    cv::resize(frame, frame, frame_double_size);
}

// 执行写入
writer.write(frame);

5. 确认FFmpeg支持FFV1

如果上述步骤仍无效,检查OpenCV编译时是否启用FFmpeg,且FFmpeg库支持FFV1编码。可通过以下命令验证:

ffmpeg -codecs | grep FFV1

若输出包含FFV1且标记为E(编码支持),则说明FFmpeg支持该编码;否则需重新编译FFmpeg或OpenCV,启用FFV1编码支持。


修正后的完整写入循环示例

// 初始化Writer并检查状态
cv::VideoWriter writer(
    out_vid_name + ".mkv", 
    cv::CAP_FFMPEG, 
    cv::VideoWriter::fourcc('F','F','V','1'), 
    cam_fps, 
    frame_double_size, 
    true
);
if (!writer.isOpened()) {
    std::cerr << "VideoWriter initialization failed!" << std::endl;
    return -1;
}

while (controller->running && ros::ok())
{
    std::shared_lock<std::shared_mutex> guard(doubleSaveFrame->mtx);
    doubleSaveFrame->cond_var.wait(guard, [&]{ return doubleSaveFrame->cond_bool_save; });
    doubleSaveFrame->cond_bool_save = false;

    std_msgs::String msg;
    msg.data = std::to_string(frame_count);
    frame_count++;
    frame_pub.publish(msg);

    cv::Mat frame = doubleSaveFrame->getHost();
    // 验证并修正帧格式/尺寸
    if (frame.channels() != 3) {
        cv::cvtColor(frame, frame, cv::COLOR_GRAY2BGR);
    }
    if (frame.size() != frame_double_size) {
        cv::resize(frame, frame, frame_double_size);
    }

    // 写入帧
    writer.write(frame);

    // 打印调试信息
    std::cout << "Written frame " << frame_count 
              << ", size: " << frame.size() 
              << ", type: " << frame.type() << std::endl;

    // 修正imwrite路径(添加根目录/)
    cv::imwrite("/home/Documents/camera/imwritefun" + std::to_string(frame_count) + ".JPG", frame);
}
writer.release();

内容的提问来源于stack exchange,提问作者user18953215

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:25:12