conduit r1720 - in trunk: conduit/datatypes conduit/gtkui conduit/modules conduit/modules/iPodModule conduit/utils test/python-tests



Author: arosenfeld
Date: Wed Sep 10 02:51:05 2008
New Revision: 1720
URL: http://svn.gnome.org/viewvc/conduit?rev=1720&view=rev

Log:
Added option to keep converted files in the iPod module.
Fixed code in the AudioVideo converter to allow files to be kept after conversion.
Changed the AudioVideo converter to trust metadata from Video and Audio classes.
Let the GStreamer conversion to be stopped when the sync is cancelled.
Fixed some issues in the Audio and Video classes.
Improved SimpleConfigurator documentation.



Modified:
   trunk/conduit/datatypes/Audio.py
   trunk/conduit/datatypes/Video.py
   trunk/conduit/gtkui/SimpleConfigurator.py
   trunk/conduit/modules/AudioVideoConverterModule.py
   trunk/conduit/modules/iPodModule/iPodModule.py
   trunk/conduit/utils/MediaFile.py
   trunk/test/python-tests/TestCoreConvertAudioVideo.py

Modified: trunk/conduit/datatypes/Audio.py
==============================================================================
--- trunk/conduit/datatypes/Audio.py	(original)
+++ trunk/conduit/datatypes/Audio.py	Wed Sep 10 02:51:05 2008
@@ -8,7 +8,8 @@
 
 PRESET_ENCODINGS = {
     "ogg":{"acodec":"vorbisenc","format":"oggmux","file_extension":"ogg"},
-    "wav":{"acodec":"wavenc","file_extension":"wav"}
+    "wav":{"acodec":"wavenc","file_extension":"wav"},
+    "mp3":{"acodec":"lame", "file_extension": "mp3"},
     }
 
 def mimetype_is_audio(mimetype):

Modified: trunk/conduit/datatypes/Video.py
==============================================================================
--- trunk/conduit/datatypes/Video.py	(original)
+++ trunk/conduit/datatypes/Video.py	Wed Sep 10 02:51:05 2008
@@ -8,7 +8,7 @@
 # "arate":44100, "abitrate":"64k"
 # "fps":15
 PRESET_ENCODINGS = {
-    "divx":{"vcodec":"xvidenc", "acodec":"lame", "format":"avimux", "vtag":"DIVX", "file_extension":"avi", },
+    "divx":{"vcodec":"xvidenc", "acodec":"lame", "format":"avimux", "vtag":"DIVX", "file_extension":"avi", "mimetype": "video/x-msvideo"},
     #breaks on single channel audio files because ffmpeg vorbis encoder only suuport stereo
     "ogg":{"vcodec":"theoraenc", "acodec":"vorbisenc", "format":"oggmux", "file_extension":"ogg"},
     #needs mencoder or ffmpeg compiled with mp3 support
@@ -36,7 +36,7 @@
         MediaFile.MediaFile.__init__(self, URI, **kwargs)
 
     def get_video_duration(self):
-        return _get_metadata('duration')
+        return self._get_metadata('duration')
 
     def get_video_size(self):
-        return _get_metadata('width'),_get_metadata('height')
+        return self._get_metadata('width'), self._get_metadata('height')

Modified: trunk/conduit/gtkui/SimpleConfigurator.py
==============================================================================
--- trunk/conduit/gtkui/SimpleConfigurator.py	(original)
+++ trunk/conduit/gtkui/SimpleConfigurator.py	Wed Sep 10 02:51:05 2008
@@ -20,8 +20,8 @@
                     "InitialValue" : value or function
                     }
                 ]
+                
     Or, alternatively:
-        
 
         maps = [
                     {
@@ -29,6 +29,7 @@
                     "Kind" : "text", "check" or "list",
                     "Callback" : function,
                     "InitialValue" : value or function
+                    "Values": list if Kind = "list"
                     }
                 ]        
     """
@@ -50,7 +51,8 @@
         self.dialogParent = window
         #the child widget to contain the custom settings
         self.customSettings = gtk.Table(rows=0, columns=2)
-        self.customSettings.set_row_spacings(8)
+        self.customSettings.set_row_spacings(4)
+        self.customSettings.set_border_width(4)
         
         #The dialog is loaded from a glade file
         gladeFile = os.path.join(conduit.SHARED_DATA_DIR, "conduit.glade")
@@ -123,6 +125,8 @@
         """
         #For each item in the mappings list create the appropriate widget
         for l in self.mappings:
