[xiph-commits] r11758 - trunk/souffleur

daraku at svn.xiph.org daraku at svn.xiph.org
Thu Aug 10 08:04:06 PDT 2006


Author: daraku
Date: 2006-08-10 08:03:56 -0700 (Thu, 10 Aug 2006)
New Revision: 11758

Added:
   trunk/souffleur/MediaInfo.py
   trunk/souffleur/SouffleurXML.py
   trunk/souffleur/streams.py
Removed:
   trunk/souffleur/discoverer.py
   trunk/souffleur/gstfile.py
Modified:
   trunk/souffleur/Souffleur.py
   trunk/souffleur/Subtitles.py
   trunk/souffleur/souffleur.glade
Log:
Some optimize in GUI.
Fixe error in cb_subChangeSave function.
Added subUpdate function to Subtitles class.
Added functions to subtitles list window support.
Added Media and Stream class.
Replace Discoverer with MediaInfo class.
Added OggBin class for extracting media info from ogg files.
Added SouffleurXML class.
Added Project file save function.


Added: trunk/souffleur/MediaInfo.py
===================================================================
--- trunk/souffleur/MediaInfo.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/MediaInfo.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -0,0 +1,479 @@
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import pygst
+pygst.require('0.10')
+
+import gst
+import gobject
+import os.path
+from gst.extend.pygobject import gsignal
+import gst.interfaces
+
+from string import replace
+from streams import Media
+from streams import Stream
+
+
+UNKNOWN = 0
+SUCCESS = 1
+FAILURE = 2
+CANCELLED = 3
+
+
+class DiscoverMIMEBin(gst.Pipeline):
+    __gsignals__ = {
+        'mime_found' : (gobject.SIGNAL_RUN_FIRST,
+                        None,
+                        (gobject.TYPE_BOOLEAN, ))
+        }
+    
+    mimetype = None
+    finished = False
+
+
+    def __init__(self, filename):
+        gobject.GObject.__init__(self)
+
+
+        self.filename = filename
+        self.mimetype = None
+
+        self.finished = False
+        self._success = False
+
+        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)
+
+    def _finished(self, success=False):
+        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.finished = True
+        self.set_state(gst.STATE_READY)
+        self.emit('mime_found', self._success)
+        
+
+    def _bus_message_cb(self, bus, message):
+        if message.type == gst.MESSAGE_EOS:
+            self._finished()
+        elif message.type == gst.MESSAGE_ERROR:
+            self._finished()
+
+    def discover(self):
+        if self.finished:
+            self.emit('mime_found', 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)
+        
+        if not self.set_state(gst.STATE_PLAYING):
+            self._finished()
+
+
+    def _have_type_cb(self, typefind, prob, caps):
+        self.mimetype = caps.to_string()
+        self._finished()
+
+    def getMIME(self):
+        return self.mimetype
+
+    def getSource(self):
+        return self.filename
+
+class DiscoverMIME:
+    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.current = None
+
+        self.SOURCE = discoverer.getSource()
+        self.MIME = discoverer.getMIME()
+
+        self.mainloop.quit()
+        
+    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
+        # create a discoverer for that file
+        self.current = DiscoverMIMEBin(filename)
+        # connect a callback on the 'discovered' signal
+        self.current.connect('mime_found', self._discovered)
+        # start the discovery
+        self.current.discover()
+        return False
+
+    def getMIME(self):
+        return self.MIME
+
+class MediaInfo(gst.Pipeline):
+
+    def __init__(self, URI, FN,lastID):
+        # HACK: should do Pipeline.__init__, but that doesn't do what we
+        # want; there's a bug open aboooot that
+        self.__gobject_init__()
+
+        self.fromuri = URI
+        self.filename = FN
+        self.lastID = lastID
+        self.src = self.remuxbin = self.sink = None
+        self.resolution = UNKNOWN
+
+        self.window = None
+
+        self.media=Media()
+
+        self._query_id = -1
+
+    def do_setup_pipeline(self):
+        self.src = gst.element_make_from_uri(gst.URI_SRC, self.fromuri)
+        dMIME = DiscoverMIME(self.filename)
+        dMIME.run()
+        self.MIME = dMIME.getMIME()
+        self.media.MIME=self.MIME
+        self.media.source=self.filename
+        self.media.sourceURI=self.fromuri
+        if self.MIME == "application/ogg":
+            self.remuxbin = OggBin(self.lastID, self.media)
+        else:
+            self.remuxbin = DefaultBin(self.lastID, self.media)
+        self.remuxbin.connect('done', self._finished)
+        self.sink = gst.element_factory_make("fakesink")
+        self.resolution = UNKNOWN
+
+        if gobject.signal_lookup('allow-overwrite', self.sink.__class__):
+            self.sink.connect('allow-overwrite', lambda *x: True)
+
+        self.add(self.src, self.remuxbin, self.sink)
+
+        self.src.link(self.remuxbin)
+        self.remuxbin.link(self.sink)
+
+    def _start_queries(self):
+        def do_query():
+            try:
+                # HACK: self.remuxbin.query() should do the same
+                # (requires implementing a vmethod, dunno how to do that
+                # although i think it's possible)
+                # HACK: why does self.query_position(..) not give useful
+                # answers? 
+                pad = self.remuxbin.get_pad('src')
+                pos, format = pad.query_position(gst.FORMAT_TIME)
+                duration, format = pad.query_duration(gst.FORMAT_TIME)
+                #print (pos*100.0)/duration
+            except:
+                pass
+            return True
+        if self._query_id == -1:
+            self._query_id = gobject.timeout_add(100, # 10 Hz
+                                                 do_query)
+
+    def _stop_queries(self):
+        if self._query_id != -1:
+            gobject.source_remove(self._query_id)
+            self._query_id = -1
+
+    def _bus_watch(self, bus, message):
+        if message.type == gst.MESSAGE_ERROR:
+            print 'error', message
+            self._stop_queries()
+            m = gtk.MessageDialog(self.window,
+                                  gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+                                  gtk.MESSAGE_ERROR,
+                                  gtk.BUTTONS_CLOSE,
+                                  "Error processing file")
+            gerror, debug = message.parse_error()
+            txt = ('There was an error processing your file: %s\n\n'
+                   'Debug information:\n%s' % (gerror, debug))
+            m.format_secondary_text(txt)
+            m.run()
+            m.destroy()
+            self.response(FAILURE)
+        elif message.type == gst.MESSAGE_WARNING:
+            print 'warning', message
+        elif message.type == gst.MESSAGE_STATE_CHANGED:
+            if message.src == self:
+                old, new, pending = message.parse_state_changed()
+                if ((old, new, pending) ==
+                    (gst.STATE_READY, gst.STATE_PAUSED,
+                     gst.STATE_VOID_PENDING)):
+                    self._start_queries()
+                    self.set_state(gst.STATE_PLAYING)
+        elif message.type == gst.MESSAGE_EOS:
+            self._finished(True)
+
+    def _finished(self, success=False):
+        self.bus.remove_signal_watch()
+        gobject.idle_add(self._stop)
+        return False
+
+    def _stop(self):
+        self.set_state(gst.STATE_READY)
+        self.response(SUCCESS)
+
+    def response(self, response):
+        assert self.resolution == UNKNOWN
+        self.resolution = response
+        self.set_state(gst.STATE_NULL)
+        self.loop.quit()
+
+    def start(self):
+        self.do_setup_pipeline()
+        self.bus = self.get_bus()
+        self.bus.add_signal_watch()
+        self.bus.connect('message', self._bus_watch)
+
+        self.set_state(gst.STATE_PAUSED)
+        return True
+        
+    def run(self):
+        if self.start():
+            self.loop = gobject.MainLoop()
+            self.loop.run()
+        else:
+            self.resolution = CANCELLED
+        return self.resolution
+
+    def getMedia(self):
+        return self.media
+
+class OggBin(gst.Bin):
+    __gsignals__ = {
+        'done' : (gobject.SIGNAL_RUN_FIRST,
+                        None, ())
+                        #(gobject.TYPE_BOOLEAN, ))
+        }
+
+    def __init__(self, ID, MEDIA):
+        self.__gobject_init__()
+
+        self.startID=ID
+        self.media=MEDIA
+
+
+        self.parsefactories = self._find_parsers()
+        self.parsers = []
+
+        self.demux = gst.element_factory_make('oggdemux')
+        self.mux = gst.element_factory_make('oggmux')
+
+        self.add(self.demux, self.mux)
+
+        self.add_pad(gst.GhostPad('sink', self.demux.get_pad('sink')))
+        self.add_pad(gst.GhostPad('src', self.mux.get_pad('src')))
+
+        self.demux.connect('pad-added', self._new_demuxed_pad)
+        self.demux.connect('no-more-pads', self._no_more_pads)
+
+    def _no_more_pads(self, elem):
+        self.post_message(gst.message_new_eos(elem))
+        self.emit('done')
+        return False
+
+    def _find_parsers(self):
+        registry = gst.registry_get_default()
+        ret = {}
+        for f in registry.get_feature_list(gst.ElementFactory):
+            #print "Parser: ", f.get_name(), f.get_klass()
+            #if f.get_name().find('parse') >= 0:
+            if f.get_klass().find('Parser') >= 0:
+                for t in f.get_static_pad_templates():
+                    if t.direction == gst.PAD_SINK:
+                        for s in t.get_caps():
+                            ret[s.get_name()] = f.get_name()
+                            #print f.get_name(), s.get_name(), f.get_klass()
+                        #break
+        return ret
+
+    def _pad_have_data(self, pad, buffer, udata):
+        #Name = pad.get_caps().to_string()
+        #LEN = len(buffer)
+        #if len(buffer)>3:
+        #if udata == "serial_00000004":
+        #if buffer.flag_is_set(gst.BUFFER_FLAG_LAST):
+        #    print "last:"
+        #if (LEN>4):
+            #if ("text" not in buffer[1:5]) and ("vorbis" not in buffer[1:7]):
+        #        print buffer.duration, buffer.offset, buffer.timestamp, buffer.offset_end, buffer.size, udata , "\n\t", str(buffer[3:-1])
+        #else:
+        #        print buffer.duration, buffer.offset_end, buffer.size, udata, "\n\tstop" 
+        #print buffer.timestamp, buffer.src
+        return True
+
+    def _new_demuxed_pad(self, element, pad):
+        format = pad.get_caps()[0].get_name()
+        #print pad.get_name(), pad.get_caps().to_string()
+        if "text" in format:
+            pad.add_buffer_probe(self._pad_have_data, pad.get_name())
+
+        #print "format: ", format
+        nStream=Stream()
+        nStream.MIME=format
+        nStream.Name=pad.get_name()
+        self.startID=self.startID+1
+        nStream.ID=self.startID
+        self.media.addStream(nStream)
+        if format not in self.parsefactories:
+            #self.async_error("Unsupported media type: %s", format)
+            return
+
+        queue = gst.element_factory_make('queue', 'queue_' + pad.get_name())
+        parser = gst.element_factory_make(self.parsefactories[format])
+        self.add(queue)
+        self.add(parser)
+        queue.set_state(gst.STATE_PAUSED)
+        parser.set_state(gst.STATE_PAUSED)
+        pad.link(queue.get_compatible_pad(pad))
+        queue.link(parser)
+        if "text" not in format:
+            parser.link(self.mux)
+        self.parsers.append(parser)
+
+class DefaultBin(gst.Bin):
+    __gsignals__ = {
+        'done' : (gobject.SIGNAL_RUN_FIRST,
+                        None, ())
+                        #(gobject.TYPE_BOOLEAN, ))
+        }
+
+    def __init__(self, ID, MEDIA):
+        self.__gobject_init__()
+
+        self.startID=ID
+        self.media=MEDIA
+
+
+        self.parsefactories = self._find_parsers()
+        self.parsers = []
+
+        self.demux = gst.element_factory_make('decodebin')
+        self.mux = gst.element_factory_make('oggmux')
+
+        self.add(self.demux, self.mux)
+
+        self.add_pad(gst.GhostPad('sink', self.demux.get_pad('sink')))
+        self.add_pad(gst.GhostPad('src', self.mux.get_pad('src')))
+
+        self.demux.connect('pad-added', self._new_demuxed_pad)
+        self.demux.connect('no-more-pads', self._no_more_pads)
+
+    def _no_more_pads(self, elem):
+        self.post_message(gst.message_new_eos(elem))
+        self.emit('done')
+        return False
+
+    def _find_parsers(self):
+        registry = gst.registry_get_default()
+        ret = {}
+        for f in registry.get_feature_list(gst.ElementFactory):
+            #print "Parser: ", f.get_name(), f.get_klass()
+            #if f.get_name().find('parse') >= 0:
+            if f.get_klass().find('Parser') >= 0:
+                for t in f.get_static_pad_templates():
+                    if t.direction == gst.PAD_SINK:
+                        for s in t.get_caps():
+                            ret[s.get_name()] = f.get_name()
+                            #print f.get_name(), s.get_name(), f.get_klass()
+                        #break
+        return ret
+
+    def _pad_have_data(self, pad, buffer, udata):
+        #Name = pad.get_caps().to_string()
+        #LEN = len(buffer)
+        #if len(buffer)>3:
+        #if udata == "serial_00000004":
+        #if buffer.flag_is_set(gst.BUFFER_FLAG_LAST):
+        #    print "last:"
+        #if (LEN>4):
+            #if ("text" not in buffer[1:5]) and ("vorbis" not in buffer[1:7]):
+        #        print buffer.duration, buffer.offset, buffer.timestamp, buffer.offset_end, buffer.size, udata , "\n\t", str(buffer[3:-1])
+        #else:
+        #        print buffer.duration, buffer.offset_end, buffer.size, udata, "\n\tstop" 
+        #print buffer.timestamp, buffer.src
+        return True
+
+    def _new_demuxed_pad(self, element, pad):
+        format = pad.get_caps()[0].get_name()
+        #print pad.get_name(), pad.get_caps().to_string()
+        #if "text" in format:
+        #    pad.add_buffer_probe(self._pad_have_data, pad.get_name())
+
+        #print "format: ", format
+        nStream=Stream()
+        nStream.MIME=format
+        nStream.Name=pad.get_name()
+        self.startID=self.startID+1
+        nStream.ID=self.startID
+        self.media.addStream(nStream)
+        if format not in self.parsefactories:
+            #self.async_error("Unsupported media type: %s", format)
+            return
+
+        #queue = gst.element_factory_make('queue', 'queue_' + pad.get_name())
+        #parser = gst.element_factory_make(self.parsefactories[format])
+        #self.add(queue)
+        #self.add(parser)
+        #queue.set_state(gst.STATE_PAUSED)
+        #parser.set_state(gst.STATE_PAUSED)
+        #pad.link(queue.get_compatible_pad(pad))
+        #queue.link(parser)
+        #if "text" not in format:
+        #    parser.link(self.mux)
+        #self.parsers.append(parser)

