From: Antonio Ospite Date: Thu, 28 Feb 2013 11:51:17 +0000 (+0100) Subject: Initial import X-Git-Url: https://git.ao2.it/experiments/gstreamer.git/commitdiff_plain/1314f8c4dcefedb9b17571864ffc4d387c57ea49 Initial import --- 1314f8c4dcefedb9b17571864ffc4d387c57ea49 diff --git a/gst-simple-player.py b/gst-simple-player.py new file mode 100755 index 0000000..22050ec --- /dev/null +++ b/gst-simple-player.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python + +# Simple media player with GStreamer +# +# Copyright (C) 2013 Antonio Ospite +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# References: +# http://pygstdocs.berlios.de/pygst-reference +# https://core.fluendo.com/gstreamer/svn/trunk/gst-fluendo-gdlsink/test/ismdplay.py + +import sys +import os + +import gobject +gobject.threads_init() + +import gst + +# The player window will have a fixed width and height. +# This is just to demonstrate the use of capabilities. +WIDTH = 640 +HEIGHT = 480 + + +class CustomVideoBin(gst.Bin): + def __init__(self): + gst.Bin.__init__(self, 'CustomVideoBin') + + queue = gst.element_factory_make('queue', 'vqueue') + self.add(queue) + + caps = gst.Caps("video/x-raw-yuv,format=(fourcc)AYUV,width=%d,height=%d" % (HEIGHT, WIDTH)) + capsfilter = gst.element_factory_make("capsfilter", "filter") + capsfilter.set_property("caps", caps) + self.add(capsfilter) + + rescale = gst.element_factory_make("videoscale", "rescale") + self.add(rescale) + + colorspace = gst.element_factory_make("colorspace", "colorspace") + self.add(colorspace) + + videosink = gst.element_factory_make("autovideosink", "vidoesink") + self.add(videosink) + + gst.element_link_many(queue, capsfilter, rescale, colorspace, videosink) + sink = queue.get_pad('sink') + self.add_pad(gst.GhostPad('sink', sink)) + + +class CustomAudioBin(gst.Bin): + def __init__(self): + gst.Bin.__init__(self, 'CustomAudioBin') + + queue = gst.element_factory_make('queue', 'aqueue') + self.add(queue) + + audioconvert = gst.element_factory_make("audioconvert", "audioconverter") + self.add(audioconvert) + + audiosink = gst.element_factory_make("autoaudiosink", "audiosink") + self.add(audiosink) + + gst.element_link_many(queue, audioconvert, audiosink) + sink = queue.get_pad('sink') + self.add_pad(gst.GhostPad('sink', sink)) + + +class CustomPlayBin(gst.Pipeline): + __gproperties__ = { + 'source': (gst.Element, "source", "Source element", gobject.PARAM_READABLE) + } + + def __init__(self, uri=None): + gst.Pipeline.__init__(self, 'CustomPlayBin') + + self._uri = uri + + self._playbin = gst.element_factory_make("playbin2", "playbin") + self.add(self._playbin) + + self._playbin.set_property("uri", self._uri) + self._playbin.set_property("video-sink", CustomVideoBin()) + self._playbin.set_property("audio-sink", CustomAudioBin()) + + def set_uri(self, uri): + self._uri = uri + self._playbin.set_property("uri", self._uri) + + +class GstPlayer: + def __init__(self): + + # The user can require some action at End Of Stream + self.eos_cb = None + + self.pipeline = CustomPlayBin() + + bus = self.pipeline.get_bus() + bus.add_signal_watch() + bus.connect('message::eos', self.on_eos) + bus.connect('message::tag', self.on_tag) + bus.connect('message::error', self.on_error) + bus.connect('message::state-changed', self.on_state_changed) + + def on_eos(self, bus, msg): + print 'on_eos' + self.stop() + if self.eos_cb: + self.eos_cb() + + def on_tag(self, bus, msg): + print 'on_tag:' + taglist = msg.parse_tag() + for key in taglist.keys(): + print '\t%s = %s' % (key, taglist[key]) + + def on_error(self, bus, msg): + print 'on_error' + error, debug = msg.parse_error() + print "Error: %s" % error, debug + self.stop() + + def on_state_changed(self, bus, msg): + print 'on_state_changed' + if msg.src != self.pipeline: + return + + old_state, new_state, pending = msg.parse_state_changed() + + def set_location(self, location): + self.pipeline.set_uri(location) + + def play(self): + self.pipeline.set_state(gst.STATE_PLAYING) + + def pause(self): + self.pipeline.set_state(gst.STATE_PAUSED) + + def stop(self): + self.pipeline.set_state(gst.STATE_NULL) + + +class PlayerTUI(): + def __init__(self, location): + + self.player = GstPlayer() + self.player.eos_cb = self.quit + + self.mainloop = gobject.MainLoop() + + self.player.set_location(location) + self.player.play() + + gobject.io_add_watch(sys.stdin, gobject.IO_IN, self.on_stdin) + + try: + self.mainloop.run() + except KeyboardInterrupt: + self.quit() + + def on_stdin(self, fd, event): + # The user has to send a newline fo this to go on + c = os.read(fd.fileno(), 1) + + if c == "q": + self.quit() + elif c == "s": + self.player.pause() + elif c == "r": + self.player.play() + + return True + + def quit(self): + self.player.stop() + self.player = None + self.mainloop.quit() + + +def main(args): + def usage(): + sys.stdout.write("usage: %s \n" % args[0]) + + if len(args) != 2: + usage() + sys.exit(1) + + if not gst.uri_is_valid(args[1]): + sys.stderr.write("Error: Invalid URI: %s\n" % args[1]) + sys.exit(1) + + tui = PlayerTUI(args[1]) + +if __name__ == '__main__': + sys.exit(main(sys.argv))