Python + QT + Gstreamer
Asked Answered
S

4

6

I'm working with PyQt and trying to get video from a webcam to play within a QT widget. I've found tutorials for C and Qt, and for python and gtk, but NOTHING for this combo of pyQt and gstreamer. Anybody get this working?

This plays the video fine, but in a separate window:

self.gcam = gst.parse_launch('v4l2src device=/dev/video0 ! autovideosink')
self.gcam.set_state(gst.STATE_PLAYING)

what I need is to get the overlay working so it's displayed within a widget on my GUI. Thanks, Gurus of the internet!

ok, so I've gotten a lot farther, but still in need of some help. I'm actually writing this for Maemo, but the following code works fine on my linux laptop:

class Vid:
    def __init__(self, windowId):
    self.player = gst.Pipeline("player")
    self.source = gst.element_factory_make("v4l2src", "vsource")
    self.sink = gst.element_factory_make("autovideosink", "outsink")
    self.source.set_property("device", "/dev/video0")
    self.scaler = gst.element_factory_make("videoscale", "vscale")
    self.window_id = None
    self.windowId = windowId

    self.player.add(self.source, self.scaler, self.sink)
    gst.element_link_many(self.source,self.scaler, self.sink)

    bus = self.player.get_bus()
    bus.add_signal_watch()
    bus.enable_sync_message_emission()
    bus.connect("message", self.on_message)
    bus.connect("sync-message::element", self.on_sync_message)

    def on_message(self, bus, message):
    t = message.type
    if t == gst.MESSAGE_EOS:
        self.player.set_state(gst.STATE_NULL)
    elif t == gst.MESSAGE_ERROR:
       err, debug = message.parse_error()
       print "Error: %s" % err, debug
       self.player.set_state(gst.STATE_NULL)

    def on_sync_message(self, bus, message):
    if message.structure is None:
        return
    message_name = message.structure.get_name()
    if message_name == "prepare-xwindow-id":
        win_id = self.windowId
        assert win_id
        imagesink = message.src
        imagesink.set_property("force-aspect-ratio", True)
        imagesink.set_xwindow_id(win_id)
    def startPrev(self):
    self.player.set_state(gst.STATE_PLAYING)
    print "should be playing"
vidStream = Vid(wId)
vidStream.startPrev()

where wId is the window id of the widget im trying to get to display the output in. When I run this on the N900, the screen goes black and blinks. Any ideas? I'm dying here!

EDIT: I've been asked to post the full code, and though I still need to clean it up a bit, here's the relevant part:

self.cameraWindow = QtGui.QWidget(self)
self.cameraWindow.setGeometry(QtCore.QRect(530, 20, 256, 192))
self.cameraWindow.setObjectName("cameraWindow")
self.cameraWindow.setAttribute(0, 1); # AA_ImmediateWidgetCreation == 0
self.cameraWindow.setAttribute(3, 1); # AA_NativeWindow == 3

global wId
wId = self.cameraWindow.winId()

self.camera = Vid(wId)

self.camera.startPrev()

class Vid:
    def __init__(self, windowId):
    self.player = gst.Pipeline("player")
    self.source = gst.element_factory_make("v4l2src", "vsource")
    self.sink = gst.element_factory_make("autovideosink", "outsink")
    self.source.set_property("device", "/dev/video0")
    #self.scaler = gst.element_factory_make("videoscale", "vscale")
    self.fvidscale = gst.element_factory_make("videoscale", "fvidscale")
    self.fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
    self.fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=256, height=192'))
    self.window_id = None
    self.windowId = windowId
    print windowId

    self.player.add(self.source, self.fvidscale, self.fvidscale_cap, self.sink)
    gst.element_link_many(self.source,self.fvidscale, self.fvidscale_cap, self.sink)

    bus = self.player.get_bus()
    bus.add_signal_watch()
    bus.enable_sync_message_emission()
    bus.connect("message", self.on_message)
    bus.connect("sync-message::element", self.on_sync_message)

    def on_message(self, bus, message):
    t = message.type
    if t == gst.MESSAGE_EOS:
        self.player.set_state(gst.STATE_NULL)
    elif t == gst.MESSAGE_ERROR:
       err, debug = message.parse_error()
       print "Error: %s" % err, debug
       self.player.set_state(gst.STATE_NULL)

    def on_sync_message(self, bus, message):
    if message.structure is None:
        return
    message_name = message.structure.get_name()
    if message_name == "prepare-xwindow-id":
        win_id = self.windowId
        assert win_id
        imagesink = message.src
        imagesink.set_property("force-aspect-ratio", True)
        imagesink.set_xwindow_id(win_id)
    def startPrev(self):
    self.player.set_state(gst.STATE_PLAYING)
    def pausePrev(self):
    self.player.set_state(gst.STATE_NULL)

