Package conduit :: Package modules :: Module AudioVideoConverterModule
[hide private]

Source Code for Module conduit.modules.AudioVideoConverterModule

  1  import re 
  2  import logging 
  3  log = logging.getLogger("modules.AVConverter") 
  4   
  5  import conduit 
  6  import conduit.utils as Utils 
  7  import conduit.utils.CommandLineConverter as CommandLineConverter 
  8  import conduit.TypeConverter as TypeConverter 
  9  import conduit.datatypes.File as File 
 10  import conduit.datatypes.Audio as Audio 
 11  import conduit.datatypes.Video as Video 
 12   
 13  if Utils.program_installed("ffmpeg"): 
 14      MODULES = { 
 15          "AudioVideoConverter" :  { "type": "converter" } 
 16          } 
 17  else: 
 18      MODULES = {} 
 19   
20 -class FFmpegCommandLineConverter(CommandLineConverter.CommandLineConverter):
21 - def __init__(self, duration=None):
22 CommandLineConverter.CommandLineConverter.__init__(self) 23 self.duration = duration 24 self.percentage_match = re.compile('time=?(\d+\.\d+)')
25
26 - def build_command(self, **kwargs):
27 kwargs['in_file'] = '"%s"' 28 kwargs['out_file'] = '"%s"' 29 30 command = "ffmpeg -i %(in_file)s " 31 #video options 32 if kwargs.get('vcodec', None): command += "-vcodec %(vcodec)s " 33 if kwargs.get('vbitrate', None): command += "-b %(vbitrate)s " 34 if kwargs.get('fps', None): command += "-r %(fps)s " 35 if kwargs.get('vtag', None): command += "-vtag %(vtag)s " 36 if kwargs.get('width', None) and kwargs.get('height', None): 37 command += "-s %(width)sx%(height)s " 38 #audio options 39 if kwargs.get('acodec', None): command += "-acodec %(acodec)s " 40 if kwargs.get('arate', None): command += "-ar %(arate)s " 41 # if kwargs.get('abitrate', None): command += "-ab %(abitrate)s " 42 if kwargs.get('achannels', None): command += "-ac %(achannels)s " 43 #output file, overwrite and container format 44 if kwargs.get('format', None): command += "-f %(format)s " 45 command += "-y %(out_file)s" 46 47 self.command = command % kwargs
48
49 - def calculate_percentage(self, val):
50 return float(val)/self.duration*100.0
51
52 - def check_cancelled(self):
53 return conduit.GLOBALS.cancelled
54
55 -class MencoderCommandLineConverter(CommandLineConverter.CommandLineConverter):
56 - def __init__(self):
57 CommandLineConverter.CommandLineConverter.__init__(self) 58 self.percentage_match = re.compile('(\d+)%')
59
60 - def build_command(self, **kwargs):
61 kwargs['in_file'] = '"%s"' 62 kwargs['out_file'] = '"%s"' 63 64 command = "mencoder %(in_file)s -o %(out_file)s " 65 #audio options 66 if kwargs.get('arate', None): command += "-srate %(arate)s " 67 if kwargs.get('achannels', None): command += "-channels %(achannels) " 68 #only support lavc atm 69 command += "-oac lavc " 70 if kwargs.has_key('acodec') and kwargs.has_key('abitrate'): 71 command += "-lavcopts acodec=%(acodec)s:abitrate=%(abitrate)s " 72 if kwargs.get('achannels', None): 73 command += "-af volnorm,channels=%(achannels) " 74 else: 75 command += "-af volnorm " 76 #video options (only support lavc atm) 77 command += "-ovc lavc " 78 if kwargs.has_key('vcodec') and kwargs.has_key('vbitrate'): 79 command += "-ovc lavc -lavcopts vcodec=%(vcodec)s:vbitrate=%(vbitrate)s " 80 if kwargs.get('width', None) and kwargs.get('height', None): 81 command += "-vf-add scale=%(width)s:%(height)s " 82 if kwargs.get('fps', None): command += "-ofps %(fps)s " 83 if kwargs.get('vtag', None): command += "-ffourcc %(vtag)s " 84 85 self.command = command % kwargs
86
87 - def calculate_percentage(self, val):
88 return float(val)
89
90 - def check_cancelled(self):
91 return conduit.GLOBALS.cancelled
92
93 -class AudioVideoConverter(TypeConverter.Converter):
94 95 #These commands are run to determine attributes about the file 96 #(such as size and duration) prior to transcode. They should be 97 #Robust and work with ALL input files, even if the transode step may 98 #later fail 99 100 VIDEO_INSPECT_COMMAND = 'ffmpeg -an -y -t 0:0:0.001 -i "%s" -f image2 "%s" 2>&1' 101 AUDIO_INSPECT_COMMAND = 'ffmpeg -fs 1 -y -i "%s" -f wav "%s" 2>&1' 102
103 - def __init__(self):
104 self.conversions = { 105 "file/video,file/video" : self.transcode_video, 106 "file,file/video" : self.file_to_video, 107 "file/audio,file/audio" : self.transcode_audio, 108 "file,file/audio" : self.file_to_audio 109 }
110
111 - def transcode_video(self, video, **kwargs):
112 mimetype = video.get_mimetype() 113 if not Video.mimetype_is_video(mimetype): 114 log.debug("File %s is not video type: %s" % (video,mimetype)) 115 return None 116 input_file = video.get_local_uri() 117 118 #run ffmpeg over the video to work out its format, and duration 119 c = CommandLineConverter.CommandLineConverter() 120 c.build_command(AudioVideoConverter.VIDEO_INSPECT_COMMAND) 121 ok,output = c.convert(input_file,"/dev/null",save_output=True) 122 123 if not ok: 124 log.debug("Error getting video information\n%s" % output) 125 return None 126 127 #extract the video parameters 128 pat = re.compile(r'Input.*?Duration: ([\d:]*\.*\d*).*?Stream #\d\.\d: Video:.*?(\d+)x(\d+)',re.DOTALL) 129 try: 130 duration_string,w,h = re.search(pat,output).groups() 131 #make duration into seconds 132 ho,m,s = duration_string.split(':') 133 duration = (60.0*60.0*float(ho)) + (60*float(m)) + float(s) 134 except AttributeError: 135 log.debug("Error parsing ffmpeg output") 136 return None 137 log.debug("Input Video %s: size=%swx%sh, duration=%ss" % (input_file,w,h,duration)) 138 139 if kwargs.get('width',None) != None and kwargs.get('height',None) != None: 140 kwargs['width'],kwargs['height'] = Utils.get_proportional_resize( 141 desiredW=int(kwargs['width']), 142 desiredH=int(kwargs['height']), 143 currentW=int(w), 144 currentH=int(h) 145 ) 146 147 #create output file 148 output_file = video.to_tempfile() 149 if kwargs.has_key("file_extension"): 150 video.force_new_file_extension(".%s" % kwargs["file_extension"]) 151 152 #convert the video 153 if kwargs.get("mencoder", False) and Utils.program_installed("mencoder"): 154 c = MencoderCommandLineConverter() 155 else: 156 c = FFmpegCommandLineConverter(duration=duration) 157 c.build_command(**kwargs) 158 ok,output = c.convert( 159 input_file, 160 output_file, 161 callback=lambda x: log.debug("Trancoding video %s%% complete" % x), 162 save_output=True 163 ) 164 165 if not ok: 166 log.debug("Error transcoding video\n%s" % output) 167 return None 168 169 return video
170
171 - def transcode_audio(self, audio, **kwargs):
172 mimetype = audio.get_mimetype() 173 if not Audio.mimetype_is_audio(mimetype): 174 log.debug("File %s is not audio type: %s" % (audio,mimetype)) 175 return None 176 input_file = audio.get_local_uri() 177 178 #run ffmpeg over the video to work out its format, and duration 179 c = CommandLineConverter.CommandLineConverter() 180 c.build_command(AudioVideoConverter.AUDIO_INSPECT_COMMAND) 181 ok,output = c.convert(input_file,"/dev/null",save_output=True) 182 183 if not ok: 184 log.debug("Error getting audio information\n%s" % output) 185 return None 186 187 #extract the video parameters 188 pat = re.compile(r'Input.*?Duration: ([\d:]*\.*\d*)',re.DOTALL) 189 try: 190 duration_string = re.search(pat,output).group(1) 191 #make duration into seconds 192 h,m,s = duration_string.split(':') 193 duration = (60.0*60.0*float(h)) + (60*float(m)) + float(s) 194 except AttributeError: 195 log.debug("Error parsing ffmpeg output") 196 return None 197 log.debug("Input Audio %s: duration=%ss" % (input_file,duration)) 198 199 #create output file 200 output_file = audio.to_tempfile() 201 if kwargs.has_key("file_extension"): 202 audio.force_new_file_extension(".%s" % kwargs["file_extension"]) 203 204 #convert audio 205 c = FFmpegCommandLineConverter(duration=duration) 206 c.build_command(**kwargs) 207 ok,output = c.convert( 208 input_file, 209 output_file, 210 callback=lambda x: log.debug("Trancoding audio %s%% complete" % x), 211 save_output=True 212 ) 213 214 if not ok: 215 log.debug("Error transcoding audio\n%s" % output) 216 return None 217 218 return audio
219
220 - def file_to_audio(self, f, **kwargs):
221 mimetype = f.get_mimetype() 222 if Audio.mimetype_is_audio(mimetype): 223 a = Audio.Audio( 224 URI=f._get_text_uri() 225 ) 226 a.set_from_instance(f) 227 if len(kwargs) > 0: 228 return self.transcode_audio(a,**kwargs) 229 else: 230 return a 231 else: 232 return None
233
234 - def file_to_video(self, f, **kwargs):
235 mimetype = f.get_mimetype() 236 if Video.mimetype_is_video(mimetype): 237 v = Video.Video( 238 URI=f._get_text_uri() 239 ) 240 v.set_from_instance(f) 241 if len(kwargs) > 0: 242 return self.transcode_video(v,**kwargs) 243 else: 244 return v 245 else: 246 return None
247