Changeset 922
- Timestamp:
- 07/03/09 10:03:30 (14 months ago)
- Location:
- plumimediaqueue/trunk/src/plumimediaqueue
- Files:
-
- 7 modified
-
events/events.py (modified) (1 diff)
-
events/interfaces.py (modified) (1 diff)
-
interfaces.py (modified) (2 diffs)
-
models.py (modified) (2 diffs)
-
queues/bittorrent.py (modified) (1 diff)
-
queues/download.py (modified) (3 diffs)
-
queues/transcoding.py (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
plumimediaqueue/trunk/src/plumimediaqueue/events/events.py
r532 r922 12 12 13 13 class JobReset(grok.ObjectModifiedEvent): 14 implements(job.IJobResetedEvent) 15 16 14 implements(job.IJobResetEvent) 17 15 18 16 class JobDeleted(ObjectEvent): -
plumimediaqueue/trunk/src/plumimediaqueue/events/interfaces.py
r532 r922 10 10 """ 11 11 12 class IJobReset edEvent(grok.IObjectModifiedEvent):12 class IJobResetEvent(grok.IObjectModifiedEvent): 13 13 """A job has been restarted. 14 14 """ -
plumimediaqueue/trunk/src/plumimediaqueue/interfaces.py
r658 r922 51 51 the add will return false, unless 'replace' is True. 52 52 In that case, existing task with the same uuid are overwritten. 53 If added to the queue, calls notify(job,IJobQueuedEvent), which should put the 54 jobItem into STARTING state. 55 """ 53 """ 56 54 57 55 def get_job(self, uuid): … … 65 63 66 64 def reset_job(self,uuid): 67 """Sets the job, matched by uuid, to STARTING state""" 65 """Sets the job, matched by uuid, to STARTING state 66 """ 68 67 69 68 def start_job(self,uuid): -
plumimediaqueue/trunk/src/plumimediaqueue/models.py
r658 r922 62 62 self.id = uuid 63 63 64 def copy(self, other_obj): 65 self.video_download_url = other_obj.video_download_url 66 self.file_path = other_obj.file_path 67 self.processed_filepaths = other_obj.processed_filepaths 68 64 69 class Queue(grok.Container): 65 70 grok.implements(IQueue) … … 97 102 job = self.get_job(uuid) 98 103 job.set_status(status.STARTING) 104 evnt = events.JobReset(job) 105 evnt.newParent = self 106 notify(evnt) 107 99 108 return True 100 109 -
plumimediaqueue/trunk/src/plumimediaqueue/queues/bittorrent.py
r536 r922 32 32 if IBittorrentQueue.providedBy(q) and obj.starting(): 33 33 logging.log(logging.INFO, "New obj added: %s , with event %s at newParent %s " % (obj,event,event.newParent)) 34 35 #XXX make torrent file 36 #XXX seed 37 #XXX announce to tracker -
plumimediaqueue/trunk/src/plumimediaqueue/queues/download.py
r536 r922 46 46 url_parts = urlparse(download_url) 47 47 rel_fp = url_parts[1]+url_parts[2] 48 incoming_filename = event.newParent.download_dir + '/' + rel_fp48 incoming_filename = q.download_dir + '/' + rel_fp 49 49 logging.debug("url parts are %s %s %s %s %s %s" % (url_parts[0],url_parts[1],url_parts[2],url_parts[3],url_parts[4],url_parts[5])) 50 50 logging.info("downloading media file from url %s, into location %s " % (download_url,incoming_filename)) … … 61 61 #tell the queue we failed. 62 62 q.fail_job(obj.uuid) 63 #nothing added to transcoding or bittorrent queues 63 64 return 65 66 #XXX 67 #do an MD5 checksum on the file, and store it on the object 68 64 69 65 70 logging.info("finished downloading") … … 70 75 #Add a jobitem for the transcoding queue, and bittorrent queues. 71 76 t_nm=NetworkMediaItem() 72 t_nm. file_path = incoming_filename77 t_nm.copy(obj) 73 78 bt_nm=NetworkMediaItem() 74 bt_nm.file_path = incoming_filename 79 bt_nm.copy(obj) 80 #set the both reset, into the STARTING state. 81 75 82 q.__parent__['transcoding'].add_job(t_nm) 83 76 84 q.__parent__['bittorrent'].add_job(bt_nm) 85 -
plumimediaqueue/trunk/src/plumimediaqueue/queues/transcoding.py
r656 r922 4 4 5 5 from plumimediaqueue.models import Queue, NetworkMediaItem 6 7 import logging 8 import os6 from plumimediaqueue.events.interfaces import IJobResetEvent 7 8 import logging , os , traceback , time, subprocess 9 9 10 10 class ITranscodingQueue(IQueue): … … 14 14 ) 15 15 16 mencoder_installed_location = Text( 17 title = u"MEncoder", 18 description=u"The file path to a MEncoder executable" 19 ) 20 21 ffmpeg2theora_installed_location = Text( 22 title = u"ffmpeg2theora", 23 description=u"The file path to a ffmpeg2theora executable" 24 ) 25 26 flvtool_installed_location = Text( 27 title = u"flvtool2", 28 description=u"The file path to a flvtool2 executable" 29 ) 30 16 31 mencoder_flv_options = Text( 17 32 title = u"MEncoder command line to produce FLV files.", 18 33 description=u"The set of options to pass to MEncoder when transcoding" 19 34 ) 35 36 ffmpeg2theora_options = Text( 37 title = u"ffmpeg2theora command line to produce OGV files.", 38 description=u"The set of options to pass to ffmpeg2theora when transcoding" 39 ) 40 41 42 mencoder_flv_highquality_options = Text( 43 title = u"MEncoder command line to produce high quality FLV files.", 44 description=u"The set of options to pass to MEncoder when transcoding" 45 ) 46 47 ffmpeg2theora_highquality_options = Text( 48 title = u"ffmpeg2theora command line to produce high-quality OGV files.", 49 description=u"The set of options to pass to ffmpeg2theora when transcoding" 50 ) 51 52 nice_level = Text( 53 title = u"Unix nice level", 54 description=u"The level to 'renice' the transcoding processes" 55 ) 56 57 20 58 21 59 file_extensions = List( … … 25 63 ) 26 64 27 flowplayer_URL_SWF = URI (28 title=u'URL of Flowplayer SWF',29 description=u'Network address of FlowPlayer movie to serve.'30 )31 32 videohost_URL = URI (33 title=u'URL of transcoded media server.',34 description=u'Network domain name for transcoded media server.'35 )36 37 38 65 class TranscodingQueue(Queue): 39 66 grok.implements(ITranscodingQueue) 40 67 41 68 #set a sensible default for downloading 42 transcoding_dir=os.path.join(os.getcwd(),'download_queue_files') 69 transcoding_dir=os.path.join(os.getcwd(),'transcoding_queue_files') 70 71 mencoder_installed_location = '/usr/local/bin/mencoder' 72 ffmpeg2theora_installed_location = '/usr/bin/ffmpeg2theora' 73 flvtool_installed_location = '/usr/bin/flvtool2' 43 74 44 75 mencoder_flv_options='-really-quiet -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:keyint=50:vbitrate=150:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -vf scale=320:240 -srate 22050' 45 76 77 mencoder_flv_highquality_options='-really-quiet -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:keyint=50:vbitrate=250:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -vf scale=720:480 -srate 22050' 78 46 79 file_extensions=['.avi','.qt','.mov','.mpeg','.mp4','.mpg','.asf','.wmv','.3gp','.m4v','.ogm','.ogg','.divx','flv'] 47 80 48 flowplayer_URL_SWF = 'http://flv.plumi.org/flowplayer/FlowPlayer.swf' 49 50 videohost_URL = '' 81 ffmpeg2theora_options = '-p preview' 82 83 ffmpeg2theora_highquality_options = '-p pro' 84 85 nice_level = '10' 51 86 52 87 def __init__(self,id=None): … … 63 98 64 99 @grok.subscribe(NetworkMediaItem, grok.IObjectAddedEvent) 100 @grok.subscribe(NetworkMediaItem, IJobResetEvent) 65 101 def handle(obj, event): 66 102 #check if the JobItem is STARTING … … 78 114 79 115 def attempt_transcode_file(transcoding_queue, networkmediaitem): 80 """Start the transcoding attempt with file 'f'. Converts to FLV format, and OGG/Theora. Produces HTML snippets for including the players appropriate for the produced video format. At the moment, this is FlowPlayer/JW Player for FLV, and Cortado java applet for OGG/Theora"""116 """Start the transcoding attempt with file 'f'. Converts to FLV format, and OGG/Theora. XXX other mobile formats """ 81 117 #whether or not the transcoding worked for the given file 'f' 82 118 worked = False 119 120 #from this queue, we can get our sibling queue 'download' 121 #XXX abstract the names in app.py , and give them constants 122 dld_dir=transcoding_queue.__parent__['download'].download_dir 83 123 84 124 #get filepath, and then split into stem and extension, and return false straight away if not in recognised set. … … 89 129 90 130 #setup filenames we will need. 91 videofile = f92 lockfile = f+".trans_lock" # we are encoding already93 skipfile = f+".trans_skip" # we tried and failed, don't bother again94 flvfile = transcoding_queue.transcoding_dir + stem + ".flv" # output FLV file95 theorafile = transcoding_queue.transcoding_dir + ".ogg" # output OGGfile96 includefile = self.INCLUDE_FILE_DIRECTORY+stem+self.INCLUDE_FILE_SUFFIX97 logging.info("using %s, %s, %s %s %s " % (lockfile, skipfile, flvfile, theorafile, includefile))131 original_videofile = f 132 video_file = f.replace(dld_dir,transcoding_queue.transcoding_dir) 133 lockfile = video_file+".trans_lock" # we are encoding already 134 skipfile = video_file+".trans_skip" # we tried and failed, don't bother again 135 flvfile = video_file + ".flv" # output FLV file 136 theorafile = video_file + ".ogv" # output OGG file 137 logging.info("using %s, %s, %s, %s %s " % (video_file, lockfile, skipfile, flvfile, theorafile)) 98 138 99 139 #check that another encoder isnt already processing this file (lockfile) or that we havent tried and failed before (skipfile) 100 if os.path.exists(skipfile) or os.path (lockfile):140 if os.path.exists(skipfile) or os.path.exists(lockfile): 101 141 #dont do it 102 142 return False 103 143 104 144 #OK, valid video file ready to try to transcode 105 logging.info(" Checking file %s, using extension %s " % (videofile, extension))145 logging.info("Using original file %s, using extension %s " % (original_videofile, extension)) 106 146 try: 147 #lets make sure all the directories are created 148 try: 149 os.makedirs(os.path.dirname(lockfile)) 150 except: 151 #the dirs may already exist 152 pass 153 107 154 # touch the lock file 108 155 #we should catch the exception here, and return FALSE! … … 112 159 logging.info("lock file creation failed! ABORTING. %s " % lockfile) 113 160 return False 114 #lets make sure all the directories are created115 try:116 os.makedirs(os.path.dirname(flvfile))117 except:118 #the dirs may already exist119 pass120 161 121 logging.info('OK to try encoding: '+ videofile)162 logging.info('OK to try encoding: '+original_videofile) 122 163 #mencoder flv conversion 123 164 start_time=time.time() 124 encoder_command = self.MENCODER_LOCATION + " -quiet " + videofile + " -o " + flvfile + " " + self.MENCODER_OPTIONS125 encoder_command_string = 'nice -n '+ self.BE_HOW_NICE+' '+encoder_command165 encoder_command = transcoding_queue.mencoder_installed_location + " -quiet " + original_videofile + " -o " + flvfile + " " + transcoding_queue.mencoder_flv_options 166 encoder_command_string = 'nice -n '+ transcoding_queue.nice_level +' '+encoder_command 126 167 output,error = subprocess.Popen([encoder_command_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 127 168 logging.debug("FLV transcoder output: %s ; error: %s" %(output,error)) 128 flvtool_command = self.FLVTOOL_LOCATION+" -U stdin "+flvfile129 flvtool_command_string = "cat "+ flvfile +" | "+ 'nice -n '+ self.BE_HOW_NICE+' '+flvtool_command169 flvtool_command = transcoding_queue.flvtool_installed_location+" -U stdin "+flvfile 170 flvtool_command_string = "cat "+ flvfile +" | "+ 'nice -n '+ transcoding_queue.nice_level + ' '+flvtool_command 130 171 output,error = subprocess.Popen([flvtool_command_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 131 172 logging.debug("FLV tool output: %s ; error: %s" %(output,error)) 132 173 #XXX update the set of transformed file paths on the item. 133 174 finish_time=time.time() 134 logging.info("Encoded %s in %.2f seconds, using cmd -- %s" % ( videofile,finish_time-start_time,encoder_command_string))175 logging.info("Encoded %s in %.2f seconds, using cmd -- %s" % (original_videofile,finish_time-start_time,encoder_command_string)) 135 176 136 177 #ffmpeg2theora , theora/ogg conversion 137 178 start_time=time.time() 138 theora_cmd = self.FFMPEG2THEORA_COMMAND + ' ' + videofile + " -o " + theorafile139 theora_cmd_string='nice -n '+ self.BE_HOW_NICE+' '+ theora_cmd179 theora_cmd = transcoding_queue.ffmpeg2theora_installed_location + ' ' + transcoding_queue.ffmpeg2theora_options + " -o " + theorafile + ' ' + original_videofile 180 theora_cmd_string='nice -n '+ transcoding_queue.nice_level+ ' '+ theora_cmd 140 181 output,error = subprocess.Popen([theora_cmd_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 141 182 logging.debug("Theora output: %s ; error: %s" %(output,error)) 142 183 #XXX update the set of transformed file paths on the item. 143 184 finish_time=time.time() 144 logging.info("Encoded %s in %.2f seconds, using cmd -- %s" % ( videofile,finish_time-start_time,theora_cmd_string))185 logging.info("Encoded %s in %.2f seconds, using cmd -- %s" % (original_videofile,finish_time-start_time,theora_cmd_string)) 145 186 146 187 if os.path.exists(flvfile) and os.path.getsize(flvfile)>0 and os.path.exists(theorafile) and os.path.getsize(theorafile)>0: 147 188 # OK ! It Worked. 189 190 #update the object with the details of the new file paths. 191 networkmediaitem.processed_filepaths=(flvfile,theorafile) 192 148 193 worked = True 149 194 else: … … 154 199 return False 155 200 156 #Now, make the flash HTML snippet if the flv and Theora got created correctly.157 #XXX todo, separate out the flv and ogg theora (java applet) html snippet158 if os.path.exists(flvfile) and os.path.getsize(flvfile)>0:159 #lets make sure all the directories are created160 try:161 os.makedirs(os.path.dirname(includefile))162 except:163 #the dirs may already exist164 pass165 166 logging.info("Making html template - original size of %s: %.1fMB, Encoded size: %.1fMB" % (videofile,os.path.getsize(videofile)/1000000.0,os.path.getsize(flvfile)/1000000.0))167 data_map={168 'flowplayer_location':self.FLOWPLAYER_LOCATION,169 'videofile':flvfile,170 'videobaseurl':self.VIDEO_SERVER_URL,171 'splashbaseurl':self.SPLASH_IMAGE_BASE,172 'splashfile':self.SPLASH_IMAGE_FILE,173 'cortado_location':self.CORTADO_LOCATION,174 'oggfile':theorafile,175 }176 template = Template(file=self.INCLUDE_TEMPLATE, searchList=[data_map])177 file_template=open(includefile, 'w')178 file_template.write(template.respond())179 file_template.close()180 181 182 201 except: 183 logging.info("Error while processing %s: %s" % ( videofile,traceback.format_exc()))202 logging.info("Error while processing %s: %s" % (original_videofile,traceback.format_exc())) 184 203 #catch exception to remove lock file. 185 204 os.remove(lockfile) 186 205 return False 187 206 207 os.remove(lockfile) 188 208 #return a status value if we managed to get all the way here. 189 209 return worked
