Qt6.4: how to record a renderd camera video
Unsolved
General and Desktop
-
Hello there
I would like to record a video via camera, add some overlay to it and finally save it as a mp4. The overlay must be visible in the mp4 file.
I made it to display the overlay on a VideoOutput in qml.
But i didn't got it to record the overlay on the video.
Is there a way to set the VideoOutput as source to record, instead of the camera?My Code so far:
video_input.h (QVideoSink)#ifndef VIDEO_INPUT_H #define VIDEO_INPUT_H #include "qmediacapturesession.h" #include <QVideoSink> #include <QCamera> #include <QMediaCaptureSession> #include <QPointer> #include <QMediaRecorder> class Video_input : public QVideoSink { Q_OBJECT Q_PROPERTY( QVideoSink* videoSink READ videoSink WRITE setVideoSink NOTIFY videoSinkChanged ) Q_PROPERTY( QMediaRecorder* recorder READ recorder WRITE setRecorder NOTIFY recorderChanged ) public: explicit Video_input(QObject * parent = nullptr); ~Video_input(); QVideoSink * videoSink() const; void setVideoSink( QVideoSink * new_video_sink ); QMediaRecorder * recorder() const; void setRecorder( QMediaRecorder * new_recorder ); signals: void videoSinkChanged(); void recorderChanged(); private slots: void new_frame(const QVideoFrame& frame); private: void start_camera(); void stop_camera(); private: Q_DISABLE_COPY(Video_input) QCamera * m_camera; QMediaCaptureSession m_capture_session; QPointer<QVideoSink> m_video_sink; QMediaRecorder * m_recorder; }; #endif // VIDEO_INPUT_H
video_input.cpp (QVideoSink)
#include "Video_input.h" #include <QPainter> #include <QFont> #include <QDebug> Video_input::Video_input(QObject * parent) : QVideoSink(parent) { connect(this,&QVideoSink::videoFrameChanged,this,&Video_input::new_frame); this->start_camera(); } Video_input::~Video_input() { this->stop_camera(); } QVideoSink * Video_input::videoSink() const { return m_video_sink.get(); } void Video_input::setVideoSink(QVideoSink * new_video_sink) { if(m_video_sink == new_video_sink) { return; } m_video_sink = new_video_sink; emit videoSinkChanged(); } QMediaRecorder * Video_input::recorder() const { return m_recorder; } void Video_input::setRecorder(QMediaRecorder * new_recorder) { if(m_recorder == new_recorder) { return; } m_recorder = new_recorder; m_capture_session.setRecorder(m_recorder); emit recorderChanged(); } void Video_input::start_camera() { m_camera = new QCamera(this); m_capture_session.setCamera(m_camera); m_capture_session.setVideoSink(this); //m_capture_session.setVideoOutput(this); m_camera->start(); } void Video_input::stop_camera() { m_camera->stop(); disconnect(m_camera, 0, 0,0); m_camera->setParent(nullptr); delete m_camera; m_camera = nullptr; } void Video_input::new_frame(const QVideoFrame & frame) { QVideoFrame m_frame = frame; QImage m_image; //get frame to image m_frame.map(QVideoFrame::ReadOnly); if(m_frame.isValid()) { m_image = m_frame.toImage(); } //Unmap if(m_frame.isMapped()) m_frame.unmap(); m_image = m_image.convertToFormat(QImage::Format_RGBA8888); //Draw overlay QPainter m_painter(&m_image); m_painter.fillRect(QRect(0, 0, 100, 100), QColor(Qt::GlobalColor::red)); m_painter.fillRect(QRect(0, 100, 100, 100), QColor(Qt::GlobalColor::green)); m_painter.fillRect(QRect(0, 200, 100, 100), QColor(Qt::GlobalColor::blue)); QVideoFrameFormat m_videoformat(m_image.size(), QVideoFrameFormat::Format_RGBA8888); QVideoFrame m_overlay(m_videoformat); m_overlay.map(QVideoFrame::WriteOnly); if(m_overlay.isValid()) { uint8_t pane = 0; memcpy(m_overlay.bits(pane),m_image.bits(),m_image.sizeInBytes()); } if(m_overlay.isMapped()) m_overlay.unmap(); if(m_video_sink) { m_video_sink->setVideoFrame(m_overlay); } }
main.qml
import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick 2.7 import QtQuick.Window 2.2 import my.Video_input 1.0 import QtMultimedia Window { id: appWindow width: 640 height: 480 visible: true title: qsTr("My Video Overlay") Video_input { id: video_input videoSink: view.videoSink recorder: recorder } VideoOutput { id: view anchors.fill: parent } MediaRecorder{ id: recorder } Button { text: "Record" visible: recorder.recorderState !== MediaRecorder.RecordingState onClicked: recorder.record() } Button { text: "Stop" visible: recorder.recorderState === MediaRecorder.RecordingState onClicked: recorder.stop() } }
Thanks in advance
Alex