I want to play a video in PyQT with a transparent background using QAbstractVideoSurface.
I have found a program which works on Linux on this topic : Video with alpha channel overlay on background image: Alpha shows black
...but in windows it does not work and the background is black.
** Here's the script :**
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class VideoWidget(QWidget):
image = QImage()
def __init__(self, **kwargs):
super().__init__(**kwargs)
def setImage(self, image):
self.image = image
self.update()
def sizeHint(self):
return QSize(640, 480)
def paintEvent(self, event):
qp = QPainter(self)
# ensure that smooth transformation is used while scaling pixmaps
qp.setRenderHints(qp.SmoothPixmapTransform)
# provide compliancy with background set using stylesheets, see:
# https://doc.qt.io/qt-5/stylesheet-reference.html#qwidget-widget
opt = QStyleOption()
opt.initFrom(self)
self.style().drawPrimitive(QStyle.PE_Widget, opt, qp, self)
# draw the image, scaled to the widget size; if you need fixed sizes
# or keep aspect ratio, implement this (or the widget) accordingly
qp.drawImage(self.rect(), self.image, self.image.rect())
class AlphaVideoDrawer(QAbstractVideoSurface):
def __init__(self, videoWidget=None, widgetOptions=None):
super().__init__()
if videoWidget:
if not hasattr(videoWidget, 'setImage'):
raise NotImplementedError(
'setImage() must be implemented for videoWidget!')
else:
if not isinstance(widgetOptions, dict):
widgetOptions = {}
elif not 'styleSheet' in widgetOptions:
# just a default background for testing purposes
widgetOptions = {'styleSheet': 'background: darkGray;'}
videoWidget = VideoWidget(**widgetOptions)
self.videoWidget = videoWidget
# QVideoFrame.image() has been introduced since Qt 5.15
version, majVersion, minVersion = map(int, QT_VERSION_STR.split('.'))
if version < 6 and majVersion < 15:
self.imageFromFrame = self._imageFromFrameFix
else:
self.imageFromFrame = lambda frame: frame.image()
def _imageFromFrameFix(self, frame):
clone_frame = QVideoFrame(frame)
clone_frame.map(QAbstractVideoBuffer.ReadOnly)
image = QImage(
clone_frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(),
QVideoFrame.imageFormatFromPixelFormat(frame.pixelFormat()))
clone_frame.unmap()
return image
def supportedPixelFormats(self, type):
return [QVideoFrame.Format_ARGB32]
def present(self, frame: QVideoFrame):
if frame.isValid():
self.videoWidget.setImage(self.imageFromFrame(frame))
if self.surfaceFormat().pixelFormat() != frame.pixelFormat() or \
self.surfaceFormat().frameSize() != frame.size():
self.setError(QAbstractVideoSurface.IncorrectFormatError)
self.stop()
return False
else:
return True
class AlphaVideoTest(QMainWindow):
def __init__(self):
super().__init__()
self.setStyleSheet('''
QFrame#mainFrame {
background: blue;
}
''')
mainFrame = QFrame(objectName='mainFrame')
self.setCentralWidget(mainFrame)
layout = QVBoxLayout(mainFrame)
self.playButton = QPushButton('Play', checkable=True)
layout.addWidget(self.playButton)
self.drawer = AlphaVideoDrawer()
layout.addWidget(self.drawer.videoWidget)
self.mediaPlayer1 = QMediaPlayer(self, QMediaPlayer.VideoSurface)
self.playlist = QMediaPlaylist(self)
path = QDir.current().absoluteFilePath('vida1test.mov')
self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))
self.playlist.setCurrentIndex(1)
self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
self.mediaPlayer1.setPlaylist(self.playlist)
self.mediaPlayer1.setVideoOutput(self.drawer)
self.playButton.toggled.connect(self.togglePlay)
def togglePlay(self, play):
if play:
self.mediaPlayer1.play()
self.playButton.setText('Pause')
else:
self.mediaPlayer1.pause()
self.playButton.setText('Play')
import sys
app = QApplication(sys.argv)
test = AlphaVideoTest()
test.show()
sys.exit(app.exec_())
I tried with .mov, .avi, and webm files with VP8 and VP9 codec but it did not work at all. I have also installed K-Lite Codec Pack on my windows to read these files.
Is it even possible ?
Thank you very much if you can help me !