|
|
@@ -0,0 +1,103 @@ |
|
|
import sys |
|
|
|
|
|
# needed for casting PyCObject to void pointer |
|
|
from ctypes import pythonapi, c_void_p, py_object |
|
|
|
|
|
from PySide.QtCore import * |
|
|
from PySide.QtGui import * |
|
|
|
|
|
import gobject |
|
|
import pygst |
|
|
pygst.require('0.10') |
|
|
import gst |
|
|
|
|
|
|
|
|
class Form(QDialog): |
|
|
def __init__(self, parent=None): |
|
|
super(Form, self).__init__(parent) |
|
|
self.setWindowTitle('PySide+GStreamer on Microsoft Windows') |
|
|
|
|
|
# create widgets and set properties |
|
|
self.videoWidget = QWidget(self) |
|
|
self.videoWidget.setMinimumSize(640, 480) |
|
|
self.numBuffersSpinBox = QSpinBox() |
|
|
self.numBuffersSpinBox.setMinimum(-1) |
|
|
self.numBuffersSpinBox.setValue(-1) |
|
|
self.button = QPushButton('Start') |
|
|
|
|
|
# build layout |
|
|
layout = QVBoxLayout() |
|
|
layout.addWidget(self.videoWidget) |
|
|
layout.addWidget(QLabel('num-buffers')) |
|
|
layout.addWidget(self.numBuffersSpinBox) |
|
|
layout.addWidget(self.button) |
|
|
self.setLayout(layout) |
|
|
|
|
|
# connect signals |
|
|
self.button.clicked.connect(self.on_start_stop) |
|
|
|
|
|
# build pipeline |
|
|
self.pipeline = gst.Pipeline() |
|
|
self.source = gst.element_factory_make('videotestsrc') |
|
|
self.sink = gst.element_factory_make('dshowvideosink') |
|
|
self.pipeline.add(self.source, self.sink) |
|
|
gst.element_link_many(self.source, self.sink) |
|
|
|
|
|
# connect sync-message from gst.Bus |
|
|
self.bus = self.pipeline.get_bus() |
|
|
self.bus.add_signal_watch() |
|
|
self.bus.enable_sync_message_emission() |
|
|
self.bus.connect('sync-message::element', self.on_sync_message) |
|
|
|
|
|
# create timer for checking gst.Bus messages |
|
|
self.timer = QTimer() |
|
|
self.timer.timeout.connect(self.on_timer) |
|
|
|
|
|
# we can't call winId() within the streaming thread (on_sync_message) |
|
|
# so we must do it here |
|
|
winid = self.videoWidget.winId() |
|
|
|
|
|
# convert winId from PyCObject to void pointer (only for PySide on |
|
|
# Windows) |
|
|
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p |
|
|
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object] |
|
|
self.hWnd = pythonapi.PyCObject_AsVoidPtr(self.videoWidget.winId()) |
|
|
|
|
|
def on_start_stop(self): |
|
|
if self.button.text() == 'Stop': |
|
|
self.pipeline.set_state(gst.STATE_NULL) |
|
|
self.button.setText('Start') |
|
|
else: |
|
|
self.source.props.num_buffers = self.numBuffersSpinBox.value() |
|
|
self.pipeline.set_state(gst.STATE_PLAYING) |
|
|
self.button.setText('Stop') |
|
|
self.timer.start(30) |
|
|
|
|
|
def on_sync_message(self, bus, message): |
|
|
if message.structure is None: |
|
|
return |
|
|
|
|
|
if message.structure.get_name() == 'prepare-xwindow-id': |
|
|
# enables video to play in QWidget |
|
|
self.sink.set_xwindow_id(self.hWnd) |
|
|
|
|
|
def on_timer(self): |
|
|
message = self.bus.pop() |
|
|
if message == None: |
|
|
return |
|
|
|
|
|
t = message.type |
|
|
if t == gst.MESSAGE_EOS: |
|
|
self.on_start_stop() |
|
|
elif t == gst.MESSAGE_ERROR: |
|
|
err, debug = message.parse_error() |
|
|
QMessageBox.critical(self, self.tr('Pipeline error'), |
|
|
str(err) + '\n' + debug) |
|
|
self.on_start_stop() |
|
|
|
|
|
if __name__ == '__main__': |
|
|
gobject.threads_init() |
|
|
app = QApplication(sys.argv) |
|
|
form = Form() |
|
|
form.show() |
|
|
sys.exit(app.exec_()) |