Modified: trunk/souffleur/Souffleur.py
===================================================================
--- trunk/souffleur/Souffleur.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/Souffleur.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -23,6 +23,11 @@
 #from datetime import time
 import sys
 
+from streams import Media
+from streams import Stream
+from MediaInfo import MediaInfo
+from SouffleurXML import ProjectXML
+
 try:
     import pygtk
     #tell pyGTK, if possible, that we want GTKv2
@@ -60,10 +65,15 @@
         self.UPDATE_INTERVAL=100
         
         self.Subtitle = None
+        self.Subtitles = []
         self.curSub = -1
         self.scroll = 0
-        self.videoWidgetGst=None
-        self.player=None
+        self.videoWidgetGst = None
+        self.player = None
+        self.t_duration = 0
+        
+        self.media = []
+        self.lastID=0
         #self.videoWidget=VideoWidget();
         #gtk.glade.set_custom_handler(self.videoWidget, VideoWidget())
 
@@ -91,10 +101,12 @@
             "on_TOOL_END_clicked": self.cb_setSubEndTime,\
             "on_TOOL_SAVE_clicked": self.cb_subChangeSave,\
             "on_TOOL_DELETE_clicked": self.cb_subDel,\
-            "on_main_file_save_activate": self.cb_onSaveMenu}
+            "on_main_file_save_activate": self.cb_onSaveMenu,\
+            "on_LIST_SUBS_cursor_changed": self.cb_onSubsListSelect}
         self.wTree.signal_autoconnect (dic)
         
         self.windowFileOpen=None
