[xiph-commits] r11594 - trunk/souffleur

daraku at svn.xiph.org daraku at svn.xiph.org
Tue Jun 20 11:41:52 PDT 2006


Author: daraku
Date: 2006-06-20 11:41:37 -0700 (Tue, 20 Jun 2006)
New Revision: 11594

Added:
   trunk/souffleur/discoverer.py
   trunk/souffleur/gstfile.py
Modified:
   trunk/souffleur/Souffleur.py
   trunk/souffleur/souffleur.glade
Log:
Add GStreamer Support (at last)

Modified: trunk/souffleur/Souffleur.py
===================================================================
--- trunk/souffleur/Souffleur.py	2006-06-20 16:49:52 UTC (rev 11593)
+++ trunk/souffleur/Souffleur.py	2006-06-20 18:41:37 UTC (rev 11594)
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 
-import oggStreams
+#import oggStreams
+from gstfile import GstFile
 import sys
 
 try:
@@ -12,6 +13,7 @@
     pass
 try:
     import gtk
+    import gobject
     import gtk.glade
 except:
     print "You need to install pyGTK or GTKv2 ",
@@ -49,9 +51,16 @@
 
 	self.windowFileOpen=None
 	self.windowStreams=gtk.glade.XML (self.gladefile,"STREAM_WINDOW")
+	### Setup LIST_STREAMS
+	LIST = self.windowStreams.get_widget("LIST_STREAMS")
+	if LIST:
+	    self.streamsTreeStore = gtk.TreeStore(gobject.TYPE_STRING)
+	    LIST.set_model(self.streamsTreeStore)
+	    cell = gtk.CellRendererText()
+	    tvcolumn = gtk.TreeViewColumn('Streams', cell, text = 0)
+	    LIST.append_column(tvcolumn)
 	WND=self.windowStreams.get_widget("STREAM_WINDOW")
 	WND.hide()
-	self.Streams=None
 	return
 #==============================================================================
     def mainFileOpen(self, widget):
@@ -60,11 +69,11 @@
 	    dic={"on_OPEN_BUTTON_CANCEL_clicked": self.openFileCancel,\
 		"on_OPEN_BUTTON_OPEN_clicked": self.openFileOpen }
 	    self.windowFileOpen.signal_autoconnect(dic)
-	    WND=self.windowFileOpen.get_widget("OPEN_OGG")
-	    Filter=gtk.FileFilter()
-	    Filter.set_name("OGM file")
-	    Filter.add_pattern("*.og[gm]")
-	    WND.add_filter(Filter)
+#	    WND=self.windowFileOpen.get_widget("OPEN_OGG")
+#	    Filter=gtk.FileFilter()
+#	    Filter.set_name("OGM file")
+#	    Filter.add_pattern("*.og[gm]")
+#	    WND.add_filter(Filter)
 	else:
 	    WND=self.windowFileOpen.get_widget("OPEN_OGG")
 	    if(WND==None):
@@ -83,20 +92,36 @@
     def openFileOpen(self, widget):
 	WND=self.windowFileOpen.get_widget("OPEN_OGG")
 	FN=WND.get_filename()
+	Streams = None
 	if((FN!="")and(FN!=None)):
-	    self.Streams=oggStreams.oggStreams(FN)
+#	    self.Streams=oggStreams.oggStreams(FN)
+	    print FN
+	    Streams = GstFile(FN)
+	    if Streams:
+		Streams.run()
 	WND.hide()
 	WND=self.windowStreams.get_widget("STREAM_WINDOW")
 	WND.show()
-	self.refreshStreamsWindow()
+	self.addStreams(Streams)
+#	self.refreshStreamsWindow()
 	return
 #==============================================================================
-    def refreshStreamsWindow(self):
-	TStreams=self.Streams.getStreams()
-	for OGGStream in Streams:
+    def addStreams(self, Streams):
+	if not Streams:
+	    return
+	iter = self.streamsTreeStore.append(None)
+	self.streamsTreeStore.set(iter, 0, Streams.MIME + " " + Streams.SOURCE)
+	for i in Streams.STREAMS.keys():
+	    child = self.streamsTreeStore.append(iter)
+	    self.streamsTreeStore.set(child, 0, i +" " + Streams.STREAMS[i])
+	    print i +" " + Streams.STREAMS[i]
+	return
+#    def refreshStreamsWindow(self):
+#	TStreams=self.Streams.getStreams()
+#	for OGGStream in Streams:
 	    #TODO
-	    pass
-	return
+#	    pass
+#	return
 #==============================================================================
 #	MAIN:
 #==============================================================================

