Merge lp:~brunogirin/python-snippets/gstreamer-basics into lp:~jonobacon/python-snippets/trunk

Proposed by Bruno Girin
Status: Needs review
Proposed branch: lp:~brunogirin/python-snippets/gstreamer-basics
Merge into: lp:~jonobacon/python-snippets/trunk
Diff against target: 195 lines (+186/-0)
2 files modified
gstreamer/cdaudio.py (+110/-0)
gstreamer/webcam.py (+76/-0)
To merge this branch: bzr merge lp:~brunogirin/python-snippets/gstreamer-basics
Reviewer Review Type Date Requested Status
Jono Bacon Pending
Review via email: mp+24254@code.launchpad.net

Description of the change

Added two snippets:
- stream an audio CD to standard audio output (pulse)
- stream from a webcam, scale the stream and display in a small window

To post a comment you must log in.

Unmerged revisions

100. By Bruno Girin

Added snippets to play audio CDs and display a webcam input

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'gstreamer/cdaudio.py'
2--- gstreamer/cdaudio.py 1970-01-01 00:00:00 +0000
3+++ gstreamer/cdaudio.py 2010-04-27 19:42:32 +0000
4@@ -0,0 +1,110 @@
5+#!/usr/bin/env python
6+#
7+# [SNIPPET_NAME: Audio CD Streamer]
8+# [SNIPPET_CATEGORIES: GStreamer]
9+# [SNIPPET_DESCRIPTION: A basic streamer that plays the first five seconds of each song on an audio CD]
10+# [SNIPPET_AUTHOR: Bruno Girin <brunogirin@gmail.com>]
11+# [SNIPPET_LICENSE: GPL]
12+#
13+# This snippet demonstrate the basics of playing an audio CD. In practice, it
14+# uses the core code of a small application I wrote for my own use and that I
15+# called Cacofonix (after the bard in the Asterix comics of course). If you
16+# want a more complete example with GTK UI, grab the cacofonix code here:
17+# https://launchpad.net/~brunogirin/+archive/cacofonix
18+#
19+
20+import sys
21+import time
22+# gtk is used exclusively to benefit from the GTK main loop
23+# This is because the GStreamer pipeline uses its own thread which means that
24+# the main thread doesn't block and exits immediately; the gtk main loop is an
25+# easy way to prevent this problem happening even though it is not ideal.
26+# If anybody has a better way to do this, please contribute a patch.
27+import gtk
28+# the main import for GStreamer
29+import gst
30+
31+class CdPlayer:
32+ def __init__(self):
33+ """
34+ Initialise the CD player
35+ """
36+ # initialise a GStreamer pipeline
37+ self.player = gst.Pipeline("player")
38+ # create the source and sink
39+ # note that you could also use the cdparanoiasrc source; cdparanoiasrc
40+ # performs complex validation of the source (as the documentation puts
41+ # it: 'Read audio from CD in paranoid mode') and is more CPU intensive
42+ source = gst.element_factory_make("cdiocddasrc", "cd-source")
43+ sink = gst.element_factory_make("pulsesink", "pulse-sink")
44+ # build the pipeline
45+ self.player.add(source, sink)
46+ gst.element_link_many(source, sink)
47+ # connect the bus's message signal to the on_message method
48+ bus = self.player.get_bus()
49+ bus.add_signal_watch()
50+ bus.connect("message", self.on_message)
51+ self.sample_time = 5
52+
53+ def play(self):
54+ """
55+ Start playing the CD as soon as the user has inserted and audio CD
56+ in the drive.
57+ """
58+ print('Insert an audio CD in the drive and press ENTER.')
59+ sys.stdin.readline()
60+ self.player.set_state(gst.STATE_PLAYING)
61+
62+ def on_message(self, bus, message):
63+ """
64+ Handle messages posted on the player's bus.
65+ The most insteresting messages are TAG messages as they advise us
66+ when a track starts playing and provide us with the track number and
67+ count, which we use to jump forward to the next track after 5 seconds.
68+ We also handle error messages to advise the user that there is a problem
69+ reading from the CD.
70+ """
71+ t = message.type
72+ if t == gst.MESSAGE_TAG:
73+ taglist = message.parse_tag()
74+ tags=dict([(k, taglist[k]) for k in taglist.keys()])
75+ if('track-count' in tags):
76+ self.track_count = tags['track-count']
77+ if('track-number' in tags):
78+ # if we receive a message that includes the track number, it
79+ # means that the player has just started to play that track
80+ # note that track_number starts at index 1
81+ self.track_number = tags['track-number']
82+ print('Sampling track {track_number} out of {track_count}'.format(
83+ track_number = self.track_number, track_count = self.track_count))
84+ if(self.track_number < self.track_count):
85+ # if we haven't sampled all tracks yet, sleep for 5 seconds
86+ # and seek forward to the next track
87+ time.sleep(self.sample_time)
88+ # create a track format to tell seek_simple to seek by
89+ # track number
90+ format = gst.format_get_by_nick('track')
91+ # the seek_simple method expects the track number as a
92+ # 0-based index, while the track number in the message
93+ # is a 1-based index so passing track_number rather than
94+ # track_number+1 actually does the right thing
95+ self.player.seek_simple(
96+ format, gst.SEEK_FLAG_FLUSH, self.track_number)
97+ else:
98+ # stop the player and ask the GTK main loop to quit after
99+ # sleeping 5 seconds to sample the last track
100+ time.sleep(self.sample_time)
101+ print('Sampled all tracks, exiting.')
102+ self.player.set_state(gst.STATE_NULL)
103+ gtk.main_quit()
104+ elif t == gst.MESSAGE_ERROR:
105+ print('Cannot read CD.')
106+ self.play()
107+
108+if __name__ == "__main__":
109+ cdplayer = CdPlayer()
110+ cdplayer.play()
111+ # we only call gtk.main() to have a main loop and prevent the application
112+ # from exiting as soon as cdplayer.play() has been called
113+ gtk.main()
114+
115
116=== added file 'gstreamer/webcam.py'
117--- gstreamer/webcam.py 1970-01-01 00:00:00 +0000
118+++ gstreamer/webcam.py 2010-04-27 19:42:32 +0000
119@@ -0,0 +1,76 @@
120+#!/usr/bin/env python
121+#
122+# [SNIPPET_NAME: Webcam Streamer]
123+# [SNIPPET_CATEGORIES: GStreamer]
124+# [SNIPPET_DESCRIPTION: A basic streamer that plays a webcam's video input in a window]
125+# [SNIPPET_AUTHOR: Bruno Girin <brunogirin@gmail.com>]
126+# [SNIPPET_LICENSE: GPL]
127+#
128+# This snippet demonstrate the basics of streaming a webcam input to a display
129+# window. This is derived from BigWhale's GStreamer tutorial:
130+# http://www.twm-kd.com/computers/software/webcam-and-linux-gstreamer-tutorial/
131+# And from Ptterb's post on StackOverflow:
132+# http://stackoverflow.com/questions/2398958/python-qt-gstreamer
133+# Note that it doesn't handle audio: this is left as an exercise for the reader.
134+# BigWhale's tutorial has all the elements you need to get that to work.
135+#
136+
137+import sys
138+import time
139+# gtk is used exclusively to benefit from the GTK main loop
140+# This is because the GStreamer pipeline uses its own thread which means that
141+# the main thread doesn't block and exits immediately; the gtk main loop is an
142+# easy way to prevent this problem happening even though it is not ideal.
143+# If anybody has a better way to do this, please contribute a patch.
144+import gtk
145+# the main import for GStreamer
146+import gst
147+
148+class WebcamPlayer:
149+ def __init__(self):
150+ """
151+ Initialise the Webcam player
152+ """
153+ # initialise a GStreamer pipeline
154+ self.player = gst.Pipeline("player")
155+ # create the source and sink
156+ source = gst.element_factory_make("v4l2src", "webcam-source")
157+ fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
158+ fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=320, height=240, framerate=30/1'))
159+ sink = gst.element_factory_make("xvimagesink", "video-sink")
160+ sink.set_property('force-aspect-ratio', True)
161+ # build the pipeline
162+ self.player.add(source, fvidscale_cap, sink)
163+ gst.element_link_many(source, fvidscale_cap, sink)
164+ # connect the bus's message signal to the on_message method
165+ bus = self.player.get_bus()
166+ bus.add_signal_watch()
167+ bus.connect("message", self.on_message)
168+
169+ def play(self):
170+ """
171+ Start streaming the webcam.
172+ """
173+ print('A display window for your webcam should appear soon.\nClose that window to exit.')
174+ self.player.set_state(gst.STATE_PLAYING)
175+
176+ def on_message(self, bus, message):
177+ """
178+ Handle error messages posted on the player's bus.
179+ """
180+ t = message.type
181+ if t == gst.MESSAGE_ERROR:
182+ # An error is received when the display window is closed so use
183+ # that to exit. Of course, that's a bit of a nasty hack and you'd
184+ # want a more reliable way to exit in a real application but it
185+ # will do for this example.
186+ self.player.set_state(gst.STATE_NULL)
187+ gtk.main_quit()
188+
189+if __name__ == "__main__":
190+ webcamplayer = WebcamPlayer()
191+ webcamplayer.play()
192+ # we only call gtk.main() to have a main loop and prevent the application
193+ # from exiting as soon as cdplayer.play() has been called
194+ gtk.main()
195+

Subscribers

People subscribed via source and target branches