+        self.windowProjectSO=None
         self.windowStreams=gtk.glade.XML (self.gladefile,"STREAM_WINDOW")
         ### Setup LIST_STREAMS
         LIST = self.windowStreams.get_widget("LIST_STREAMS")
@@ -104,8 +116,29 @@
             cell = gtk.CellRendererText()
             tvcolumn = gtk.TreeViewColumn('Streams', cell, text = 0)
             LIST.append_column(tvcolumn)
+        
+        self.windowSubsList=gtk.glade.XML (self.gladefile,"SUBS_LIST")
+        dic = {"on_LIST_SUBS_cursor_changed": self.cb_onSubsListSelect}
+        self.windowSubsList.signal_autoconnect (dic)
+        SUBLIST = self.windowSubsList.get_widget("LIST_SUBS")
+        if SUBLIST:
+            self.subsListStore = gtk.ListStore(gobject.TYPE_UINT,
+                                                gobject.TYPE_UINT,
+                                                gobject.TYPE_STRING)
+            SUBLIST.set_model(self.subsListStore)
+            cell = gtk.CellRendererText()
+            tvcolumn = gtk.TreeViewColumn('Start', cell, text = 0)
+            SUBLIST.append_column(tvcolumn)
+            cell = gtk.CellRendererText()
+            tvcolumn = gtk.TreeViewColumn('End', cell, text = 1)
+            SUBLIST.append_column(tvcolumn)
+            cell = gtk.CellRendererText()
+            tvcolumn = gtk.TreeViewColumn('Text', cell, text = 2)
+            SUBLIST.append_column(tvcolumn)
         WND=self.windowStreams.get_widget("STREAM_WINDOW")
         WND.hide()
