<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<small>Hello Folks!<br>
<br>
I'm not a C++ programmer, but below is my best attempt at
translating a C++ code example found in QtEnterprise<br>
for creating a custom video widget using a custom video surface.
Please feel free to use it ... if you can get it to <br>
work! <br>
<br>
When I run the code the widget appears okay. The only error I'm
getting is "QWidget::paintEngine: Should no longer be called",<br>
but I'm not getting any video playback when I open a file. Looking
at the code I don't see anything visible that would 'start' the<br>
video surface, but I'm guessing that that is the responsibility of
the QMediaPlayer instance? (self.mediaPlayer)<br>
<br>
If anyone has any suggestions, I'd love to hear them.<br>
<br>
I'm programming under Windows 7, with Python 3.3.2 and PyQt5-5.1,
32 bit.<br>
<br>
Best regards,<br>
Timothy Grove<br>
<br>
<br>
<tt>#!/usr/bin/env python</tt><tt><br>
</tt><tt># -*- coding: utf-8 -*-<br>
<br>
</tt><tt></tt><tt>"""The Video Widget example shows how to
implement a video widget </tt><tt><br>
</tt><tt>using QtMultimedia's QAbstractVideoSurface. <br>
<br>
</tt><tt></tt><tt>The following is a translation into PyQt5 from
the C++ example found in</tt><tt><br>
</tt><tt>C:\QtEnterprise\5.1.1\msvc2010\examples\multimediawidgets\customvideosurface\customvideowidget."""<br>
<br>
</tt><tt></tt><tt>import sys</tt><tt><br>
</tt><tt>import os</tt><tt><br>
</tt><tt>from PyQt5.QtGui import *</tt><tt><br>
</tt><tt>from PyQt5.QtWidgets import *</tt><tt><br>
</tt><tt>from PyQt5.QtCore import *</tt><tt><br>
</tt><tt>from PyQt5.QtMultimedia import *</tt><tt><br>
</tt><tt>from PyQt5.QtMultimediaWidgets import *<br>
<br>
</tt><tt></tt><tt>class VideoWidgetSurface(QAbstractVideoSurface):</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def __init__(self, widget, parent=None):</tt><tt><br>
</tt><tt> super(VideoWidgetSurface, self).__init__(parent)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.widget = widget</tt><tt><br>
</tt><tt> self.imageFormat = QImage.Format_Invalid<br>
<br>
</tt><tt></tt><tt> def supportedPixelFormats(self,
handleType=QAbstractVideoBuffer.NoHandle):</tt><tt><br>
</tt><tt> formats = [QVideoFrame.PixelFormat()]</tt><tt><br>
</tt><tt> if (handleType == QAbstractVideoBuffer.NoHandle):</tt><tt><br>
</tt><tt> for f in [QVideoFrame.Format_RGB32,</tt><tt><br>
</tt><tt> QVideoFrame.Format_ARGB32,</tt><tt><br>
</tt><tt>
QVideoFrame.Format_ARGB32_Premultiplied,</tt><tt><br>
</tt><tt> QVideoFrame.Format_RGB565,</tt><tt><br>
</tt><tt> QVideoFrame.Format_RGB555</tt><tt><br>
</tt><tt> ]:</tt><tt><br>
</tt><tt> formats.append(f)</tt><tt><br>
</tt><tt> return formats</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def isFormatSupported(self, _format):</tt><tt><br>
</tt><tt> imageFormat =
QVideoFrame.imageFormatFromPixelFormat(_format.pixelFormat())</tt><tt><br>
</tt><tt> size = _format.frameSize()</tt><tt><br>
</tt><tt> _bool = False</tt><tt><br>
</tt><tt> if (imageFormat != QImage.Format_Invalid and not
</tt><tt><br>
</tt><tt> size.isEmpty() and</tt><tt><br>
</tt><tt> _format.handleType() ==
QAbstractVideoBuffer.NoHandle):</tt><tt><br>
</tt><tt> _bool = True</tt><tt><br>
</tt><tt> return _bool<br>
<br>
</tt><tt></tt><tt> def start(self, _format):</tt><tt><br>
</tt><tt> imageFormat =
QVideoFrame.imageFormatFromPixelFormat(_format.pixelFormat())</tt><tt><br>
</tt><tt> size = _format.frameSize()</tt><tt><br>
</tt><tt> if (imageFormat != QImage.Format_Invalid and not
size.isEmpty()):</tt><tt><br>
</tt><tt> self.imageFormat = imageFormat</tt><tt><br>
</tt><tt> self.imageSize = size</tt><tt><br>
</tt><tt> self.sourceRect =
_format.viewport() </tt><tt><br>
</tt><tt> QAbstractVideoSurface.start(self, _format)
</tt><tt><br>
</tt><tt> self.widget.updateGeometry()</tt><tt><br>
</tt><tt> self.updateVideoRect() </tt><tt><br>
</tt><tt> return True</tt><tt><br>
</tt><tt> else:</tt><tt><br>
</tt><tt> return False</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def stop(self):</tt><tt><br>
</tt><tt> self.currentFrame = QVideoFrame()</tt><tt><br>
</tt><tt> self.targetRect = QRect()</tt><tt><br>
</tt><tt> QAbstractVideoSurface.stop(self)</tt><tt><br>
</tt><tt> self.widget.update()<br>
<br>
</tt><tt></tt><tt> def present(self, frame):</tt><tt><br>
</tt><tt> if (self.surfaceFormat().pixelFormat() !=
frame.pixelFormat() or</tt><tt><br>
</tt><tt> self.surfaceFormat().frameSize() !=
frame.size()):</tt><tt><br>
</tt><tt>
self.setError(QAbstractVideoSurface.IncorrectFormatError)</tt><tt><br>
</tt><tt> self.stop()</tt><tt><br>
</tt><tt> return False</tt><tt><br>
</tt><tt> else:</tt><tt><br>
</tt><tt> self.currentFrame = frame</tt><tt><br>
</tt><tt> self.widget.repaint(self.targetRect)</tt><tt><br>
</tt><tt> return True<br>
<br>
</tt><tt></tt><tt> def videoRect(self):</tt><tt><br>
</tt><tt> return self.targetRect</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def updateVideoRect(self):</tt><tt><br>
</tt><tt> size = self.surfaceFormat().sizeHint()</tt><tt><br>
</tt><tt> size.scale(self.widget.size().boundedTo(size),
Qt.KeepAspectRatio)</tt><tt><br>
</tt><tt> self.targetRect = QRect(QPoint(0, 0), size);</tt><tt><br>
</tt><tt>
self.targetRect.moveCenter(self.widget.rect().center())</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def paint(self, painter):</tt><tt><br>
</tt><tt> if
(self.currentFrame.map(QAbstractVideoBuffer.ReadOnly)):</tt><tt><br>
</tt><tt> oldTransform = painter.transform()</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> if (self.surfaceFormat().scanLineDirection() ==
QVideoSurfaceFormat.BottomToTop):</tt><tt><br>
</tt><tt> painter.scale(1, -1);</tt><tt><br>
</tt><tt> painter.translate(0, -self.widget.height())</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> image = QImage(self.currentFrame.bits(),</tt><tt><br>
</tt><tt> self.currentFrame.width(),</tt><tt><br>
</tt><tt> self.currentFrame.height(),</tt><tt><br>
</tt><tt> self.currentFrame.bytesPerLine(),</tt><tt><br>
</tt><tt> self.imageFormat</tt><tt><br>
</tt><tt> )</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> painter.drawImage(self.targetRect, image,
self.sourceRect)</tt><tt><br>
</tt><tt> painter.setTransform(oldTransform)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.currentFrame.unmap()<br>
<br>
</tt><tt></tt><tt>class VideoWidget(QWidget):</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def __init__(self, parent=None):</tt><tt><br>
</tt><tt> super(VideoWidget, self).__init__(parent)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.setAutoFillBackground(False)</tt><tt><br>
</tt><tt> self.setAttribute(Qt.WA_NoSystemBackground, True)</tt><tt><br>
</tt><tt> self.setAttribute(Qt.WA_PaintOnScreen, True)</tt><tt><br>
</tt><tt> palette = self.palette()</tt><tt><br>
</tt><tt> palette.setColor(QPalette.Background, Qt.black)</tt><tt><br>
</tt><tt> self.setPalette(palette)</tt><tt><br>
</tt><tt> self.setSizePolicy(QSizePolicy.MinimumExpanding,
QSizePolicy.MinimumExpanding)</tt><tt><br>
</tt><tt> self.surface = VideoWidgetSurface(self)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def videoSurface(self):</tt><tt><br>
</tt><tt> return self.surface </tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def closeEvent(self, event):</tt><tt><br>
</tt><tt> del self.surface</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def sizeHint(self):</tt><tt><br>
</tt><tt> return self.surface.surfaceFormat().sizeHint()</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def paintEvent(self, event):</tt><tt><br>
</tt><tt> painter = QPainter(self)</tt><tt><br>
</tt><tt> if (self.surface.isActive()):</tt><tt><br>
</tt><tt> videoRect = self.surface.videoRect()</tt><tt><br>
</tt><tt> if not videoRect.contains(event.rect()):</tt><tt><br>
</tt><tt> region = event.region()</tt><tt><br>
</tt><tt> region.subtract(videoRect) </tt><tt><br>
</tt><tt> brush = self.palette().background() </tt><tt><br>
</tt><tt> for rect in region.rects():</tt><tt><br>
</tt><tt> painter.fillRect(rect, brush) </tt><tt><br>
</tt><tt> self.surface.paint(painter)</tt><tt><br>
</tt><tt> else:</tt><tt><br>
</tt><tt> painter.fillRect(event.rect(),
self.palette().window())</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def resizeEvent(self, event):</tt><tt><br>
</tt><tt> QWidget.resizeEvent(self, event)</tt><tt><br>
</tt><tt> self.surface.updateVideoRect()</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt>class VideoPlayer(QWidget):</tt><tt><br>
</tt><tt> def __init__(self, parent=None):</tt><tt><br>
</tt><tt> super(VideoPlayer, self).__init__(parent)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.mediaPlayer = QMediaPlayer(None,
QMediaPlayer.VideoSurface)</tt><tt><br>
</tt><tt> self.videoWidget = VideoWidget()</tt><tt><br>
</tt><tt> self.openButton = QPushButton("Open...")</tt><tt><br>
</tt><tt> self.openButton.clicked.connect(self.openFile)</tt><tt><br>
</tt><tt> self.playButton = QPushButton()</tt><tt><br>
</tt><tt> self.playButton.setEnabled(False)</tt><tt><br>
</tt><tt>
self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
</tt><tt><br>
</tt><tt> self.playButton.clicked.connect(self.play)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.positionSlider = QSlider(Qt.Horizontal)</tt><tt><br>
</tt><tt> self.positionSlider.setRange(0, 0)</tt><tt><br>
</tt><tt>
self.positionSlider.sliderMoved.connect(self.setPosition)</tt><tt><br>
</tt><tt> self.controlLayout = QHBoxLayout()</tt><tt><br>
</tt><tt> self.controlLayout.setContentsMargins(0, 0, 0, 0)</tt><tt><br>
</tt><tt> self.controlLayout.addWidget(self.openButton)</tt><tt><br>
</tt><tt> self.controlLayout.addWidget(self.playButton)</tt><tt><br>
</tt><tt> self.controlLayout.addWidget(self.positionSlider)</tt><tt><br>
</tt><tt> layout = QVBoxLayout()</tt><tt><br>
</tt><tt> layout.addWidget(self.videoWidget)</tt><tt><br>
</tt><tt> layout.addLayout(self.controlLayout)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> self.setLayout(layout)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt>
self.mediaPlayer.setVideoOutput(self.videoWidget.videoSurface())</tt><tt><br>
</tt><tt>
self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)</tt><tt><br>
</tt><tt>
self.mediaPlayer.positionChanged.connect(self.positionChanged)</tt><tt><br>
</tt><tt>
self.mediaPlayer.durationChanged.connect(self.durationChanged)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def openFile(self):</tt><tt><br>
</tt><tt> file_name = QFileDialog.getOpenFileName(self,
"Open Movie", QDir.homePath())[0]</tt><tt><br>
</tt><tt> if os.path.exists(file_name):</tt><tt><br>
</tt><tt>
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(file_name)))</tt><tt><br>
</tt><tt> self.playButton.setEnabled(True)<br>
<br>
</tt><tt></tt><tt> def play(self):</tt><tt><br>
</tt><tt> if self.mediaPlayer.state() ==
QMediaPlayer.PlayingState:</tt><tt><br>
</tt><tt> self.mediaPlayer.pause()</tt><tt><br>
</tt><tt> else:</tt><tt><br>
</tt><tt> self.mediaPlayer.play()<br>
<br>
</tt><tt></tt><tt> def mediaStateChanged(self, state):</tt><tt><br>
</tt><tt> if state == QMediaPlayer.PlayingState:</tt><tt><br>
</tt><tt>
self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))</tt><tt><br>
</tt><tt> else:</tt><tt><br>
</tt><tt>
self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))<br>
<br>
</tt><tt></tt><tt> def positionChanged(self, position):</tt><tt><br>
</tt><tt> self.positionSlider.setValue(position)<br>
<br>
</tt><tt></tt><tt> def durationChanged(self, duration):</tt><tt><br>
</tt><tt> self.positionSlider.setRange(0, duration)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> def setPosition(self, position):</tt><tt><br>
</tt><tt> self.mediaPlayer.setPosition(position)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt>if __name__ == '__main__':</tt><tt><br>
</tt><tt> app = QApplication(sys.argv)</tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> player = VideoPlayer()</tt><tt><br>
</tt><tt> player.show() </tt><tt><br>
</tt><tt> </tt><tt><br>
</tt><tt> sys.exit(app.exec_()) </tt></small>
</body>
</html>