2 # -*- coding: utf-8 -*-
5 # Copyright (C) 2006 Artem Popov <artfwo@gmail.com>
7 # This example demonstrates segment seeking
8 # and seamless looping within playbin.
11 pygst.require ("0.10")
18 class Looper (gobject.GObject):
20 "loop": (gobject.TYPE_BOOLEAN,
22 "Whether to loop the segment",
24 gobject.PARAM_READWRITE),
25 "start-pos": (gobject.TYPE_UINT64,
27 "The segment start marker",
29 0xfffffffffffffff, # max long possible
31 gobject.PARAM_READWRITE),
32 "stop-pos": (gobject.TYPE_UINT64,
34 "The segment stop marker",
36 0xfffffffffffffff, # max long possible
38 gobject.PARAM_READWRITE),
42 "stopped": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
43 "position-updated": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,)),
44 "error": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
47 def __init__ (self, location = None):
48 gobject.GObject.__init__ (self)
50 self.__playbin = gst.element_factory_make ("playbin")
51 self.__playbin.props.video_sink = gst.element_factory_make ("fakesink")
53 bus = self.__playbin.get_bus ()
54 bus.add_watch (self.__on_bus_message)
65 def load (self, location):
66 self.__playbin.props.uri = location
67 self.__start_position = 0
68 self.__stop_position = 0
70 def set_segment (self, start, stop):
71 self.props.start_pos = start
72 self.props.stop_pos = stop
75 if not (self.__start_pos or self.__stop_pos):
76 raise RuntimeError, "Cannot start playback, segment was not set!"
78 self.__playbin.set_state (gst.STATE_PLAYING)
80 def stop (self, silent = False):
81 self.__playbin.set_state (gst.STATE_NULL)
85 def do_get_property (self, property):
86 if property.name == "loop":
88 elif property.name == "start-pos":
89 return self.__start_pos
90 elif property.name == "stop-pos":
91 return self.__stop_pos
93 raise AttributeError, "Unknown property %s" % property.name
95 def do_set_property (self, property, value):
96 if property.name == "loop":
98 elif property.name == "start-pos":
99 self.__start_pos = value
100 elif property.name == "stop-pos":
101 self.__stop_pos = value
103 raise AttributeError, "Unknown property %s" % property.name
105 def do_stopped (self):
106 if self.__timeout_id:
107 gobject.source_remove (self.__timeout_id)
108 self.__timeout_id = 0
110 def __seek (self, start, stop, flush):
111 flags = gst.SEEK_FLAG_SEGMENT | gst.SEEK_FLAG_ACCURATE
113 flags = flags | gst.SEEK_FLAG_FLUSH
114 self.__playbin.seek (1.0, gst.FORMAT_TIME, flags,
115 gst.SEEK_TYPE_SET, start,
116 gst.SEEK_TYPE_SET, stop)
118 def __on_timeout (self):
119 position = self.__playbin.query_position (gst.FORMAT_TIME) [0]
120 self.emit ("position-updated", float (position))
123 def __on_bus_message (self, bus, message):
124 if message.type == gst.MESSAGE_ERROR:
125 error, debug = message.parse_error ()
126 self.stop () # this looks neccessary here
127 self.emit ("error", (error, debug))
129 elif message.type == gst.MESSAGE_NEW_CLOCK:
130 # we connect the timeout handler here to be sure that further queries succeed
131 interval = int ((self.__stop_position - self.__start_position) / (2 * gst.SECOND) + 50)
132 self.__timeout_id = gobject.timeout_add (interval, self.__on_timeout)
134 elif message.type == gst.MESSAGE_STATE_CHANGED:
135 old_state, new_state, pending = message.parse_state_changed ()
136 if old_state == gst.STATE_READY and new_state == gst.STATE_PAUSED and message.src == self.__playbin:
137 self.__seek (self.__start_pos, self.__stop_pos, True)
139 elif message.type == gst.MESSAGE_SEGMENT_DONE:
141 self.__seek (self.__start_pos, self.__stop_pos, False)
143 src = self.__playbin.get_property ("source")
144 pad = src.get_pad ('src')
145 pad.push_event (gst.event_new_eos ())
147 # this is the good old way:
149 # pads = src.src_pads ()
153 # pad.push_event (gst.event_new_eos ())
157 elif message.type == gst.MESSAGE_EOS:
162 mainloop = gobject.MainLoop ()
164 def on_looper_stopped (looper):
167 def on_looper_pos_updated (looper, position):
168 print round (position / gst.SECOND, 2)
170 def on_looper_error (looper, error_tuple):
171 error, debug = error_tuple
172 print "\n\n%s\n\n%s\n\n" % (error, debug)
175 if __name__ == "__main__":
177 if len (sys.argv) != 5:
178 print "Usage: %s <filename|uri> <start_seconds> <stop_seconds> <loop = 0|1>" % sys.argv [0]
181 if "://" in sys.argv [1]:
185 uri = "file://" + os.path.abspath (sys.argv [1])
187 looper = Looper (uri)
189 looper.props.start_pos = long (sys.argv [2]) * gst.SECOND
190 looper.props.stop_pos = long (sys.argv [3]) * gst.SECOND
191 looper.props.loop = int (sys.argv [4])
193 looper.connect ("stopped", on_looper_stopped)
194 looper.connect ("position-updated", on_looper_pos_updated)
195 looper.connect ("error", on_looper_error)