+        WND=self.windowSubsList.get_widget("SUBS_LIST")
+        WND.hide()
         ### Main window setup
         self.videoWidget = self.wTree.get_widget("VIDEO_OUT_PUT")
         self.adjustment = self.wTree.get_widget("MEDIA_ADJUSTMENT")
@@ -119,9 +152,104 @@
         self.playButton = self.wTree.get_widget("TOOL_PLAY")
         return
 #==============================================================================
+    def setEditSubtitle(self, Sub):
+        if not self.Subtitle:
+            return
+        if Sub == None:
+            if (self.curSub!=-1):
+                BUF=gtk.TextBuffer()
+                BUF.set_text("")
+                self.SubEdit.set_buffer(BUF)
+                self.curSub=-1
+                self.setSubStartTime(0)
+                self.setSubEndTime(0)
+        else:
+            if (Sub.start_time!=self.curSub):
+                BUF=gtk.TextBuffer()
+                BUF.set_text(Sub.text)
+                self.SubEdit.set_buffer(BUF)
+                self.curSub=int(Sub.start_time)
+                self.setSubStartTime(Sub.start_time)
+                self.setSubEndTime(Sub.end_time)
+#==============================================================================
+    def cb_onSubsListSelect(self, widget):
+        Row=None
+        Selection = widget.get_selection()
+        if Selection==None:
+            return
+        Model, Rows = Selection.get_selected_rows()
+        if Rows != None:
+            Row = Model[Rows[0][0]]
+            if self.Subtitle:
+                Sub = self.Subtitle.subs[Row[0]]
+                self.setEditSubtitle(Sub)
+                if self.player:
+                    B=0;
+                    if self.player.is_playing():
+                        B=1
+                        self.play_toggled()
+                    real = long(Row[0]) # in ns
+                    self.player.seek(real*1000000)
+                    # allow for a preroll
+                    self.player.get_state(timeout=50*gst.MSECOND) # 50 ms
+                    if B==1:
+                        self.play_toggled()
+#==============================================================================
+    def subsWindowUpdate(self):
+        if (self.windowSubsList):
+            self.subsListStore.clear()
+            for i in self.Subtitle.subKeys:
+                S=self.Subtitle.subs[i]
+                iter = self.subsListStore.append(None)
+                self.subsListStore.set(iter, 0, S.start_time,
+                                            1, S.end_time,
+                                            2, S.text)
+#==============================================================================
+    def cb_projectOpenOpen(self, widget):
+        WND=self.windowProjectSO.get_widget("SAVE_OPEN_PFILE")
+        FN=WND.get_filename()
+        if FN[-4:]!=".spf":
+            FN=FN+".spf"
+        PXML=ProjectXML()
+        PXML.addHeadInfo("title", "Soufleur development version")
+        PXML.addHeadInfo("desc", "This is version current at development stage.")
+        PXML.addHeadInfo("author", "DarakuTenshi")
+        PXML.addHeadInfo("email", "otaky at ukr.net")
+        PXML.addHeadInfo("info", "Sample of save function")
+        for i in self.media:
+            PXML.addMedia(i)
+        for i in self.Subtitles:
+            PXML.addSubtitle(i)
+        PXML.write(FN)
+        WND.hide()
+#==============================================================================
+    def cb_projectSaveCancel(self, widget):
+        if(self.windowProjectSO==None): return
+        WND=self.windowProjectSO.get_widget("SAVE_OPEN_PFILE")
+        WND.hide()
+#==============================================================================
     def cb_onSaveMenu(self, widget):
