如何在QT C++中将QImage序列保存为视频?
解决QMediaRecorder无法直接录制带叠加层视频的问题
QMediaRecorder确实只能直接录制摄像头的原始流,没法中途插入帧处理。要实现“抓帧→加叠加层→存视频”的需求,得绕开QMediaRecorder的直接录制逻辑,改用自定义帧捕获+处理+写入的流程,下面是两种可行的实现方式:
方法一:Qt原生模块实现(推荐)
用QCamera捕获帧,自定义QAbstractVideoSurface处理叠加层,最后用QVideoWriter写入视频文件。
步骤1:实现自定义视频表面
继承QAbstractVideoSurface来接收摄像头的每一帧,在present方法里完成叠加层绘制:
#include <QAbstractVideoSurface> #include <QVideoFrame> #include <QPainter> class OverlayVideoSurface : public QAbstractVideoSurface { Q_OBJECT public: explicit OverlayVideoSurface(QObject *parent = nullptr) : QAbstractVideoSurface(parent) {} // 声明支持的像素格式 QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const override { Q_UNUSED(handleType); return {QVideoFrame::Format_RGB32, QVideoFrame::Format_ARGB32}; } // 处理每一帧 bool present(const QVideoFrame &frame) override { if (!frame.isValid()) return false; // 复制帧并映射到内存 QVideoFrame cloneFrame(frame); if (!cloneFrame.map(QAbstractVideoBuffer::ReadOnly)) return false; QImage image(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(), QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat())); cloneFrame.unmap(); // 添加叠加层(示例:居中红色文字) QPainter painter(&image); painter.setPen(Qt::red); painter.setFont(QFont("Arial", 20)); painter.drawText(image.rect(), Qt::AlignCenter, "实时叠加内容"); painter.end(); // 发送处理后的帧 emit frameProcessed(QVideoFrame(image)); return true; } signals: void frameProcessed(const QVideoFrame &frame); };
步骤2:整合摄像头与视频写入器
在主逻辑里连接摄像头、自定义表面和QVideoWriter:
#include <QCamera> #include <QVideoWriter> #include <QVideoEncoderSettings> // 初始化摄像头 QCamera *camera = new QCamera(this); camera->setCaptureMode(QCamera::CaptureVideo); // 实例化自定义表面 OverlayVideoSurface *surface = new OverlayVideoSurface(this); camera->setViewfinderSurface(surface); // 配置视频写入器 QVideoWriter writer; QString outputPath = "./record_with_overlay.mp4"; QVideoEncoderSettings encodeSettings; encodeSettings.setCodec("video/mp4"); // 根据系统支持调整,可通过QVideoWriter::supportedCodecs()查看 encodeSettings.setResolution(640, 480); // 匹配摄像头分辨率 encodeSettings.setFrameRate(30.0); writer.setFileName(outputPath); writer.setSettings(encodeSettings); // 绑定处理后的帧到写入器 connect(surface, &OverlayVideoSurface::frameProcessed, this, [&](const QVideoFrame &frame){ if (writer.isOpen()) { writer.write(frame); } }); // 启动录制 if (writer.open()) { camera->start(); } // 停止录制时记得调用 // camera->stop(); // writer.close();
方法二:结合FFmpeg实现(适合复杂编码需求)
如果Qt原生的QVideoWriter满足不了编码格式要求,可以调用FFmpeg库来完成视频编码。核心逻辑是:
- 用
QCamera抓帧转成RGB/YUV格式 - 把帧数据传给FFmpeg的编码器
- 写入封装好的视频文件
这种方式需要自己处理FFmpeg的编码上下文、流配置等,灵活性更高但代码量更大。
注意事项
- 确保
QVideoWriter的编码格式是系统支持的,Windows、macOS、Linux的支持列表可能不同 - 帧格式转换时要注意像素格式匹配,避免出现花屏、颜色失真
- 录制结束必须调用
writer.close(),否则视频文件可能损坏
内容的提问来源于stack exchange,提问作者lilsoujaaa
相关产品推荐
相关产品推荐

