سؤال

أنا أعمل مع PYQT وأحاول الحصول على مقطع فيديو من كاميرا ويب للعب داخل عنصر واجهة مستخدم QT. لقد وجدت البرامج التعليمية لـ C و QT ، و Python و GTK ، ولكن لا شيء لهذا التحرير والسرد من Pyqt و Gstreamer. أي شخص يحصل على هذا العمل؟

هذا يلعب الفيديو بشكل جيد ، ولكن في نافذة منفصلة:

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

ما أحتاجه هو عمل التراكب بحيث يتم عرضه داخل عنصر واجهة مستخدم على واجهة المستخدم الرسومية. شكرا ، معلمي الإنترنت!

حسنًا ، لقد حصلت على الكثير ، لكنني ما زلت في حاجة إلى بعض المساعدة. أنا في الواقع أكتب هذا من أجل Maemo ، لكن الكود التالي يعمل بشكل جيد على جهاز الكمبيوتر المحمول 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()

حيث يكون Wid هو معرف نافذة العنمل الذي أحاول الوصول إليه. عندما أقوم بتشغيل هذا على N900 ، تصبح الشاشة سوداء وتومض. أيه أفكار؟ أنا أموت هنا!

تحرير: طُلب مني نشر الكود الكامل ، وعلى الرغم من أنني ما زلت بحاجة إلى تنظيفه قليلاً ، فإليك الجزء ذي الصلة:

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)

هذا يجمع بين بعض البتات ، ولا يمكنني اختباره الآن ، لكن ربما سيكون مفيدًا لشخص ما. حظا طيبا وفقك الله!

هل كانت مفيدة؟

المحلول 2

فهمتك! يبدو أنني بحاجة لإجبار دقة خط الأنابيب على مطابقة دقة القطعة حيث كنت أضخ الفيديو إلى:

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

ثم فقط أضفها إلى خط الأنابيب مثل العناصر الأخرى ، وهي تعمل بشكل رائع. يا رجل ، يبدو من السهل أن ننظر إليه الآن ، لكن عندما كنت أقصف رأسي على الحائط لبضعة أيام ، لم يكن الأمر واضحًا ...

نصائح أخرى

إذا كنت تحدث لاستخدام بيسايد بدلاً من pyqt على منصة أخرى غير Linux ، فإن WinID () يعيد pycobject أي لا يمكن استخدامها مباشرة مع الوظائف الأصلية أو الوحدات الأخرى. في حالتي ، أصبح هذا مفيدًا عند استخدام Gstreamer (Pygst) مع بيسايد على 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 هل يمكنك نشر الرمز الكامل الخاص بك من فضلك؟

لقد نسخت الرمز الخاص بك.
تمت إضافة FVIDSCALE_CAP إلى خط الأنابيب ، مع:

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)

من البرنامج الرئيسي أقوم بإنشاء QWIDGET جديد ، ونقل WinID () إلى مُنشئ VID.
يبدأ التحميل عنصر واجهة المستخدم ، ولكن تعطل.

يقول الإخراج:
يجب أن يلعب
خطأ تجزئة

لا يعرض الرمز المرفق تحميل goBject ، والذي لا يمكن رفضه. استغرق الأمر مني وقتًا جيدًا لمعرفة ما كان مفقودًا. شكرًا يونيو للحصول على مثال صوتي عمل.

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_())
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top