-        if (self.Subtitle != None):
-            self.Subtitle.subSave(1)
+        if(self.windowProjectSO==None):
+            self.windowProjectSO=gtk.glade.XML (self.gladefile,"SAVE_OPEN_PFILE")
+            dic={"on_PROJECT_BUTTON_CANCEL_clicked": self.cb_projectSaveCancel,\
+                "on_PROJECT_BUTTON_OK_clicked": self.cb_projectOpenOpen }
+            self.windowProjectSO.signal_autoconnect(dic)
+            WND=self.windowProjectSO.get_widget("SAVE_OPEN_PFILE")
+            WND.set_action(gtk.FILE_CHOOSER_ACTION_SAVE)
+            OKB = self.windowProjectSO.get_widget("PROJECT_BUTTON_OK")
+            OKB.set_label("gtk-save")
+            OKB.set_use_stock(True)
+            Filter=gtk.FileFilter()
+            Filter.set_name("Souffleur project file")
+            Filter.add_pattern("*.spf")
+            WND.add_filter(Filter)
+        else:
+            WND=self.windowProjectSO.get_widget("SAVE_OPEN_PFILE")
+            if(WND==None):
+                self.windowProjectSO=None
+                self.cb_onSaveMenu(widget)
+            else:
+                WND.show()
 #==============================================================================
     def cb_subDel(self, widget):
         if (self.Subtitle != None) and (self.curSub != -1):
@@ -133,8 +261,13 @@
                 BUF = self.SubEdit.get_buffer()
                 TEXT = BUF.get_text(BUF.get_start_iter(), BUF.get_end_iter())
                 self.Subtitle.subs[int(self.curSub)].text = str(TEXT)
-                self.Subtitle.subs[int(self.curSub)].start_time=self.subStartTime.get_value_as_int()
                 self.Subtitle.subs[int(self.curSub)].end_time=self.subEndTime.get_value_as_int()
+                if self.Subtitle.subs[int(self.curSub)].start_time!=self.subStartTime.get_value_as_int():
+                    newTime=self.subStartTime.get_value_as_int()
+                    self.Subtitle.subs[int(self.curSub)].start_time=newTime
+                    self.Subtitle.subUpdate(int(self.curSub))
+                    self.curSub = newTime
+                self.subsWindowUpdate()
             else:
                 self.subAdd()
 #==============================================================================
@@ -165,7 +298,7 @@
 #==============================================================================
     def changeValueAdjustment(self, widget, t1, t2):
         #if (not self.scroll):
-            real = long(self.adjustment.get_value() * self.p_duration / 100) # in ns
+            real = long(self.adjustment.get_value()) # in ns
             self.player.seek(real)
             # allow for a preroll
             self.player.get_state(timeout=50*gst.MSECOND) # 50 ms
@@ -216,39 +349,45 @@
     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)
-#   	    print FN
-            Streams = GstFile(FN)
-            if Streams:
-                Streams.run()
+        URI=WND.get_uri()
+        mInfo = MediaInfo(URI, FN, self.lastID)
+        mInfo.run()
+        #Streams = None
+        #if((FN!="")and(FN!=None)):
+        #    Streams = GstFile(FN)
+        #    if Streams:
+        #        Streams.run()
+        
         WND.hide()
         WND=self.windowStreams.get_widget("STREAM_WINDOW")
         WND.show()
-        self.addStreams(Streams)
-#   	self.refreshStreamsWindow()
+        self.addMedia(mInfo.getMedia())
         return
 #==============================================================================
-    def loadSubtitle(self, FileName):
-        pass
-#==============================================================================
-    def addStreams(self, Streams):
-        if not Streams:
+    def addMedia(self, mInfo):
+        if not mInfo:
             return
+        self.media.append(mInfo)
+        self.lastID = mInfo.lastID
         iter = self.streamsTreeStore.append(None)
-        self.streamsTreeStore.set(iter, 0, Streams.MIME + " " + Streams.SOURCE)
-        for i in Streams.STREAMS.keys():
+        self.streamsTreeStore.set(iter, 0, mInfo.MIME + " ("+mInfo.source+")")
+        for i in mInfo.Streams:
             child = self.streamsTreeStore.append(iter)
-            self.streamsTreeStore.set(child, 0, i +" " + Streams.STREAMS[i])
-            print i +" " + Streams.STREAMS[i]
-        if "subtitle" in Streams.MIME:
+            self.streamsTreeStore.set(child, 0, i.MIME + " ("+i.Name+")")
+            #print i +" " + Streams.STREAMS[i]
+        if "subtitle" in mInfo.MIME:
             self.Subtitle = Subtitles()
-            self.Subtitle.subLoad(Streams.SOURCE)
+            self.Subtitle.subLoad(mInfo.source, mInfo.Streams[0].ID)
+            self.Subtitles.append(self.Subtitle)
+            if (self.windowStreams):
+                WND=self.windowSubsList.get_widget("SUBS_LIST")
+                WND.show()
+                self.subsWindowUpdate()
+                
         else:
             self.videoWidgetGst=VideoWidget(self.videoWidget)
             self.player=GstPlayer(self.videoWidgetGst)
-            self.player.set_location("file://"+Streams.SOURCE)
+            self.player.set_location("file://"+mInfo.source)
             if self.videoWidget.flags() & gtk.REALIZED:
                 self.play_toggled()
             else:
@@ -271,6 +410,9 @@
     def update_scale_cb(self):
         had_duration = self.p_duration != gst.CLOCK_TIME_NONE
         self.p_position, self.p_duration = self.player.query_position()
