I need to play a .mov video (ProRes4444) with alpha channel in a scene. The scene has a background image and I need to use the alpha channel of the video so it overlays on the background.
If I open the video normally with QMediaPlayer, the alpha channel appears in black.
screen with background pic & video with black alpha:
How can I make the output of the QMediaPlayer (QGraphicsVideoItem) respect the alpha and make the overlay effect possible?
The closest I got to the answer based on online research is code in cpp that I've found that shows the necessity to create a subclass of a QAbstractVideoSurface that receives videoframes converts to ARGB, then forwards those to a QLabel that displays them.
Displaying a video with an alpha channel using qt
I've also tried that unsuccessfully. Is this the right course or I'm just missing something simple on my current code?
EDIT: Link to files (background image and video .mov) https://drive.google.com/drive/folders/1LIZzTg1E8wkaD0YSvkkcfSATdlDTggyh?usp=sharing
import sys
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class VideoWindow(QMainWindow):
def __init__(self):
super(VideoWindow, self).__init__()
self.setWindowTitle('QMediaPlayer TEST')
self.resize(1920, 1080)
self.vista = QGraphicsView(self)
self.vista.setGeometry(QRect(0, 0, 1920, 1080))
self.scene = QGraphicsScene(self.vista)
self.scene.setSceneRect(0, 0, 1920, 1080)
self.vista.setScene(self.scene)
self.graphvitem1 = QGraphicsVideoItem()
#SET BACKGROUND IMAGE ON SCENE
self.tempImg = QPixmap("/Users/elemental/Desktop/pyvids/fons.jpeg")
self.tempImg = self.tempImg.scaled(self.scene.width(), self.scene.height())
self.graphicsPixmapItem = QGraphicsPixmapItem(self.tempImg)
self.scene.addItem(self.graphicsPixmapItem)
#SET VIDEO 1 WITH LOOP
self.mediaPlayer1 = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.mediaPlayer1.setVideoOutput(self.graphvitem1)
self.playlist1 = QMediaPlaylist(self)
self.playlist1.addMedia(QMediaContent(QUrl.fromLocalFile("/Users/elemental/Desktop/pyvids/vida1.mov")))
self.playlist1.setCurrentIndex(1)
self.playlist1.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
self.mediaPlayer1.setPlaylist(self.playlist1)
self.graphvitem1.setPos(500, 100)
self.graphvitem1.setSize(QSizeF(1000, 500))
self.scene.addItem(self.graphvitem1)
self.mediaPlayer1.play()
self.vista.show()
if __name__ == '__main__':
app = QApplication([])
window = VideoWindow()
window.show()
sys.exit(app.exec_())

From what I can see, QVideoWidget doesn't support alpha channels by default, so it falls back to the "basic" black background.
But, implementation seems possible, by properly subclassing QAbstractVideoSurface.
Consider that the following code is experimental, my knowledge of QMediaPlayer and the Qt video surface isn't that deep (the former is an abstract for multiple platforms and multiple libraries that can behave very differently on different configurations), and I could only test it on two Linux platforms, so I don't know how it behaves under Windows nor MacOS.
The assumption is that the video surface provides a default dedicated QWidget subclass (VideoWidget) unless another class with a suitable
setImageis provided, and updates itsimagewhenever the media player requires it.Note that I only tested it with a couple of videos (including the provided one), and further testing might be required.
I based the above code on the following sources:
Note that I limited the
supportedPixelFormatsoutput, as using the full list of formats provided in the related question didn't work; this doesn't mean that this would work anyway, but that further testing is probably required, possibly on different machines and different OS/System configurations and video formats: remember that QMediaPlayer completely relies on the underlying OS and default media backend.Finally, if you only need this for "limited" and predefined animations, consider implementing your own subclass of QWidget that uses a list of loaded PNG images and shows them by implementing
paintEvent()that would be called by updates based on a QVariantAnimation. While this kind of implementation might result less performant or ideal, it has the major benefit of providing cross platform compatibility.