Search code examples
pythonqmlpyside2

Why is the "run()" method of my QVideoFilterRunnable in PySide2 not being executed?


I'm want to make use of a Video Filter in a Pyside2(5.12.2)/QML application to further process the camera's frames. I converted the example from the QT docs to Python, but instead of the QVideoFilterRunnable's "run()" method being executed, the constructor is invoked endlessly thus creating one new instance after another. I suspect this might be related to Python's garbage collection - does anyone know how to make the run() method being executed in PySide2?

import sys
from PySide2.QtCore import QUrl, Slot, Signal, Property
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType

from PySide2.QtMultimedia import QVideoFilterRunnable, QAbstractVideoFilter

class MyFilterRunnable(QVideoFilterRunnable):

    def __init__(self, filter):
        print("init")
        self.init = False
        self.filter = filter

    def run(self, input, surface, flags):
        print("run")
        return input

class MyVideoFilter(QAbstractVideoFilter):

    def createFilterRunnable(self):
        return MyFilterRunnable(self)

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    qmlRegisterType(MyVideoFilter, "my.uri", 1, 0, "MyVideoFilter");
    engine.load(QUrl.fromLocalFile('qml_test.qml'))
    sys.exit(app.exec_())

The QML file:

import QtQuick 2.0
import QtMultimedia 5.4
import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2

import my.uri 1.0

ApplicationWindow {

    id: app
    width: 640
    height: 480
    visible: true

    Rectangle {
        id : cameraUI
        anchors.fill: parent

        Camera {
            id: camera
        }

        MyVideoFilter {
            id: myvideofilter
        }

        VideoOutput {
            id: viewfinder
            filters: [ myvideofilter ]
            source: camera
        }
    }
}

Instead of "run" i see countless "init" in the console.


Solution

  • In Python you have to be explicit when doing the inheritance and for this you must use super(), in your case Qt detects that MyFilterRunnable is not a QVideoFilterRunnable so it tries to find another filter and the MyVideoFilter passes the same filter to it so you see that "init" is printed at every moment. Also, what is filter? we do not know, it is not necessary, and since it is not necessary to add parameters as arguments we can omit __init__:

    class MyFilterRunnable(QVideoFilterRunnable):
        def run(self, _input, surface, flags):
            print("run")
            return _input
    

    Even considering the above unfortunately your program will crash due to an unsolved bug: PYSIDE-785. The same happens in PyQt5.