+        if self.p_duration != self.t_duration:
+            self.t_duration = self.p_duration
+            self.adjustment.set_range(0, self.t_duration)
         tmSec= self.p_position/1000000
         MSec = tmSec
         tmSec = tmSec/1000
@@ -281,28 +423,16 @@
         if self.Subtitle:
             TText = self.Subtitle.getSub(MSec)
             if TText:
-                if (TText.start_time!=self.curSub):
-                    BUF=gtk.TextBuffer()
-                    BUF.set_text(TText.text)
-                    self.SubEdit.set_buffer(BUF)
-                    self.curSub=int(TText.start_time)
-                    self.setSubStartTime(TText.start_time)
-                    self.setSubEndTime(TText.end_time)
+                self.setEditSubtitle(TText)
             else:
-                if (self.curSub!=-1):
-                    BUF=gtk.TextBuffer()
-                    BUF.set_text("")
-                    self.SubEdit.set_buffer(BUF)
-                    self.curSub=-1
-                    self.setSubStartTime(0)
-                    self.setSubEndTime(0)
+                self.setEditSubtitle(None)
         if (self.p_position != gst.CLOCK_TIME_NONE):# and (not self.scroll):
-            value = self.p_position * 100.0 / self.p_duration
+            value = self.p_position
             self.adjustment.set_value(value)
-        self.labelHour.set_text(str(Hour))
-        self.labelMin.set_text(str(Min))
-        self.labelSec.set_text(str(Sec))
-        self.labelMSec.set_text(str(MSec))
+        self.labelHour.set_text("%02d"%Hour)
+        self.labelMin.set_text("%02d"%Min)
+        self.labelSec.set_text("%02d"%Sec)
+        self.labelMSec.set_text("%09d"%MSec)
         return True
 #==============================================================================
 #	MAIN:

