2010-03-08 20 views
6

Je travaille avec PyQt et j'essaie d'obtenir une vidéo d'une webcam pour jouer dans un widget QT. J'ai trouvé des tutoriels pour C et Qt, et pour python et gtk, mais rien pour cette combinaison de pyQt et gstreamer. Quelqu'un a-t-il ce travail?Python + QT + Gstreamer

Cela joue la belle vidéo, mais dans une fenêtre séparée:

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

ce que je dois est d'obtenir la superposition de travail de sorte qu'il est affiché dans un widget sur votre interface graphique. Merci, gourous de l'Internet!

ok, donc j'ai eu beaucoup plus loin, mais j'ai toujours besoin d'aide. J'écris en fait cela pour Maemo, mais le code suivant fonctionne très bien sur mon ordinateur portable linux:

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() 

où IFD est l'ID de la fenêtre du widget im essayant d'obtenir pour afficher la sortie quand je lance ce. sur le N900, l'écran devient noir et clignote. Des idées? Je suis en train de mourir ici!

EDIT: On m'a demandé de publier le code complet, et si je dois encore nettoyer un peu, voici la partie pertinente:

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) 

Ceci est assemblant quelques bits, et Je ne peux pas le tester maintenant, mais peut-être que cela sera utile à quelqu'un. Bonne chance!

+0

Je suis à la recherche d'un moyen de diffuser rstp avec QT – user63898

+0

Juste la recherche de ce site et google j'ai trouvé des informations pour C++ et QT. Consultez également les forums Maemo.org. Bonne chance! – Ptterb

Répondre

1

Got it! Il semble que je devais forcer la résolution du pipeline pour correspondre à la résolution du widget où je pompait la vidéo:

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

Ensuite, ajoutez simplement ceux du pipeline comme les autres éléments, et cela fonctionne très bien . Man, il semble si facile à regarder maintenant, mais quand je me cognais la tête contre le mur pendant quelques jours ce n'était pas si évident ...

1

Ptterb pouvez-vous poster votre code complet s'il vous plaît?

J'ai copié votre code.
Ajouté à fvidscale_cap pipeline, avec:

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) 

du programme principal créer un nouveau QWidget et passer son winId() au constructeur Vid.
Le widget démarre le chargement, mais se bloque.

La sortie dit:
devrait jouer
Segmentation faute

+0

Essayez le nouveau code que je viens de mettre en place. Faites-moi savoir si vous avez toujours des problèmes! – Ptterb

+0

ZolaKt, avez-vous résolu le problème ci-dessus? –

+0

@BernardoKyotoku: Non, désolé. J'ai abandonné sur ce projet lorsque Nokia a décidé d'aller à la merde et passer à Windows – ZolaKt

3

Si vous arrive d'utiliser PySide au lieu de PyQt sur une plate-forme autre que Linux, winId() retourne un PyCObject qui can't be used directly with native functions or other modules. Dans mon cas, ce qui est pratique lors de l'utilisation GStreamer (pygst) avec PySide sur 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) 
1

Le code collé ne montre pas le chargement gobject, qui ne peut être rejetée. Il m'a fallu beaucoup de temps pour comprendre ce qui manquait. Merci Jun pour avoir un exemple audio de travail.Où avez-vous trouvé pour C++ et QT?

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_())