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

如何在QML中为VideoSink添加MediaRecorder实现视频录制?

解决方案

Qt6的MediaRecorder确实无法直接在QML中绑定VideoSink作为录制源,因为它依赖QMediaCaptureSession来关联媒体输入。你需要在C++层的Producer类中集成录制逻辑,通过QMediaCaptureSession对接VideoSink的视频流,具体步骤如下:

1. 修改C++ Producer类,添加录制功能

扩展你的Producer类,加入QMediaCaptureSession、QMediaRecorder以及自定义视频源,用来传递VideoSink收到的帧:

头文件(Producer.h)

#ifndef PRODUCER_H
#define PRODUCER_H

#include <QObject>
#include <QVideoSink>
#include <QMediaCaptureSession>
#include <QMediaRecorder>
#include <QUrl>

class Producer : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVideoSink* videoSink READ videoSink WRITE setVideoSink NOTIFY videoSinkChanged)
    Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation NOTIFY outputLocationChanged)
public:
    explicit Producer(QObject *parent = nullptr);

    QVideoSink* videoSink() const;
    void setVideoSink(QVideoSink* sink);

    QUrl outputLocation() const;
    void setOutputLocation(const QUrl& location);

public slots:
    void startRecording();
    void stopRecording();
    bool isRecording() const;

signals:
    void videoSinkChanged();
    void outputLocationChanged();
    void recordingStateChanged(bool isRecording);

private slots:
    void onFrameReceived(const QVideoFrame& frame);

private:
    class VideoFrameSource : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QVideoFrame currentFrame READ currentFrame NOTIFY currentFrameChanged)
    public:
        explicit VideoFrameSource(QObject* parent = nullptr) : QObject(parent) {}
        QVideoFrame currentFrame() const { return m_frame; }

    public slots:
        void setFrame(const QVideoFrame& frame) {
            m_frame = frame;
            emit currentFrameChanged();
        }

    signals:
        void currentFrameChanged();

    private:
        QVideoFrame m_frame;
    };

    QVideoSink* m_videoSink = nullptr;
    QMediaCaptureSession m_captureSession;
    QMediaRecorder m_recorder;
    QUrl m_outputLocation;
    VideoFrameSource* m_videoSource = nullptr;
};

#endif // PRODUCER_H

实现文件(Producer.cpp)

#include "Producer.h"
#include <QMediaFormat>

Producer::Producer(QObject *parent)
    : QObject{parent}
{
    m_videoSource = new VideoFrameSource(this);
    m_captureSession.setVideoInput(m_videoSource);
    m_captureSession.setRecorder(&m_recorder);

    // 配置MP4录制格式,使用H264视频编码
    QMediaFormat format;
    format.setFileFormat(QMediaFormat::MP4);
    format.setVideoCodec(QMediaFormat::VideoCodec::H264);
    m_recorder.setMediaFormat(format);
}

QVideoSink* Producer::videoSink() const
{
    return m_videoSink;
}

void Producer::setVideoSink(QVideoSink* sink)
{
    if (m_videoSink == sink) return;

    if (m_videoSink) {
        disconnect(m_videoSink, &QVideoSink::frameReceived, this, &Producer::onFrameReceived);
    }

    m_videoSink = sink;
    if (m_videoSink) {
        connect(m_videoSink, &QVideoSink::frameReceived, this, &Producer::onFrameReceived);
    }
    emit videoSinkChanged();
}

QUrl Producer::outputLocation() const
{
    return m_outputLocation;
}

void Producer::setOutputLocation(const QUrl& location)
{
    if (m_outputLocation == location) return;
    m_outputLocation = location;
    m_recorder.setOutputLocation(location);
    emit outputLocationChanged();
}

void Producer::startRecording()
{
    if (!m_outputLocation.isValid()) return;
    m_recorder.record();
    emit recordingStateChanged(true);
}

void Producer::stopRecording()
{
    m_recorder.stop();
    emit recordingStateChanged(false);
}

bool Producer::isRecording() const
{
    return m_recorder.status() == QMediaRecorder::RecordingStatus;
}

void Producer::onFrameReceived(const QVideoFrame& frame)
{
    if (m_videoSource && isRecording()) {
        m_videoSource->setFrame(frame);
    }
}

2. 修改QML代码,调用Producer的录制接口

移除原有的独立MediaRecorder,直接通过Producer的方法控制录制:

VideoOutput
{
    id: cameraDisplay
    anchors.fill: parent
}

Producer
{
    id:producer
    objectName: "producer"
    videoSink: cameraDisplay.videoSink
    // 设置MP4输出路径,确保程序有写入权限
    outputLocation: "file:///home/user/recorded_video.mp4"
}

Button{
    text: ""
    Image {
        id: recordImage
        source: producer.isRecording() ? "Images/StopRecord.png" : "Images/Record.png"
        width: parent.width
        height: parent.height
    }

    onClicked: {
        if (producer.isRecording()) {
            producer.stopRecording()
        } else {
            producer.startRecording()
        }
    }
}

关键说明

  • QMediaCaptureSession是Qt6中媒体捕获的核心组件,负责关联视频输入和录制器;
  • 自定义的VideoFrameSource用来将VideoSink收到的帧传递给QMediaCaptureSession,作为录制的视频源;
  • 确保项目文件中已添加多媒体模块:QT += multimedia;
  • 输出路径需使用file://前缀,且程序拥有对应目录的写入权限;
  • 视频编码格式需根据系统支持情况调整,H264是MP4容器的通用选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:35:15