2010-03-08 15 views
6

Sto lavorando con PyQt e sto cercando di ottenere il video da una webcam per giocare all'interno di un widget QT. Ho trovato tutorial per C e Qt, e per python e gtk, ma NULLA per questa combo di pyQt e gstreamer. Qualcuno lo fa funzionare?Python + QT + Gstreamer

questo gioca il video bene, ma in una finestra separata:

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

quello che mi serve è quello di ottenere la sovrapposizione di lavoro in modo che sia visualizzato all'interno di un widget sul mio GUI. Grazie, guru di internet!

ok, quindi sono diventato molto più lontano, ma ho ancora bisogno di aiuto. In realtà sto scrivendo questo per Maemo, ma il seguente codice funziona bene sul mio portatile 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() 

dove WID è la finestra ID del widget im cercando di ottenere per visualizzare l'output in Quando eseguo questo. sull'N900, lo schermo diventa nero e lampeggia. Qualche idea? Sto morendo qui!

EDIT: Mi è stato chiesto di inviare il codice completo, e anche se ho ancora bisogno di ripulirlo un po ', ecco la parte relativa:

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) 

Questo è mettere insieme un paio di pezzi, e Non posso testarlo adesso, ma forse sarà utile a qualcuno. In bocca al lupo!

+0

dove hai trovato per C++ e QT? Sto cercando il modo di streaming rstp con QT – user63898

+0

Basta cercare questo sito e google ho trovato informazioni per C++ e QT. Inoltre, controlla i forum di Maemo.org. In bocca al lupo! – Ptterb

risposta

1

Trovato! Sembra avevo bisogno di forzare la risoluzione del gasdotto per corrispondere alla risoluzione del widget in cui mi stava pompando il video:

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

Quindi basta aggiungere quelli alla pipeline come gli altri elementi, e funziona benissimo . Amico, sembra così facile guardarlo ora, ma quando stavo battendo la testa contro il muro per alcuni giorni non era così ovvio ...

1

Ptterb puoi pubblicare il tuo codice completo per favore?

Ho copiato il codice.
Aggiunto fvidscale_cap al gasdotto, con:

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) 

Dal programma principale che creare un nuovo QWidget, e passa la sua WinID() al costruttore Vid.
Il widget inizia a caricare, ma si blocca.

L'uscita dice:
dovrebbe giocare
Segmentation fault

+0

Prova il nuovo codice che ho appena messo. Fammi sapere se hai ancora problemi! – Ptterb

+0

ZolaKt, hai risolto il problema sopra? –

+0

@BernardoKyotoku: No, mi dispiace. Ho rinunciato a quel progetto quando Nokia ha deciso di andare a schifo e passare a Windows – ZolaKt

3

Se stai succedendo utilizzare PySide invece di PyQt su una piattaforma diversa da Linux, WinID() restituisce un PyCObject che can't be used directly with native functions or other modules. Nel mio caso questo è venuto in pratico quando si usa GStreamer (pygst) con PySide su 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

Il codice incollato non sta mostrando gobject di carico, che non può essere respinto. Mi ci è voluto un bel po 'per capire cosa mancava. Grazie Jun per avere un esempio audio funzionante.

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