Pregunta

Estoy trabajando con PyQt y tratando de conseguir el vídeo desde una cámara web para jugar dentro de un widget de QT. Me he encontrado tutoriales para C y Qt, y para Python y GTK, pero nada de este combo de pyqt y gstreamer. Alguien conseguir este trabajo?

Esto juega la multa de vídeo, pero en una ventana separada:

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

lo que necesito es conseguir que el trabajo de superposición de modo que se muestre dentro de un widget en mi interfaz gráfica de usuario. Gracias, gurús de internet!

bien, así que he vuelto mucho más lejos, pero todavía necesita un poco de ayuda. En realidad estoy escribiendo esto para Maemo, pero el siguiente código funciona bien en mi portátil 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()

donde WID es la ventana Identificación del widget de im tratando de llegar a mostrar el resultado en. Cuando ejecuto esto en la N900, la pantalla se queda en negro y parpadea. ¿Algunas ideas? Me estoy muriendo aquí!

EDIT: Me han pedido para publicar el código completo, y aunque todavía tengo que limpiarlo un poco, aquí está la parte 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)

Esta es poner en común unos pocos bits, y no puedo probarlo ahora mismo, pero tal vez sea útil a alguien. Buena suerte!

¿Fue útil?

Solución 2

Lo tienes! Parece que necesitaba para forzar la resolución de la tubería para que coincida con la resolución del widget donde yo estaba bombeando el vídeo a:

self.fvidscale_cap = gst.element_factory_make ( "capsfilter", "fvidscale_cap") self.fvidscale_cap.set_property ( 'caps', gst.caps_from_string ( 'video / x-crudo-YUV, width = 256, altura = 192'))

A continuación, sólo tiene que añadir los de la tubería al igual que los otros elementos, y funciona muy bien. El hombre, que parece tan fácil mirando ahora, pero cuando estaba golpeando mi cabeza contra la pared durante unos días no era tan obvio ...

Otros consejos

Si usted está pasando a utilizar PySide en lugar de PyQt en una plataforma que no sea Linux, winId () devuelve un PyCObject que no se pueden utilizar directamente con las funciones nativas u otros módulos . En mi caso esto fue muy útil cuando se utiliza GStreamer (pygst) con PySide en 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)

Ptterb puede publicar su código completa por favor?

He copiado el código.
Añadido fvidscale_cap a la tubería, 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)

Desde el programa principal que crear una nueva QWidget, y pasan su winId () para Vid constructor.
El widget de empezar a cargar, pero se bloquea.

La salida dice:
deberían estar jugando
fallo de segmentación

El código pegado no aparece carga gobject, que no puede ser desestimada. Me tomó un buen tiempo para averiguar lo que le faltaba. Gracias junio por tener un ejemplo de audio de trabajo.

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_())
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top