1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
# PyGST Tutorial/Demos/Demo.py
#!/usr/bin/env python
"""Basic Framework for writing GStreamer Demos in Python"""
#<excerpt 2>
import gobject
gobject.threads_init()
import gst
#</excerpt>
import pygtk
pygtk.require("2.0")
import gtk
gtk.gdk.threads_init()
import sys
import os
class DemoException(Exception):
"""Base exception class for errors which occur during demos"""
def __init__(self, reason):
self.reason = reason
class Demo:
"""Base class implementing boring, boiler-plate code.
Sets up a basic gstreamer environment which includes:
* a window containing a drawing area and basic media controls
* a basic gstreamer pipeline using an ximagesink
* connects the ximagesink to the window's drawing area
Derived classes need only override magic(), __name__,
and __usage__ to create new demos."""
__name__ = "Basic Demo"
__usage__ = "python demo.py -- runs a simple test demo"
__def_win_size__ = (320, 240)
# this comment allows us to include only a portion of the file
# in the tutorial for this demo
# <excerpt 1> ...
def magic(self, pipeline, sink, args):
"""This is where the magic happens"""
src = gst.element_factory_make("videotestsrc", "src")
pipeline.add(src)
src.link(sink)
def createPipeline(self, w):
"""Given a window, creates a pipeline and connects it to the window"""
# code will make the ximagesink output in the specified window
def set_xid(window):
gtk.gdk.threads_enter()
sink.set_xwindow_id(window.window.xid)
sink.expose()
gtk.gdk.threads_leave()
# this code receives the messages from the pipeline. if we
# need to set X11 id, then we call set_xid
def bus_handler(unused_bus, message):
if message.type == gst.MESSAGE_ELEMENT:
if message.structure.get_name() == 'prepare-xwindow-id':
set_xid(w)
return gst.BUS_PASS
# create our pipeline, and connect our bus_handler
self.pipeline = gst.Pipeline()
bus = self.pipeline.get_bus()
bus.set_sync_handler(bus_handler)
sink = gst.element_factory_make("ximagesink", "sink")
sink.set_property("force-aspect-ratio", True)
sink.set_property("handle-expose", True)
scale = gst.element_factory_make("videoscale", "scale")
cspace = gst.element_factory_make("ffmpegcolorspace", "cspace")
# our pipeline looks like this: ... ! cspace ! scale ! sink
self.pipeline.add(cspace, scale, sink)
scale.link(sink)
cspace.link(scale)
return (self.pipeline, cspace)
# ... end of excerpt </excerpt>
# subclasses can override this method to provide custom controls
def customWidgets(self):
return gtk.HBox()
def createWindow(self):
"""Creates a top-level window, sets various boring attributes,
creates a place to put the video sink, adds some and finally
connects some basic signal handlers. Really, really boring.
"""
# create window, set basic attributes
w = gtk.Window()
w.set_size_request(*self.__def_win_size__)
w.set_title("Gstreamer " + self.__name__)
w.connect("destroy", gtk.main_quit)
# declare buttons and their associated handlers
controls = (
("play_button", gtk.ToolButton(gtk.STOCK_MEDIA_PLAY), self.onPlay),
("stop_button", gtk.ToolButton(gtk.STOCK_MEDIA_STOP), self.onStop),
("quit_button", gtk.ToolButton(gtk.STOCK_QUIT), gtk.main_quit)
)
# as well as the container in which to put them
box = gtk.HButtonBox()
# for every widget, connect to its clicked signal and add it
# to the enclosing box
for name, widget, handler in controls:
widget.connect("clicked", handler)
box.pack_start(widget, True)
setattr(self, name, widget)
viewer = gtk.DrawingArea()
viewer.modify_bg(gtk.STATE_NORMAL, viewer.style.black)
# we will need this later
self.xid = None
# now finally do the top-level layout for the window
layout = gtk.VBox(False)
layout.pack_start(viewer)
# subclasses can override childWidgets() to supply
# custom controls
layout.pack_start(self.customWidgets(), False, False)
layout.pack_end(box, False, False)
w.add(layout)
w.show_all()
# we want to return only the portion of the window which will
# be used to display the video, not the whole top-level
# window. a DrawingArea widget is, in fact, an X11 window.
return viewer
def onPlay(self, unused_button):
self.pipeline.set_state(gst.STATE_PLAYING)
def onStop(self, unused_button):
self.pipeline.set_state(gst.STATE_READY)
def run(self):
w = self.createWindow()
p, s = self.createPipeline(w)
try:
self.magic(p, s, sys.argv[1:])
gtk.main()
except DemoException, e:
print e.reason
print self.__usage__
sys.exit(-1)
# if this file is being run directly, create the demo and run it
if __name__ == '__main__':
Demo().run()
|