Reputation: 1
I have a demo PyQt6 application using the QtMultimedia library to capture live video from a webcam and record it via QCamera, QMediaCaptureSession, QVideoWidget and QMediaRecorder.
I want to add some text to the frames. I believe this is possible by using the map()
QVideoFrame.toImage()
and unmap()
functions. I want the text to be present on the QVideoWidget as well as the exported video file.
However, the resulting QImage returned by the QVideoFrame.toImage() function is always Null (using the QImage.isNull() function).
I have tried different QCameraFormat's offered by my webcam, YUYV, JPEG, NV12 etc. but it makes no difference.
I have tried the QVideoFrame.addSubtitleText()
function, but that does not embed the text into the video frame, so it is not present on the exported video file.
How can I add text to a QVideoFrame?
I am using Python3.10 and PyQt6.7.1.
import os
from PyQt6.QtCore import QUrl, pyqtSlot
from PyQt6.QtMultimedia import (
QCamera,
QCameraDevice,
QMediaCaptureSession,
QMediaDevices,
QMediaRecorder,
QVideoFrame,
)
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtWidgets import (
QApplication,
QComboBox,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget,
)
video_path = os.path.join(os.getcwd(), "my_video.mp4")
class Main(QMainWindow):
def __init__(self):
super().__init__()
widget = QWidget()
self.setCentralWidget(widget)
self.main_layout = QVBoxLayout(widget)
self.m_devices = QMediaDevices()
self.devices_list = QComboBox()
[
self.devices_list.addItem(str(d.description()), d)
for d in self.m_devices.videoInputs()
]
self.devices_list.setCurrentIndex(-1)
self.devices_list.activated.connect(
lambda idx: self.set_camera(self.devices_list.itemData(idx))
)
self.main_layout.addWidget(QLabel("Select Camera"))
self.main_layout.addWidget(self.devices_list)
self.start_btn = QPushButton("Start Recording")
self.start_btn.clicked.connect(self.start_recording)
self.main_layout.addWidget(self.start_btn)
self.stop_btn = QPushButton("Stop Recording")
self.stop_btn.clicked.connect(self.stop_recording)
self.main_layout.addWidget(self.stop_btn)
self.video_widget = QVideoWidget()
self.video_sink = self.video_widget.videoSink()
self.video_sink.videoFrameChanged.connect(self.on_video_frame)
self.main_layout.addWidget(self.video_widget, 1)
self.m_recorder = QMediaRecorder()
self.m_recorder.recorderStateChanged.connect(lambda state: print(state))
self.m_recorder.setOutputLocation(QUrl.fromLocalFile(video_path))
self.m_recorder.errorOccurred.connect(lambda error, error_str: print(error_str))
self.m_capture_session = QMediaCaptureSession()
self.m_capture_session.setVideoSink(self.video_sink)
self.m_capture_session.setRecorder(self.m_recorder)
# self.capture_session.setVideoOutput(self.video_widget)
self.camera = QCamera(QCameraDevice())
self.show()
self.resize(800, 600)
def set_camera(self, camera: QCameraDevice):
self.camera = QCamera(camera)
self.m_capture_session.setCamera(self.camera)
self.camera.start()
def start_recording(self):
self.m_recorder.record()
def stop_recording(self):
self.m_recorder.stop()
@pyqtSlot(QVideoFrame)
def on_video_frame(self, frame: QVideoFrame) -> None:
""" """
if not frame.isValid():
return
if not frame.map(QVideoFrame.MapMode.ReadOnly):
return
img = frame.toImage()
### edit QImage here ###
print(f"Frame received (null={img.isNull()})")
frame.unmap()
if __name__ == "__main__":
app = QApplication([])
main = Main()
app.exec()
Upvotes: 0
Views: 66