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

Subscribers

People subscribed via source and target branches