This is piecing together a few bits, and I can't test it right now, but maybe it will be helpful to someone. Good luck!

Sprightly answered 8/3, 2010 at 2:26 Comment(3)
where did you found for c++ and QT ? im looking for way to stream rstp with QTPhraseogram
Just searching this site and google I found info for c++ and QT. Also, check the Maemo.org forums. Good luck!Sprightly
The issue in you code seems to be an indent issue. You functions startPrev and pausePrev are empty like you have posted themKristofor
S
1

Got it! It appears I needed to force the resolution of the pipeline to match the resolution of the widget where I was pumping the video to:

self.fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap") self.fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=256, height=192'))

Then just add those to the pipeline like the other elements, and it works great. Man, it seems so easy looking at it now, but when I was pounding my head against the wall for a few days it wasn't so obvious...

Sprightly answered 6/4, 2010 at 18:50 Comment(0)
P
3

If you're happening to use PySide instead of PyQt on a platform other than Linux, winId() returns a PyCObject which can't be used directly with native functions or other modules. In my case this came in handy when using GStreamer (pygst) with PySide on Microsoft Windows:

from ctypes import pythonapi, c_void_p, py_object
...
if message_name == 'prepare-xwindow-id':
    # convert winId from PyCObject to void pointer
    pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
    pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
    hWnd = pythonapi.PyCObject_AsVoidPtr(self.videoWidget.winId())

    # set window handle to video sink
    self.videoSink.set_xwindow_id(hWnd)
Pyelitis answered 1/8, 2011 at 19:11 Comment(0)
S
1

Got it! It appears I needed to force the resolution of the pipeline to match the resolution of the widget where I was pumping the video to:

self.fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap") self.fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=256, height=192'))

Then just add those to the pipeline like the other elements, and it works great. Man, it seems so easy looking at it now, but when I was pounding my head against the wall for a few days it wasn't so obvious...

Sprightly answered 6/4, 2010 at 18:50 Comment(0)
E
1

Ptterb can you post your full code please?

I copied your code.
Added fvidscale_cap to pipeline, with:

self.player.add(self.source, self.scaler, self.fvidscale_cap, self.sink)
gst.element_link_many(self.source,self.scaler, self.fvidscale_cap, self.sink)

From the main program I create a new QWidget, and pass its winId() to Vid constructor.
The widget start loading, but crashes.

The output says:
should be playing
Segmentation fault

Enculturation answered 29/4, 2010 at 18:39 Comment(2)
Try the new code I just put up. Let me know if you're still having problems!Sprightly
@BernardoKyotoku: No, sorry. I gave up on that project when Nokia decided to go to crap and switch to WindowsEnculturation
M
1

The pasted code is not showing gobject loading, which cannot be dismissed. It took me a good while to figure out what was missing. Thanks Jun for having a working audio example.

import gobject, pygst
pygst.require('0.10')
import gst
from PyQt4.QtGui import QMainWindow, QWidget, QApplication 
import sys

class Video(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        container = QWidget()
        self.setCentralWidget(container)
        self.windowId = container.winId()
        self.setGeometry(300,300,640,480)
        self.show()

    def setUpGst(self):
        self.player = gst.Pipeline("player")
        source = gst.element_factory_make("v4l2src", "vsource")
        sink = gst.element_factory_make("xvimagesink", "sink")
        fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
        fvidscale = gst.element_factory_make("videoscale", "fvidscale")
        caps = gst.caps_from_string('video/x-raw-yuv')
        fvidscale_cap.set_property('caps', caps)
        source.set_property("device", "/dev/video0")

        self.player.add(source, fvidscale, fvidscale_cap, sink)
        gst.element_link_many(source,fvidscale, fvidscale_cap, sink)
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.enable_sync_message_emission()
        bus.connect("message", self.on_message)
        bus.connect("sync-message::element", self.on_sync_message)

    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            self.player.set_state(gst.STATE_NULL)
            print "end of message"
        elif t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            self.player.set_state(gst.STATE_NULL)

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        message_name = message.structure.get_name()
        if message_name == "prepare-xwindow-id":
            win_id = self.windowId
            assert win_id
            imagesink = message.src
            imagesink.set_xwindow_id(win_id)

    def startPrev(self):
        self.player.set_state(gst.STATE_PLAYING)
        print "should be playing"

if __name__ == "__main__":
    gobject.threads_init()
    app = QApplication(sys.argv)
    video = Video()
    video.setUpGst()
    video.startPrev()
    sys.exit(app.exec_())
Monograph answered 19/1, 2012 at 2:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.