diff options
author | flavio <fdanesse@gmail.com> | 2012-08-04 16:27:48 (GMT) |
---|---|---|
committer | flavio <fdanesse@gmail.com> | 2012-08-04 16:27:48 (GMT) |
commit | 663b6c907c1f75502b1ccc0135a9532634830a88 (patch) | |
tree | cce7e17271e1fefafa51f4c1182b29df22e90f5e /JAMediaReproductor.py |
Diffstat (limited to 'JAMediaReproductor.py')
-rw-r--r-- | JAMediaReproductor.py | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/JAMediaReproductor.py b/JAMediaReproductor.py new file mode 100644 index 0000000..83d75f6 --- /dev/null +++ b/JAMediaReproductor.py @@ -0,0 +1,361 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# JAMediaReproductor.py por: +# Flavio Danesse <fdanesse@gmail.com> +# CeibalJAM! - Uruguay +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Se remplaza: +# Depends: python-gst0.10, +# gstreamer0.10-plugins-good, +# gstreamer0.10-plugins-ugly, +# gstreamer0.10-plugins-bad, +# gstreamer0.10-ffmpeg + +# Con: +# Depends: python-gi, +# gir1.2-gstreamer-1.0, +# gir1.2-gst-plugins-base-1.0, +# gstreamer1.0-plugins-good, +# gstreamer1.0-plugins-ugly, +# gstreamer1.0-plugins-bad, +# gstreamer1.0-libav + +# https://wiki.ubuntu.com/Novacut/GStreamer1.0#Using_GStreamer_1.0_from_Python +# http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBus.html#gst-bus-create-watch +# http://www.roojs.org/seed/gir-1.1-gtk-2.0/Gst.MessageType.html#expand + +import os + +import gi +gi.require_version('Gst', '1.0') + +from gi.repository import GObject +from gi.repository import Gst +from gi.repository import GstVideo + +GObject.threads_init() +Gst.init(None) + +class JAMediaReproductor(GObject.GObject): + """ + Reproductor de Audio, Video y Streaming de + Radio y Television. Implementado sobre: + + python 2.7.3 + Gtk 3 + Gstreamer 1.0 + """ + + __gsignals__ = {"endfile":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, []), + "estado":(GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, + (GObject.TYPE_STRING,)), + "newposicion":(GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, + (GObject.TYPE_INT,)), + "volumen":(GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, + (GObject.TYPE_FLOAT,))} + + # Estados: playing, paused, None + + def __init__(self, ventana_id): + """ Recibe el id de un DrawingArea + para mostrar el video. """ + + GObject.GObject.__init__(self) + self.name = "JAMediaReproductor" + self.ventana_id = ventana_id + self.pipeline = None + self.estado = None + + self.duracion = 0 + self.posicion = 0 + self.actualizador = None + + self.player = None + self.bus = None + + self.set_pipeline() + + def set_pipeline(self): + """Crea el pipe de Gst. (playbin)""" + + if self.pipeline: del(self.pipeline) + + self.pipeline = Gst.Pipeline() + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.connect('message', self.on_mensaje) + + self.bus.enable_sync_message_emission() + self.bus.connect('sync-message', self.sync_message) + + self.player = Gst.ElementFactory.make("playbin", "player") + self.pipeline.add(self.player) + + def sync_message(self, bus, mensaje): + """Captura los mensajes en el bus del pipe Gst.""" + + try: + if mensaje.get_structure().get_name() == 'prepare-window-handle': + mensaje.src.set_window_handle(self.ventana_id) + return + except: + pass + + if mensaje.type == Gst.MessageType.STATE_CHANGED: + old, new, pending = mensaje.parse_state_changed() + if old == Gst.State.PAUSED and new == Gst.State.PLAYING: + if self.estado != new: + self.estado = new + self.emit("estado", "playing") + self.new_handle(True) + return + elif old == Gst.State.READY and new == Gst.State.PAUSED: + if self.estado != new: + self.estado = new + self.emit("estado", "paused") + self.new_handle(False) + return + elif old == Gst.State.READY and new == Gst.State.NULL: + if self.estado != new: + self.estado = new + self.emit("estado", "None") + self.new_handle(False) + return + elif old == Gst.State.PLAYING and new == Gst.State.PAUSED: + if self.estado != new: + self.estado = new + self.emit("estado", "paused") + self.new_handle(False) + return + elif old == Gst.State.NULL and new == Gst.State.READY: + pass + elif old == Gst.State.PAUSED and new == Gst.State.READY: + pass + else: + #print ">>>", old, new, pending + return + + elif mensaje.type == Gst.MessageType.ASYNC_DONE: + #print mensaje.get_structure().get_name() + return + elif mensaje.type == Gst.MessageType.NEW_CLOCK: + return + elif mensaje.type == Gst.MessageType.STREAM_STATUS: + #print mensaje.parse_stream_status() + return + elif mensaje.type == Gst.MessageType.TAG: + return + elif mensaje.type == Gst.MessageType.ERROR: + err, debug = mensaje.parse_error() + print "***", 'sync_message' + print err, debug + self.new_handle(False) + #self.pipeline.set_state(Gst.State.NULL) + #self.pipeline.set_state(Gst.State.READY) + #return self.set_pipeline() + return + elif mensaje.type == Gst.MessageType.EOS: + return + else: + try: + nombre = mensaje.get_structure().get_name() + if nombre == "playbin-stream-changed": + #print "Nuevo src:", mensaje.get_structure().to_string() + pass + elif nombre == "have-window-handle": + pass + elif nombre == "prepare-window-handle": + pass + else: + pass + except: + print "sync_message", mensaje.type + return + + def on_mensaje(self, bus, mensaje): + """Captura los mensajes en el bus del pipe Gst.""" + + #if mensaje.type == Gst.MessageType.ASYNC_DONE: + # print mensaje.get_structure().get_name() + #elif mensaje.type == Gst.MessageType.NEW_CLOCK: + # pass + + if mensaje.type == Gst.MessageType.ELEMENT: + nombre = mensaje.get_structure().get_name() + # playbin-stream-changed , prepare-window-handle, have-window-handle + #if nombre == 'prepare-window-handle': + # mensaje.src.set_window_handle(self.ventana_id) + #else: + # print nombre + + ''' + elif mensaje.type == Gst.MessageType.STATE_CHANGED: + old, new, pending = mensaje.parse_state_changed() + if old == Gst.State.PAUSED and new == Gst.State.PLAYING: + if self.estado != new: + self.estado = new + #self.emit("estado", "playing") + elif old == Gst.State.READY and new == Gst.State.PAUSED: + if self.estado != new: + self.estado = new + #self.emit("estado", "paused") + else: + if self.F: print old, new, pending + pass + elif mensaje.type == Gst.MessageType.STREAM_STATUS: + pass + elif mensaje.type == Gst.MessageType.TAG: + #print mensaje.get_structure().to_string() + pass''' + + if mensaje.type == Gst.MessageType.EOS: + #self.pipeline.seek_simple(Gst.Format.TIME, + #Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0) + self.new_handle(False) + self.set_pipeline() + self.emit("endfile") + + elif mensaje.type == Gst.MessageType.QOS: + pass + elif mensaje.type == Gst.MessageType.WARNING: + print mensaje.get_structure().to_string() + #self.new_handle(False) + #self.pipeline.set_state(Gst.State.NULL) + #self.set_pipeline() + + elif mensaje.type == Gst.MessageType.ERROR: + err, debug = mensaje.parse_error() + print "***", 'sync_message' + print err, debug + self.new_handle(False) + #self.pipeline.set_state(Gst.State.NULL) + #self.set_pipeline() + self.pipeline.set_state(Gst.State.READY) + + elif mensaje.type == Gst.MessageType.LATENCY: + #print mensaje.type + pass + else: + #print "on_mensaje", mensaje.type + pass + + def load(self, uri): + """Carga un archivo o stream en el pipe de Gst.""" + + self.stop() + if os.path.exists(uri): + direccion = Gst.filename_to_uri(uri) + self.player.set_property("uri", direccion) + self.play() + else: + # FIXME: Funciona con la radio pero no con la Tv + direccion = uri + #Gst.uri_get_protocol(uri) + if Gst.uri_is_valid(uri): + self.player.set_property("uri", direccion) + self.play() + #print Gst.uri_protocol_is_supported(uri, Gst.uri_get_protocol(uri)) + #print Gst.uri_protocol_is_valid(Gst.uri_get_protocol(uri)) + #self.player.set_property("buffer-size", 1024) + #self.player.set_property("force-aspect-ratio", False) + + def play(self): + """Pone el pipe de Gst en Gst.State.PLAYING""" + + self.pipeline.set_state(Gst.State.PLAYING) + + def stop(self): + """Pone el pipe de Gst en Gst.State.NULL""" + + self.pipeline.set_state(Gst.State.NULL) + self.pipeline.set_state(Gst.State.READY) + + def pause(self): + """Pone el pipe de Gst en Gst.State.PAUSED""" + + self.pipeline.set_state(Gst.State.PAUSED) + + def pause_play(self): + """Llama a play() o pause() + segun el estado actual del pipe de Gst.""" + + if self.estado == Gst.State.PAUSED \ + or self.estado == Gst.State.NULL \ + or self.estado == Gst.State.READY: + self.play() + elif self.estado == Gst.State.PLAYING: + self.pause() + else: + print self.estado + + def new_handle(self, reset): + """Elimina o reinicia la funcion que + envia los datos de actualizacion para + la barra de progreso del reproductor.""" + + if self.actualizador: + GObject.source_remove(self.actualizador) + self.actualizador = None + if reset: + self.actualizador = GObject.timeout_add(300, self.handle) + + def handle(self): + """Funcion que envia los datos de actualizacion para + la barra de progreso del reproductor.""" + + bool1, valor1 = self.pipeline.query_duration(Gst.Format.TIME) + bool2, valor2 = self.pipeline.query_position(Gst.Format.TIME) + + duracion = float(valor1) + posicion = float(valor2) + + pos = 0 + try: + pos = int(posicion * 100 / duracion) + except: + pass + + if pos < 0 or pos > self.duracion: return True + + if self.duracion != duracion: self.duracion = duracion + + if pos != self.posicion: + self.posicion = pos + self.emit("newposicion", self.posicion) + # print "***", gst.video_convert_frame(self.player.get_property("frame")) + + return True + + def set_position(self, posicion): + """Funcion que permite desplazarse por + el archivo que se esta reproduciendo.""" + + if self.duracion < posicion: + self.emit("newposicion", self.posicion) + return + posicion = self.duracion * posicion / 100 + self.pipeline.seek_simple(Gst.Format.TIME, + Gst.SeekFlags.FLUSH, posicion) + + def get_volumen(self): + pass + + def set_volumen(self, valor): + pass +
\ No newline at end of file |