Added: trunk/souffleur/SouffleurXML.py
===================================================================
--- trunk/souffleur/SouffleurXML.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/SouffleurXML.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -0,0 +1,211 @@
+import xml.dom.minidom
+
+from streams import Media
+from streams import Stream
+
+from Subtitles import Sub
+from Subtitles import Subtitles
+
+class ProjectXML:
+    def __init__(self):
+        self.impl = xml.dom.minidom.getDOMImplementation()
+        self.doc = self.impl.createDocument(None, "souffleur", None)
+        self.root = self.doc.documentElement
+
+        rootAttr= self.doc.createAttribute("type")
+        rootAttr.nodeValue="project"
+
+        self.root.setAttributeNode(rootAttr)
+
+        versionEl = self.doc.createElement("version")
+        versionTxt = self.doc.createTextNode("0")
+        versionEl.appendChild(versionTxt)
+        self.root.appendChild(versionEl)
+
+        self.head = None
+        self.body = None
+        self.version = 0
+
+    def load(self, fileName):
+        self.root = None
+        self.head = None
+        self.body = None
+        self.version = None
+        self.doc = xml.dom.minidom.parse(fileName)
+        if self.doc.documentElement.nodeName != "souffleur":
+            return None
+        self.root=self.doc.documentElement
+        for i in self.root.childNodes:
+            if i.nodeName=="head":
+                self.head=i
+            elif i.nodeName=="body":
+                self.body=i
+            elif i.nodeName=="version":
+                self.version = i.childNode[0].nodeValue
+        return self
+
+    def write(self, fileName):
+        HDLR=file(fileName, "w")
+        self.doc.writexml(HDLR)
+        HDLR.close()
+
+    def addHeadInfo(self, attrName, attrValue):
+        if not self.head:
+            self.head=self.doc.createElement("head")
+        self.root.appendChild(self.head)
+
+        if not attrName or not attrValue:
+            return
+
+        attrEl = self.doc.createElement(attrName)
+        attrTxt = self.doc.createTextNode(attrValue)
+        attrEl.appendChild(attrTxt)
+        self.head.appendChild(attrEl)
+
+    def addMedia(self, media):
+        if not media:
+            return
+        if type(media)!=type(Media()):
+            return
+        if not self.body:
+            self.body=self.doc.createElement("body")
+            self.root.appendChild(self.body)
+
+        data = self.doc.createElement("data")
+        self.body.appendChild(data)
+
+        source = self.doc.createElement("source")
+        sType= self.doc.createAttribute("type")
+        sType.nodeValue=media.MIME
+        source.setAttributeNode(sType)
+        sTxt = self.doc.createTextNode(media.source)
+        source.appendChild(sTxt)
+        data.appendChild(source)
+
+        for i in media.Streams:
+            tmpMedia = self.doc.createElement("media")
+            data.appendChild(tmpMedia)
+
+            tmpEl = self.doc.createElement("type")
+            tmpTxt = self.doc.createTextNode(i.MIME)
+            tmpEl.appendChild(tmpTxt)
+            tmpMedia.appendChild(tmpEl)
+
+            tmpEl = self.doc.createElement("name")
+            tmpTxt = self.doc.createTextNode(i.Name)
+            tmpEl.appendChild(tmpTxt)
+            tmpMedia.appendChild(tmpEl)
+
+            tmpEl = self.doc.createElement("id")
+            tmpTxt = self.doc.createTextNode(str(i.ID))
+            tmpEl.appendChild(tmpTxt)
+            tmpMedia.appendChild(tmpEl)
+
+            if not i.attrs:
+                continue
+
+            attrs = self.doc.createElement("attrs")
+            tmpMedia.appendChild(attrs)
+            for j in i.attrs.keys():
+                tmpEl = self.doc.createElement(j)
+                tmpTxt = self.doc.createTextNode(i.attrs[j])
+                tmpEl.appendChild(tmpTxt)
+                attrs.appendChild(tmpEl)
+
+
+    def addSubtitle(self, subtitle):
+        if not subtitle:
+            return
+        if type(subtitle)!=type(Subtitles()):
+            return
+        if not self.body:
+            self.body=self.doc.createElement("body")
+            self.root.appendChild(self.body)
+
+        data = self.doc.createElement("subtitles")
+        self.body.appendChild(data)
+
+        source = self.doc.createElement("source")
+        sTxt = self.doc.createTextNode(str(subtitle.subSource))
+        source.appendChild(sTxt)
+        data.appendChild(source)
+
+        for i in subtitle.subKeys:
+            sub = self.doc.createElement("sub")
+            tmpEl = self.doc.createElement("start")
+            tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].start_time))
+            tmpEl.appendChild(tmpTxt)
+            sub.appendChild(tmpEl)
+            tmpEl = self.doc.createElement("end")
+            tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].end_time))
+            tmpEl.appendChild(tmpTxt)
+            sub.appendChild(tmpEl)
+            tmpEl = self.doc.createElement("text")
+            tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].text))
+            tmpEl.appendChild(tmpTxt)
+            sub.appendChild(tmpEl)
+            data.appendChild(sub)
+
+    def getHead(self):
+        if not self.head:
+            return None
+        ret={}
+        for i in self.head.childNodes:
+            ret[i.nodeName]=i.childNodes[0].nodeValue
+        return ret
+
+    def getMedia(self):
+        if not self.body:
+            return None
+        ret=[]
+        for i in self.body.childNodes:
+            if i.nodeName=="data":
+                tMedia=Media()
+                for j in i.childNodes:
+                    if j.nodeName=="source":
+                        mType=j.attributes["type"]
+                        if not mType:
+                            return None
+                        tMedia.MIME=mType.nodeValue
+                        tMedia.source=j.childNodes[0].nodeValue
+                    elif j.nodeName=="media":
+                        tStream = Stream()
+                        for k in j.childNodes:
+                            nodeName = k.nodeName
+                            if nodeName == "type":
+                                tStream.MIME = k.childNodes[0].nodeValue
+                            elif nodeName == "id":
+                                tStream.ID = k.childNodes[0].nodeValue
+                            elif nodeName == "name":
+                                tStream.name = k.childNodes[0].nodeValue
+                            elif nodeName == "attrs":
+                                for l in k.childNodes:
+                                    tStream.addAttr(l.nodeName, l.childNodes[0].nodeValue)
+                            tMedia.addStream(tStream)
+                ret.append(tMedia)
+        return ret
+
+    def getSubtitle(self):
+        if not self.body:
+            return None
+        ret=[]
+        for i in self.body.childNodes:
+            if i.nodeName=="subtitles":
+                tSubtitles=Subtitles()
+                for j in i.childNodes:
+                    if j.nodeName=="source":
+                        tSubtitles.ID=j.childNodes[0].nodeValue
+                    elif j.nodeName=="sub":
+                        tSub=Sub()
+                        for k in j.childNodes:
+                            nodeName = k.nodeName
+                            if nodeName == "start":
+                                tSub.start_time=k.childNodes[0].nodeValue
+                            elif nodeName == "end":
+                                tSub.end_time=k.childNodes[0].nodeValue
+                            elif nodeName == "text":
+                                tSub.text=k.childNodes[0].nodeValue
+                        tSubtitles.subs[tSub.start_time]=tSub
+                        tSubtitles.updateKeys()
+                ret.append(tSubtitles)
+        return ret

Modified: trunk/souffleur/Subtitles.py
===================================================================
--- trunk/souffleur/Subtitles.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/Subtitles.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -1,7 +1,5 @@
 import os
 import string
-#from datetime import time
-#from array import array
 
 SUB_NONE=0
 SUB_SRT=1
@@ -29,7 +27,7 @@
         self.subType=SUB_NONE
         self.subKeys=[]
 #==============================================================================
-    def subLoad(self, fileName):
+    def subLoad(self, fileName, ID):
         FILE=os.open(fileName, os.O_RDONLY)
         FS=os.fstat(FILE)
         DATA=os.read(FILE,FS.st_size)
@@ -37,7 +35,7 @@
 
         self._subSRTLoadFromString(DATA)
 
-        self.subSource=fileName
+        self.subSource=ID
 #==============================================================================    
     def subSave(self, format):
         if (self.subSource!=None):
@@ -94,7 +92,7 @@
                 Text=Text+DATA[i]+"\n"
                 i+=1
             i+=1
-            
+            Text=Text[0:-1]
             ST=int(Timing[0:2])*3600000+int(Timing[3:5])*60000+int(Timing[6:8])*1000+int(Timing[9:12])
             ET=int(Timing[17:19])*3600000+int(Timing[20:22])*60000+int(Timing[23:25])*1000+int(Timing[26:29])
             
@@ -125,6 +123,11 @@
         self.subKeys=self.subs.keys()
         self.subKeys.sort()
 #==============================================================================
+    def subUpdate(self, upSubKey):
+        Sub = self.subs[upSubKey]
+        self.subDel(upSubKey)
+        self.subAdd(Sub.start_time, Sub.end_time, Sub.text, Sub.Attributes, 1)
+#==============================================================================
     def getSub(self, time):
         i=0
         for i in self.subKeys:

Deleted: trunk/souffleur/discoverer.py
===================================================================
--- trunk/souffleur/discoverer.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/discoverer.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -1,322 +0,0 @@
-#!/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

Deleted: trunk/souffleur/gstfile.py
===================================================================
--- trunk/souffleur/gstfile.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/gstfile.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -1,75 +0,0 @@
-#!/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-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/souffleur.glade	2006-08-10 15:03:56 UTC (rev 11758)
@@ -606,7 +606,7 @@
 		  <child>
 		    <widget class="GtkLabel" id="LABEL_MSEC">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes">0000000</property>
+		      <property name="label" translatable="yes">000000000</property>
 		      <property name="use_underline">False</property>
 		      <property name="use_markup">False</property>
 		      <property name="justify">GTK_JUSTIFY_LEFT</property>
@@ -661,14 +661,18 @@
 	      </child>
 
 	      <child>
-		<widget class="GtkHScrollbar" id="MEDIA_ADJUSTMENT">
+		<widget class="GtkHScale" id="MEDIA_ADJUSTMENT">
 		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="draw_value">False</property>
+		  <property name="value_pos">GTK_POS_TOP</property>
+		  <property name="digits">1</property>
 		  <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
 		  <property name="inverted">False</property>
-		  <property name="adjustment">0 0 100 0.10000000149 1 1</property>
-		  <signal name="button_press_event" handler="on_MEDIA_ADJUSTMENT_button_press_event" last_modification_time="Sun, 02 Jul 2006 17:36:01 GMT"/>
-		  <signal name="button_release_event" handler="on_MEDIA_ADJUSTMENT_button_release_event" last_modification_time="Sun, 02 Jul 2006 17:36:13 GMT"/>
-		  <signal name="change_value" handler="on_MEDIA_ADJUSTMENT_change_value" last_modification_time="Sun, 02 Jul 2006 17:37:36 GMT"/>
+		  <property name="adjustment">0 0 100 0.10000000149 0 0</property>
+		  <signal name="change_value" handler="on_MEDIA_ADJUSTMENT_change_value" last_modification_time="Thu, 06 Jul 2006 17:07:04 GMT"/>
+		  <signal name="button_press_event" handler="on_MEDIA_ADJUSTMENT_button_press_event" last_modification_time="Thu, 06 Jul 2006 17:07:08 GMT"/>
+		  <signal name="button_release_event" handler="on_MEDIA_ADJUSTMENT_button_release_event" last_modification_time="Thu, 06 Jul 2006 17:07:14 GMT"/>
 		</widget>
 		<packing>
 		  <property name="padding">0</property>
@@ -1405,6 +1409,8 @@
 	      <property name="fixed_height_mode">False</property>
 	      <property name="hover_selection">False</property>
 	      <property name="hover_expand">False</property>
+	      <signal name="cursor_changed" handler="on_LIST_SUBS_cursor_changed" last_modification_time="Wed, 02 Aug 2006 05:34:48 GMT"/>
+	      <signal name="move_cursor" handler="on_LIST_SUBS_move_cursor" last_modification_time="Wed, 02 Aug 2006 05:42:07 GMT"/>
 	    </widget>
 	  </child>
 	</widget>
@@ -1426,7 +1432,7 @@
   <property name="show_hidden">False</property>
   <property name="do_overwrite_confirmation">False</property>
   <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="window_position">GTK_WIN_POS_CENTER</property>
   <property name="modal">True</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
@@ -1489,4 +1495,75 @@
   </child>
 </widget>
 
+<widget class="GtkFileChooserDialog" id="SAVE_OPEN_PFILE">
+  <property name="visible">True</property>
+  <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+  <property name="local_only">True</property>
+  <property name="select_multiple">False</property>
+  <property name="show_hidden">False</property>
+  <property name="do_overwrite_confirmation">True</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_CENTER</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_CENTER</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox2">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">24</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area2">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="PROJECT_BUTTON_CANCEL">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	      <signal name="clicked" handler="on_PROJECT_BUTTON_CANCEL_clicked" last_modification_time="Thu, 10 Aug 2006 13:46:14 GMT"/>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="PROJECT_BUTTON_OK">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-open</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	      <signal name="clicked" handler="on_PROJECT_BUTTON_OK_clicked" last_modification_time="Thu, 10 Aug 2006 13:46:20 GMT"/>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
 </glade-interface>

Added: trunk/souffleur/streams.py
===================================================================
--- trunk/souffleur/streams.py	2006-08-09 10:21:31 UTC (rev 11757)
+++ trunk/souffleur/streams.py	2006-08-10 15:03:56 UTC (rev 11758)
@@ -0,0 +1,28 @@
+class Stream:
+    def __init__(self):
+        self.MIME=None
+        self.Name=None
+        self.attrs={}
+        self.ID=None
+    
+    def addAttr(self, attrName, attrValue):
+        if not attrName or not attrValue:
+            return
+
+        self.attrs[attrName]=attrValue
+
+class Media:
+    def __init__(self):
+        self.MIME=None
+        self.source=None
+        self.sourceURI=None
+        self.Streams=[]
+        self.lastID=0
+
+    def addStream(self, stream):
+        if type(stream)!=type(Stream()):
+            return
+        if stream.ID <= self.lastID:
+            return
+        self.Streams.append(stream)
+        self.lastID=stream.ID



More information about the commits mailing list