Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/JAMediaReproductor.py
diff options
context:
space:
mode:
Diffstat (limited to 'JAMediaReproductor.py')
-rw-r--r--JAMediaReproductor.py361
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