Added: trunk/souffleur/discoverer.py
===================================================================
--- trunk/souffleur/discoverer.py	2006-06-20 16:49:52 UTC (rev 11593)
+++ trunk/souffleur/discoverer.py	2006-06-20 18:41:37 UTC (rev 11594)
@@ -0,0 +1,322 @@
+#!/usr/bin/env python
+# -*- Mode: Python -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+# discoverer.py
+# (c) 2005 Edward Hervey <edward at fluendo dot com>
+# Discovers multimedia information on files
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library 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
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+# (c) 2006 Maxim Litvinov (aka DarakuTenshi) <otaky at ukr dot net>
+# Adapt to Souffleur project use
+
+
+"""
+Class and functions for getting multimedia information about files
+"""
+
+import gst
+import gobject
+import os.path
+from gst.extend.pygobject import gsignal
+
+class Discoverer(gst.Pipeline):
+    """
+    Discovers information about files.
+    This class is event-based and needs a mainloop to work properly.
+    Emits the 'discovered' signal when discovery is finished.
+
+    The 'discovered' callback has one boolean argument, which is True if the
+    file contains decodable multimedia streams.
+    """
+    __gsignals__ = {
+        'discovered' : (gobject.SIGNAL_RUN_FIRST,
+                        None,
+                        (gobject.TYPE_BOOLEAN, ))
+        }
+    
+    mimetype = None
+
+    audiocaps = {}
+    videocaps = {}
+
+    videowidth = 0
+    videoheight = 0
+    videorate = 0
+
+    audiofloat = False
+    audiorate = 0
+    audiodepth = 0
+    audiowidth = 0
+    audiochannels = 0
+
+    audiolength = 0L
+    videolength = 0L
+
+    is_video = False
+    is_audio = False
+
+    otherstreams = []
+
+    finished = False
+    tags = {}
+
+
+    def __init__(self, filename):
+        gobject.GObject.__init__(self)
+
+
+        self.filename = filename
+        self.mimetype = None
+
+#        self.audiocaps = {}
+#        self.videocaps = {}
+
+#        self.videowidth = 0
+#        self.videoheight = 0
+#        self.videorate = gst.Fraction(0,1)
+
+#        self.audiofloat = False
+#        self.audiorate = 0
+#        self.audiodepth = 0
+#        self.audiowidth = 0
+#        self.audiochannels = 0
+
+#        self.audiolength = 0L
+#        self.videolength = 0L
+
+#        self.is_video = False
+#        self.is_audio = False
+
+#        self.otherstreams = []
+
+        self.finished = False
+#        self.tags = {}
+        self._success = False
+
+        self.streams = {}
+
+        self._timeoutid = 0
+        
+        if not os.path.isfile(filename):
+            self.finished = True
+            return
+        
+        # the initial elements of the pipeline
+        self.src = gst.element_factory_make("filesrc")
+        self.src.set_property("location", filename)
+        self.src.set_property("blocksize", 1000000)
+        self.dbin = gst.element_factory_make("decodebin")
+        self.add(self.src, self.dbin)
+        self.src.link(self.dbin)
+        self.typefind = self.dbin.get_by_name("typefind")
+
+        # callbacks
+        self.typefind.connect("have-type", self._have_type_cb)
+        self.dbin.connect("new-decoded-pad", self._new_decoded_pad_cb)
+        self.dbin.connect("unknown-type", self._unknown_type_cb)
+
+    def _finished(self, success=False):
+        self.debug("success:%d" % success)
+        self._success = success
+        self.bus.remove_signal_watch()
+        if self._timeoutid:
+            gobject.source_remove(self._timeoutid)
+            self._timeoutid = 0
+        gobject.idle_add(self._stop)
+        return False
+
+    def _stop(self):
+        self.debug("success:%d" % self._success)
+        self.finished = True
+        self.set_state(gst.STATE_READY)
+        self.debug("about to emit signal")
+        self.emit('discovered', self._success)
+        
+
+    def _bus_message_cb(self, bus, message):
+        if message.type == gst.MESSAGE_EOS:
+            self._finished()
+#        elif message.type == gst.MESSAGE_TAG:
+#            for key in message.parse_tag().keys():
+#                print "_bus_message_cb\t", bus.get_parent(), key, message.structure[key]
+#                self.tags[key] = message.structure[key]
+        elif message.type == gst.MESSAGE_ERROR:
+            self._finished()
+
+    def discover(self):
+        """Find the information on the given file asynchronously"""
+        self.debug("starting discovery")
+        if self.finished:
+            self.emit('discovered', False)
+            return
+
+        self.bus = self.get_bus()
+        self.bus.add_signal_watch()
+        self.bus.connect("message", self._bus_message_cb)
+
+        # 3s timeout
+        self._timeoutid = gobject.timeout_add(3000, self._finished)
+        
+        self.info("setting to PLAY")
+        if not self.set_state(gst.STATE_PLAYING):
+            self._finished()
+
+    def _time_to_string(self, value):
+        """
+        transform a value in nanoseconds into a human-readable string
+        """
+        ms = value / gst.MSECOND
+        sec = ms / 1000
+        ms = ms % 1000
+        min = sec / 60
+        sec = sec % 60
+        return "%2dm %2ds %3d" % (min, sec, ms)
+
+    def print_info(self):
+        pass
+#        """prints out the information on the given file"""
+#        if not self.finished:
+#            return
+#        if not self.mimetype:
+#            print "Unknown media type"
+#            return
+#        print "Mime Type :\t", self.mimetype
+#        if not self.is_video and not self.is_audio:
+#            return
+#        print "Length :\t", self._time_to_string(max(self.audiolength, self.videolength))
+#        print "\tAudio:", self._time_to_string(self.audiolength), "\tVideo:", self._time_to_string(self.videolength)
+#        if self.is_video and self.videorate:
+#            print "Video :"
+#            print "\t%d x %d @ %d/%d fps" % (self.videowidth,
+#                                            self.videoheight,
+#                                            self.videorate.num, self.videorate.denom)
+#            if self.tags.has_key("video-codec"):
+#                print "\tCodec :", self.tags.pop("video-codec")
+#        if self.is_audio:
+#            print "Audio :"
+#            if self.audiofloat:
+#                print "\t%d channels(s) : %dHz @ %dbits (float)" % (self.audiochannels,
+#                                                                    self.audiorate,
+#                                                                    self.audiowidth)
+#            else:
+#                print "\t%d channels(s) : %dHz @ %dbits (int)" % (self.audiochannels,
+#                                                                  self.audiorate,
+#                                                                  self.audiodepth)
+#            if self.tags.has_key("audio-codec"):
+#                print "\tCodec :", self.tags.pop("audio-codec")
+#        for stream in self.otherstreams:
+#            if not stream == self.mimetype:
+#                print "Other unsuported Multimedia stream :", stream
+#        if self.tags:
+#            print "Additional information :"
+#            for tag in self.tags.keys():
+#                print "%20s :\t" % tag, self.tags[tag]
+#
+    def _unknown_type_cb(self, dbin, pad, caps):
+        self.debug("unknown type : %s" % caps.to_string())
+#        print "_unknown_type_cb", caps.to_string()
+        # if we get an unknown type and we don't already have an
+        # audio or video pad, we are finished !
+        self.otherstreams.append(caps.to_string())
+        if not self.is_video and not self.is_audio:
+            self.finished = True
+            self._finished()
+
+    def _have_type_cb(self, typefind, prob, caps):
+        self.mimetype = caps.to_string()
+
+    def _notify_caps_cb(self, pad, args):
+        caps = pad.get_negotiated_caps()
+        if not caps:
+            pad.info("no negotiated caps available")
+            return
+        pad.info("caps:%s" % caps.to_string)
+        # the caps are fixed
+        # We now get the total length of that stream
+        q = gst.query_new_duration(gst.FORMAT_TIME)
+        pad.info("sending position query")
+        if pad.get_peer().query(q):
+            format, length = q.parse_duration()
+            pad.info("got position query answer : %d:%d" % (length, format))
+        else:
+            length = -1
+            gst.warning("position query didn't work")
+
+#        print "_notify_caps_cb", pad.get_name(), caps.to_string()
+
+        # We store the caps and length in the proper location
+#        if "audio" in caps.to_string():
+#            self.audiocaps = caps
+#            self.audiolength = length
+#            self.audiorate = caps[0]["rate"]
+#            self.audiowidth = caps[0]["width"]
+#            self.audiochannels = caps[0]["channels"]
+#            if "x-raw-float" in caps.to_string():
+#                self.audiofloat = True
+#            else:
+#                self.audiodepth = caps[0]["depth"]
+#            if (not self.is_video) or self.videocaps:
+#                self._finished(True)
+#        elif "video" in caps.to_string():
+#            self.videocaps = caps
+#            self.videolength = length
+#            self.videowidth = caps[0]["width"]
+#            self.videoheight = caps[0]["height"]
+#            self.videorate = caps[0]["framerate"]
+#            if (not self.is_audio) or self.audiocaps:
+#                self._finished(True)
+
+    def _new_decoded_pad_cb(self, dbin, pad, is_last):
+        # Does the file contain got audio or video ?
+        caps = pad.get_caps()
+        gst.info("caps:%s" % caps.to_string())
+#        print "_new_decoded_pad_cb", pad.get_name(),caps.to_string() ##!! get_name
+        self.streams[pad.get_name()] = caps.to_string()
+#        if "audio" in caps.to_string():
+#            self.is_audio = True
+#        elif "video" in caps.to_string():
+#            self.is_video = True
+#        else:
+#            self.warning("got a different caps.. %s" % caps.to_string())
+#            return
+#        if is_last and not self.is_video and not self.is_audio:
+#            self._finished(False)
+#            return
+        # we connect a fakesink to the new pad...
+#        pad.info("adding queue->fakesink")
+#        fakesink = gst.element_factory_make("fakesink")
+#        queue = gst.element_factory_make("queue")
+#        self.add(fakesink, queue)
+#        queue.link(fakesink)
+#        sinkpad = fakesink.get_pad("sink")
+#        queuepad = queue.get_pad("sink")
+        # ... and connect a callback for when the caps are fixed
+#        sinkpad.connect("notify::caps", self._notify_caps_cb)
+#        if pad.link(queuepad):
+#            pad.warning("##### Couldn't link pad to queue")
+#        queue.set_state(gst.STATE_PLAYING)
+#        fakesink.set_state(gst.STATE_PLAYING)
+        gst.info('finished here')
+
+    def getStreams(self):
+        return self.streams
+
+    def getMIME(self):
+        return self.mimetype
+
+    def getSource(self):
+        return self.filename
\ No newline at end of file