+            if "Title" in l:
+                label = gtk.Label(l["Title"])
             if 'Kind' in l:
                 kind = l['Kind']
                 widget = {'text': gtk.Entry,
@@ -172,7 +176,7 @@
             row = table.get_property('n-rows') + 1
             table.resize(row, 2)
             if label:
-                table.attach(label, 0, 1, row - 1, row)
+                table.attach(label, 0, 1, row - 1, row, xpadding = 8)
                 table.attach(widget, 1, 2, row - 1, row)
             else:
-                table.attach(widget, 0, 2, row - 1, row)
+                table.attach(widget, 0, 2, row - 1, row, xpadding = 8)

Modified: trunk/conduit/modules/AudioVideoConverterModule.py
==============================================================================
--- trunk/conduit/modules/AudioVideoConverterModule.py	(original)
+++ trunk/conduit/modules/AudioVideoConverterModule.py	Wed Sep 10 02:51:05 2008
@@ -1,6 +1,8 @@
 import re
 import logging
 import threading
+import tempfile
+import os
 log = logging.getLogger("modules.AVConverter")
 
 import conduit
@@ -14,7 +16,6 @@
 
 try:
     import gst
-    from gst.extend import discoverer
     from gst import Pipeline
     MODULES = {
         "AudioVideoConverter" :  { "type": "converter" }
@@ -54,21 +55,18 @@
     specified, the other is calculated to keep the video proportional.    
 '''
 
+PROGRESS_WAIT = 2.5
+
 class GStreamerConversionPipeline(Pipeline):
     """
     Converts between different multimedia formats.
     This class is event-based and needs a mainloop to work properly.
     Emits the 'converted' signal when conversion is finished.
-    Heavily based from gst.extend.discoverer
+    Heavily based on gst.extend.discoverer
 
     The 'converted' callback has one boolean argument, which is True if the
     file was successfully converted.
     """
-    
-    #TODO: Although this is based more on Discoverer, it might be better to base
-    # on some ideas from utils.GstMetadata, especially the pipeline reutilization
-    # (might be a temporary fix to the need to run the discover to get media 
-    # information then the conversion pipeline)
 
     __gsignals__ = {
         'converted' : (gobject.SIGNAL_RUN_FIRST,
@@ -79,8 +77,6 @@
     
     def __init__(self, **kwargs):        
         Pipeline.__init__(self)
-        #if 'file_mux' not in kwargs:
-        #    raise Exception('Output file format not specified')        
         self._has_video_enc = ('vcodec' in kwargs) or ('vcodec_pass1' in kwargs) or ('vcodec_pass2' in kwargs)
         self._has_audio_enc = 'acodec' in kwargs
         if not self._has_video_enc and not self._has_audio_enc:
@@ -126,18 +122,18 @@
             # Dont link videoscale to ffmpegcolorspace yet
             self._video_queue.link(self._video_scale)
             self._video_ffmpegcolorspace.link(self._video_enc)
-            #TODO: Add dynamic video scaling, thus removing the need to run
-            # the discoverer before conversion
             if ('width' in kwargs) or ('height' in kwargs):
                 log.debug("Video dimensions specified")
                 resolution = []                
                 if 'width' in kwargs:
                     width = kwargs['width']
+                    # Make sure it works with all encoders
                     resolution.append('width=%s' % (width - width % 2))
                 if 'height' in kwargs:
                     height = kwargs['height']
                     resolution.append('height=%s' % (height - height % 2))
-                caps = gst.caps_from_string('video/x-raw-yuv,%s;video/x-raw-yuv,%s' % (','.join(resolution), ','.join(resolution)))
+                resolution = ','.join(resolution)
+                caps = gst.caps_from_string('video/x-raw-yuv,%s;video/x-raw-rgb,%s' % (resolution, resolution))
                 self._video_scale.link_filtered(self._video_ffmpegcolorspace, caps)
             else:
                 self._video_scale.link(self._video_ffmpegcolorspace)
@@ -149,7 +145,6 @@
             self._video_pad = None
         if self._has_audio_enc and self._pass != 1:
             self._audio_queue = gst.element_factory_make('queue')
-            #TODO: Add audio rate and sampler            
             self._audio_convert = gst.element_factory_make('audioconvert')
             self._audio_resample = gst.element_factory_make('audioresample')
             self._audio_rate = gst.element_factory_make('audiorate')            
@@ -163,16 +158,13 @@
         else:
             self._audio_pad = None
             
-    def _finished(self, success=False):        
-        log.debug("Conversion finished")
+    def _finished(self, success=False):
         self._success = success
         self.bus.remove_signal_watch()
         gobject.idle_add(self._stop)
-        gobject.source_remove(self.watch)
         return False
 
     def _stop(self):
-        log.debug('Conversion stop')
         self.set_state(gst.STATE_READY)
         self.emit('converted', self._success)
 
@@ -182,12 +174,9 @@
             # conversion?
             log.debug("Conversion sucessfull")
             self._finished(True)
-        #elif message.type == gst.MESSAGE_TAG:
-        #    for key in message.parse_tag().keys():
-        #        self.tags[key] = message.structure[key]
         elif message.type == gst.MESSAGE_ERROR:
             log.debug("Conversion error")
-            self._finished()        
+            self._finished()     
             
     def _dbin_decoded_pad(self, dbin, pad, is_last):
         caps = pad.get_caps()
@@ -215,10 +204,9 @@
         try:
             (pos, format) = self.query_position(gst.FORMAT_TIME)
             (dur, format) = self.query_duration(gst.FORMAT_TIME)
-            log.debug("Conversion progress %.2f%%" % (float(pos)*100.0/dur))
             return (pos/float(gst.SECOND), dur/float(gst.SECOND))
         except gst.QueryError:
-            log.debug("QUERY ERROR")
+            log.debug("Conversion query ERROR")
             return (0.0, 0.0)
                 
     def convert(self):
@@ -227,49 +215,37 @@
         self.bus.add_signal_watch()
         self.bus.connect("message", self._bus_message_cb)
         log.debug("Starting conversion")
-        self.watch  = gobject.timeout_add(2000, self.progress)
         if not self.set_state(gst.STATE_PLAYING):
             self._finished()
             
 class GStreamerConverter():
-    def __init__(self, filename):
-        self.filename = filename
-
-    def get_stream_info(self, needs_audio = False, needs_video = False):                
-        def discovered(discoverer, valid):
-            self.valid = valid
-            event.set()        
-        event = threading.Event()    
-        log.debug("Getting stream information file: %s" % self.filename)
-        self.info = discoverer.Discoverer(self.filename)
-        self.info.connect('discovered', discovered)
-        self.info.discover()
-        event.wait()        
-        if not self.valid:
-            raise Exception('Not a valid media file')
-        if needs_video and not self.info.is_video:
-            raise Exception("Not a valid video file")
-        if needs_audio and not self.info.is_audio:
-            raise Exception("Not a valid audio file")            
-        if self.info.is_video:
-            return (self.info.videowidth, self.info.videoheight, \
-                self.info.videolength / gst.SECOND)
-        elif self.info.is_audio:            
-            return (self.info.audiolength / gst.SECOND)
-        else:
-            raise Exception
-            
     def _run_pipeline(self, **kwargs):
         def converted(converter, success):
             if not success:
                 raise Exception
             self.success = success
-            event.set()            
+            event.set()
         event = threading.Event()
         pipeline = GStreamerConversionPipeline(**kwargs)
         pipeline.connect("converted", converted)
         pipeline.convert()
-        event.wait()        
+        current_thread = threading.currentThread()
+        check_progress = False
+        while not event.isSet():
+            # Dont print an error message if we havent yet started the conversion
+            if check_progress:
+                (time, total) = pipeline.progress()
+                if total:
+                    log.debug("Conversion progress: %.2f%%" % (100.0 * time/total))
+            event.wait(PROGRESS_WAIT)
+			# FIXME: A little hackish, but works.
+            if hasattr(current_thread, 'cancelled'):
+                if current_thread.cancelled:
+                    pipeline.set_state(gst.STATE_NULL)      
+                    pipeline = None
+                    return False
+            check_progress = True
+        pipeline = None
         return self.success
 
     def convert(self, **kwargs):
@@ -292,89 +268,103 @@
                             "file,file/audio"           :   self.file_to_audio
                             }
 
+    def _get_output_file(self, input_file, **kwargs):
+        # We are not checking the contents of keep_converted, because it is a 
+        # string, not a bool, even if it was a bool in the args
+        use_temp = not kwargs.has_key("keep_converted")
+        if not use_temp:
+            try:
+                (input_folder, input_filename) = os.path.split(input_file)
+                output_folder = os.path.join(input_folder, "Converted Files")
+                if not os.path.exists(output_folder):
+                    os.mkdir(output_folder)
+                output_file = os.path.join(output_folder, input_filename)
+                if 'file_extension' in kwargs:
+                    output_file = os.path.splitext(output_file)[0] + '.' + kwargs['file_extension']
+                #TODO: If the file already exists, we could probably not convert it,
+                # because it could've been converted before
+                #if os.path.is_file(output_file):
+                #    return video
+            except Exception, e:
+                log.debug("Using temp folder as a fallback: %s" % e)
+                use_temp = True
+        if use_temp:
+            output_file = tempfile.mkstemp(suffix='conduit')[1]
+            if kwargs.has_key("file_extension"):
+                output_file += '.' + kwargs["file_extension"]
+        log.debug("Using output_file = %s", output_file)
+        return output_file
+        
     def transcode_video(self, video, **kwargs):
-        #mimetype = video.get_mimetype()
-        #if not Video.mimetype_is_video(mimetype):
-        #    log.debug("File %s is not video type: %s" % (video,mimetype))
-        #    return None
-        input_file = video.get_local_uri()
-        
-        log.debug("Creating GStreamer converter")
-
-        gst_converter = GStreamerConverter(input_file) 
-        #try:
-        log.debug("Getting video information")
-        (w, h, duration) = gst_converter.get_stream_info(needs_video = True)
-        #except:
-        #    log.debug("Error getting video information")
-        #    return None
-
-        log.debug("Input Video %s: size=%swx%sh, duration=%ss" % (input_file,w,h,duration))
-
+        #FIXME: This code fails with flv. Should we add an exception?
+        mimetype = video.get_mimetype()
+        if not Video.mimetype_is_video(mimetype):
+            log.debug("File %s is not video type: %s" % (video,mimetype))
+            return None
+        
+        kwargs['in_file'] = video.get_local_uri()
+        kwargs['out_file'] = self._get_output_file(kwargs['in_file'], **kwargs)
+        if os.path.exists(kwargs['out_file']):
+            return Video.Video(kwargs['out_file'])
+        
+        #Check if we need to convert the video
+        if kwargs.get('mimetype', None) == mimetype:
+            #Check if the video is smaller or equal then the required dimensions
+            #If it does, we dont need to convert it
+            width = kwargs.get('width', None)
+            height = kwargs.get('height', None)
+            if width or height:
+                (video_width, video_height) = video.get_video_size()
+                if (not width or video_width <= width) and \
+                   (not height or video_height <= height):
+                    log.debug("Video matches the required dimensions, not converting")
+                    return video
+            else:
+                #There is no required dimensions, and we match the mimetype,
+                #so we dont convert it
+                log.debug("Video matches the mimetype, not converting")
+                return video
+        
         if 'width' in kwargs and 'height' in kwargs:
+            (width, height) = video.get_video_size()
+            if not width and not height:
+                log.debug("Can't get video dimensions")
+                return None
             kwargs['width'],kwargs['height'] = Utils.get_proportional_resize(
                             desiredW=int(kwargs['width']),
                             desiredH=int(kwargs['height']),
-                            currentW=int(w),
-                            currentH=int(h)
+                            currentW=int(width),
+                            currentH=int(height)
                             )
-
-        #TODO: Test folder_location code
-        #if kwargs.has_key("folder_location"):
-        #    output_file = kwargs.has_key("folder_location")
-        #    if not os.path.isdir(output_file):
-        #        log.debug("Output location not a folder")
-        #        return None
-        #    output_file = os.path.join(output_file, os.path.basename(input_file))
-        #    log.debug("Using output_file = %s", output_file)
-        #else:
-        
-        #create output file
-        output_file = video.to_tempfile()
-        if kwargs.has_key("file_extension"):
-            video.force_new_file_extension(".%s" % kwargs["file_extension"])
-        kwargs['in_file'] = input_file
-        kwargs['out_file'] = output_file
-        sucess = gst_converter.convert(**kwargs)
+            log.debug("Scaling video to %swx%sh" % (kwargs['width'],kwargs['height']))
+        
+        gst_converter = GStreamerConverter()
+        sucess = gst_converter.convert(**kwargs)       
         
         if not sucess:
-            log.debug("Error transcoding video\n%s" % output)
+            log.debug("Error transcoding video\n")
             return None
-
-        return video
+        
+        return Video.Video(kwargs['out_file'])
 
     def transcode_audio(self, audio, **kwargs):
         mimetype = audio.get_mimetype()
         if not Audio.mimetype_is_audio(mimetype):
             log.debug("File %s is not audio type: %s" % (audio,mimetype))
             return None
-        input_file = audio.get_local_uri()
-
-
-        gst_converter = GStreamerConverter(input_file)
-        try:
-            duration = gst_converter.get_stream_info(needs_audio = True)
-        except:
-            log.debug("Error getting audio information")
-            return None
-
-        log.debug("Input Audio %s: duration=%ss" % (input_file,duration))
-
-        #create output file
-        output_file = audio.to_tempfile()
-        if kwargs.has_key("file_extension"):
-            audio.force_new_file_extension(".%s" % kwargs["file_extension"])
+        
+        kwargs['in_file'] = audio.get_local_uri()
+        kwargs['out_file'] = self._get_output_file(kwargs['in_file'], **kwargs)
 
         #convert audio
-        kwargs['in_file'] = input_file
-        kwargs['out_file'] = output_file
+        gst_converter = GStreamerConverter()
         sucess = gst_converter.convert(**kwargs)
         
         if not sucess:
-            log.debug("Error transcoding audio\n%s" % output)
+            log.debug("Error transcoding audio\n")
             return None
 
-        return audio
+        return Audio.Audio(kwargs['out_file'])
 
     def file_to_audio(self, f, **kwargs):
         mimetype = f.get_mimetype()

Modified: trunk/conduit/modules/iPodModule/iPodModule.py
==============================================================================
--- trunk/conduit/modules/iPodModule/iPodModule.py	(original)
+++ trunk/conduit/modules/iPodModule/iPodModule.py	Wed Sep 10 02:51:05 2008
@@ -574,7 +574,6 @@
 
     def set_info_from_video(self, video):
         self.set_info_from_file(video)
-        #FIXME: Movie should be a choice between Movie, MusicVideo, TvShow and Podcast
         self.track['mediatype'] = {'movie': gpod.ITDB_MEDIATYPE_MOVIE,
                                    'musicvideo': gpod.ITDB_MEDIATYPE_MUSICVIDEO,
                                    'tvshow': gpod.ITDB_MEDIATYPE_TVSHOW,
@@ -599,7 +598,6 @@
             if mount_point in self.__db_list:
                 log.debug('Getting DB in cache for %s' % (mount_point))
                 db = self.__db_list[mount_point]
-                #self.__db_locks[db][1] += 1
             else:
                 if mount_point:
                     log.debug('Creating DB for %s' % mount_point)
@@ -616,15 +614,14 @@
     @classmethod
     def release_db(self, db):
         assert db in self.__db_locks
+        # We dont do nothing here yet, but we could use to release resources.
+        # The db is automatically removed from the list because of the weak 
+        # reference.
         log.debug('Releasing DB for %s' % db)
-        #self.__db_locks[db][1] -= 1
 
     @classmethod
     def lock_db(self, db):
         assert db in self.__db_locks
-        #if self.__db_locks[db][1] == 1:
-        #    log.debug('Not locking DB for %s' % db)
-        #    return
         log.debug('Locking DB %s' % db)
         self.__db_locks[db].acquire()
 
@@ -632,8 +629,6 @@
     def unlock_db(self, db):
         assert db in self.__db_locks
         log.debug('Unlocking DB %s' % db)
-        #lock = self.__db_locks[db][0]
-        #if lock.locked():
         self.__db_locks[db].release()
 
 class IPodMediaTwoWay(IPodBase):
@@ -651,6 +646,7 @@
         #self.tracks = {}
         self.tracks_id = {}
         self.track_args = {}
+        self.keep_converted = True
 
     def refresh(self):
         DataProvider.TwoWay.refresh(self)
@@ -723,23 +719,33 @@
             return a
         #Get an array of encodings, so it can be indexed inside a combobox
         self.config_encodings = [dict_update({'name': name}, value) for name, value in self.encodings.iteritems()]
-        initial = None
+        initial_enc = None
         for encoding in self.config_encodings:
             if encoding['name'] == self.encoding:
-                initial = encoding.get('description', None) or encoding['name']
+                initial_enc = encoding.get('description', None) or encoding['name']
 
         def selectEnc(index, text):
             self.encoding = self.config_encodings[index]['name']
             log.debug('Encoding %s selected' % self.encoding)
             
+        def selectKeep(value):
+            self.keep_converted = value
+            log.debug("Keep converted selected: %s" % (value))
+            
         return [
                     {
                     "Name" : self.FORMAT_CONVERSION_STRING,
                     "Kind" : "list",
                     "Callback" : selectEnc,
                     "Values" : [encoding.get('description', None) or encoding['name'] for encoding in self.config_encodings],
-                    "InitialValue" : initial
-                    }
+                    "InitialValue" : initial_enc
+                    },
+                    
+                    {"Name" : _("Keep converted files"),
+                     "Kind" : "check",
+                     "Callback" : selectKeep,
+                     "InitialValue" : self.keep_converted
+                    },
                 ]        
 
     def configure(self, window):
@@ -751,13 +757,25 @@
     def set_configuration(self, config):
         if 'encoding' in config:
             self.encoding = config['encoding']
+        if 'keep_converted' in config:
+            self.keep_converted = config['keep_converted']
 
     def get_configuration(self):
-        return {'encoding':self.encoding}
+        return {'encoding':self.encoding,
+                'keep_converted': self.keep_converted}
 
     def get_input_conversion_args(self):
         try:
-            return self.encodings[self.encoding]
+            args = self.encodings[self.encoding]
+            # FIXME
+            # If we pass the bool in the args, it will become a string, and 
+            # will always return True later in the converter.
+            # So we only pass it if is True. When it's False, not being there
+            # tells the converter it isn't True.
+            # I'm not sure it was supposed to work like this.
+            if self.keep_converted:
+                args['keep_converted'] = True
+            return args
         except KeyError:
             return {}
 
@@ -774,7 +792,7 @@
 
 class IPodMusicTwoWay(IPodMediaTwoWay):
 
-    _name_ = "Music"
+    _name_ = "iPod Music"
     _description_ = "Sync your iPod music"
     _module_type_ = "twoway"
     _in_type_ = "file/audio"
@@ -792,13 +810,24 @@
         self.encoding = 'aac'
 
 IPOD_VIDEO_ENCODINGS = {
-    "mp4_x264":{"description": "MP4 (H.264)","vcodec":"x264enc", "acodec":"faac", "format":"ffmux_mp4", "file_extension":"m4v", "width": 320, "height": 240},
-    "mp4_xvid":{"description": "MP4 (XVid)","vcodec":"xvidenc", "acodec":"faac", "format":"ffmux_mp4", "file_extension":"m4v", "width": 320, "height": 240},
+    #FIXME: Add iPod mpeg4 restrictions. Follow:
+    # http://rob.opendot.cl/index.php/useful-stuff/ffmpeg-x264-encoding-guide/
+    "mp4_x264":{"description": "MP4 (Better quality - H.264)","vcodec":"x264enc", "acodec":"faac", 
+        "format":"ffmux_mp4", "file_extension":"m4v", "width": 320, "height": 240, 
+        "mimetype": "video/mp4"},
+    #FIXME: Two-pass encoding is not working. The first pass never finishes.
+    #"mp4_x264_twopass":{"description": "MP4 (H.264, Two-pass EXPERIMENTAL)", 
+    #    "vcodec_pass1":"x264enc pass=1", "vcodec_pass2":"x264enc pass=2", 
+    #    "acodec":"faac", "format":"ffmux_mp4", "file_extension":"m4v", 
+    #    "width": 320, "height": 240, "mimetype": "video/mp4", 'twopass':True},
+    "mp4_xvid":{"description": "MP4 (Faster conversion - XVid)","vcodec":"ffenc_mpeg4", "acodec":"faac",
+        "format":"ffmux_mp4", "file_extension":"m4v", "width": 320, "height": 240, 
+        "mimetype": "video/mp4"},
     }
 
 class IPodVideoTwoWay(IPodMediaTwoWay):
 
-    _name_ = "Video"
+    _name_ = "iPod Video"
     _description_ = "Sync your iPod videos"
     _module_type_ = "twoway"
     _in_type_ = "file/video"
@@ -852,6 +881,7 @@
         IPodMediaTwoWay.set_configuration(self, config)
         if 'video_kind' in config:
             self.encoding = config['video_kind']
+        self._update_track_args()
 
     def get_configuration(self):
         config = IPodMediaTwoWay.get_configuration(self)

Modified: trunk/conduit/utils/MediaFile.py
==============================================================================
--- trunk/conduit/utils/MediaFile.py	(original)
+++ trunk/conduit/utils/MediaFile.py	Wed Sep 10 02:51:05 2008
@@ -7,7 +7,7 @@
 try:
     import gst
     from gst.extend import discoverer
-    GST_AVAILABLE = False
+    GST_AVAILABLE = True
 except ImportError:
     GST_AVAILABLE = False
 
@@ -46,11 +46,10 @@
             tags['channels'] = info.audiochannels
         return tags
 
-    def _get_metadata(self, name):
-        if GST_AVAILABLE:
-            tags = self.get_media_tags()
-            if name in tags:
-                return tags[name]
+    def _get_metadata(self, name):        
+        tags = self.get_media_tags()
+        if name in tags:
+            return tags[name]
         return None
 
     def __getattr__(self, name):
@@ -68,4 +67,6 @@
         Descendants should override this function to provide their own tags,
         or merge with these tags.
         '''
-        return self.gst_tags
+        if GST_AVAILABLE:
+            return self.gst_tags
+        return None

Modified: trunk/test/python-tests/TestCoreConvertAudioVideo.py
==============================================================================
--- trunk/test/python-tests/TestCoreConvertAudioVideo.py	(original)
+++ trunk/test/python-tests/TestCoreConvertAudioVideo.py	Wed Sep 10 02:51:05 2008
@@ -10,6 +10,7 @@
 import conduit.datatypes.File as File
 import conduit.datatypes.Video as Video
 import conduit.datatypes.Audio as Audio
+import conduit.modules.iPodModule.iPodModule as iPodModule
 import conduit.utils as Utils
 import conduit.Exceptions as Exceptions
 
@@ -19,11 +20,15 @@
 ok("Video Conversion exists", tc.conversion_exists("file","file/video") == True)
 ok("Audio Conversion exists", tc.conversion_exists("file","file/audio") == True)
 
+VIDEO_ENCODINGS = Video.PRESET_ENCODINGS
+VIDEO_ENCODINGS.update(iPodModule.IPOD_VIDEO_ENCODINGS)
+
 TEST = (
 #name.list          #encodings to test  #available encodings
-("video",           ('divx','flv','ogg'),          Video.PRESET_ENCODINGS      ),
-("audio",           ('ogg',),           Audio.PRESET_ENCODINGS      ),
+("video",           ('divx', 'flv', 'ogg', 'mp4_x264', 'mp4_xvid'), VIDEO_ENCODINGS),
+("audio",           ('ogg','mp3'),           Audio.PRESET_ENCODINGS      ),
 )
+mainloop = gobject.MainLoop()
 
 def convert():    
     for name, test_encodings, all_encodings in TEST:
@@ -41,14 +46,13 @@
                     ok("%s: Conversion OK" % name, newdata != None and newdata.exists(), False)
                 except Exceptions.ConversionError:
                     ok("%s: Conversion Failed" % name, False, False)
-    finished()           
-    mainloop.quit()
-    return False
+    gobject.idle_add(mainloop.quit)
+    finished()
 
 def idle_cb():
     threading.Thread(target=convert).start()
+    return False
 
-mainloop = gobject.MainLoop()
 gobject.idle_add(idle_cb)
 mainloop.run()
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]