#!/usr/bin/env python3 # Simple media player with GStreamer # # Copyright (C) 2013-2014 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 gi gi.require_version('Gst', '1.0') from gi.repository import Gst Gst.init(None) from gi.repository import GLib from gi.repository import GObject # The player window will have a fixed width and height. # This is just to demonstrate the use of capabilities. WIDTH = 640 HEIGHT = 300 class CustomVideoBin(Gst.Bin): def __init__(self): Gst.Bin.__init__(self, 'CustomVideoBin') queue = Gst.ElementFactory.make('queue', 'vqueue') self.add(queue) rescale = Gst.ElementFactory.make("videoscale", "rescale") self.add(rescale) queue.link(rescale) caps = Gst.Caps("video/x-raw,format=(fourcc)AYUV,width=%d,height=%d,pixel-aspect-ratio=1/1" % (WIDTH, HEIGHT)) capsfilter = Gst.ElementFactory.make("capsfilter", "filter") capsfilter.set_property("caps", caps) self.add(capsfilter) rescale.link(capsfilter) videoconvert = Gst.ElementFactory.make("videoconvert", "videoconvert") self.add(videoconvert) capsfilter.link(videoconvert) videosink = Gst.ElementFactory.make("autovideosink", "vidoesink") self.add(videosink) videoconvert.link(videosink) sink = queue.get_static_pad('sink') self.add_pad(Gst.GhostPad('sink', sink)) class CustomAudioBin(Gst.Bin): def __init__(self): Gst.Bin.__init__(self, 'CustomAudioBin') queue = Gst.ElementFactory.make('queue', 'aqueue') self.add(queue) audioconvert = Gst.ElementFactory.make("audioconvert", "audioconverter") self.add(audioconvert) queue.link(audioconvert) audiosink = Gst.ElementFactory.make("autoaudiosink", "audiosink") self.add(audiosink) audioconvert.link(audiosink) sink = queue.get_static_pad('sink') self.add_pad(Gst.GhostPad('sink', sink)) class CustomPlayBin(Gst.Pipeline): __gproperties__ = { 'source': (Gst.Element, "source", "Source element", GObject.ParamFlags.READABLE) } def __init__(self, uri=None): Gst.Pipeline.__init__(self, 'CustomPlayBin') self._playbin = Gst.ElementFactory.make("playbin", "playbin") self.add(self._playbin) self._playbin.set_property("video-sink", CustomVideoBin()) self._playbin.set_property("audio-sink", CustomAudioBin()) if uri: self.set_uri(uri) 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() print('\t', taglist.to_string()) 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 = GLib.MainLoop() self.player.set_location(location) self.player.play() GLib.io_add_watch(sys.stdin, GLib.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) uri = Gst.filename_to_uri(args[1]) tui = PlayerTUI(uri) if __name__ == '__main__': sys.exit(main(sys.argv))