Added: trunk/souffleur/gstfile.py
===================================================================
--- trunk/souffleur/gstfile.py	2006-06-20 16:49:52 UTC (rev 11593)
+++ trunk/souffleur/gstfile.py	2006-06-20 18:41:37 UTC (rev 11594)
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# -*- Mode: Python -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+# gstfile.py
+# (c) 2005 Edward Hervey <edward at fluendo dot com>
+# Discovers and prints out multimedia information of files
+
+# This example shows how to use gst-python:
+# _ in an object-oriented way (Discoverer class)
+# _ subclassing a gst.Pipeline
+# _ and overidding existing methods (do_iterate())
+
+# (c) 2006 Maxim Litvinov (aka DarakuTenshi) <otaky at ukr dot net>
+# Adapt to Souffleur project use
+
+import os
+import sys
+
+import gobject
+
+import pygst
+pygst.require('0.10')
+
+from discoverer import Discoverer
+
+class GstFile:
+    """
+    Analyses one or more files and prints out the multimedia information of
+    each file.
+    """
+
+    def __init__(self, file):
+        self.file = file
+        self.mainloop = gobject.MainLoop()
+        self.current = None
+    
+    def __destroy__(self):
+        if self.file:
+            del self.file
+        if self.mainloop:
+            del self.mainloop
+        if self.current:
+            del self.current
+    
+    def run(self):
+        gobject.idle_add(self._discover_one)
+        self.mainloop.run()
+
+    def _discovered(self, discoverer, ismedia):
+        self.STREAMS=discoverer.getStreams()
+        self.current = None
+
+        self.SOURCE = discoverer.getSource()
+        self.MIME = discoverer.getMIME()
+
+        self.mainloop.quit()
+#        gobject.idle_add(self._discover_one)
+        
+    def _discover_one(self):
+        if not self.file:
+            gobject.idle_add(self.mainloop.quit)
+            return False
+        filename = self.file
+        if not os.path.isfile(filename):
+            gobject.idle_add(self._discover_one)
+            return False
+#        print "Running on", filename
+        # create a discoverer for that file
+        self.current = Discoverer(filename)
+        # connect a callback on the 'discovered' signal
+        self.current.connect('discovered', self._discovered)
+        # start the discovery
+        self.current.discover()
+        return False

Modified: trunk/souffleur/souffleur.glade
===================================================================
--- trunk/souffleur/souffleur.glade	2006-06-20 16:49:52 UTC (rev 11593)
+++ trunk/souffleur/souffleur.glade	2006-06-20 18:41:37 UTC (rev 11594)
@@ -583,6 +583,7 @@
 
 	      <child>
 		<widget class="GtkVBox" id="vbox6">
+		  <property name="border_width">8</property>
 		  <property name="visible">True</property>
 		  <property name="homogeneous">False</property>
 		  <property name="spacing">8</property>
@@ -710,6 +711,7 @@
 
 	      <child>
 		<widget class="GtkVBox" id="vbox7">
+		  <property name="border_width">8</property>
 		  <property name="visible">True</property>
 		  <property name="homogeneous">False</property>
 		  <property name="spacing">8</property>
@@ -922,8 +924,8 @@
 			  <property name="editable">True</property>
 			  <property name="overwrite">False</property>
 			  <property name="accepts_tab">True</property>
-			  <property name="justification">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap_mode">GTK_WRAP_NONE</property>
+			  <property name="justification">GTK_JUSTIFY_CENTER</property>
+			  <property name="wrap_mode">GTK_WRAP_WORD</property>
 			  <property name="cursor_visible">True</property>
 			  <property name="pixels_above_lines">0</property>
 			  <property name="pixels_below_lines">0</property>



More information about the commits mailing list