Changeset 922

Show
Ignore:
Timestamp:
07/03/09 10:03:30 (8 months ago)
Author:
andy
Message:

transcoder queue runs properly now

removed HTML generation - out of place here

added properties on transcoder queue for high/low quality versions of FLV, OGV conversion

Location:
plumimediaqueue/trunk/src/plumimediaqueue
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • plumimediaqueue/trunk/src/plumimediaqueue/events/events.py

    r532 r922  
    1212 
    1313class JobReset(grok.ObjectModifiedEvent): 
    14     implements(job.IJobResetedEvent) 
    15  
    16  
     14    implements(job.IJobResetEvent) 
    1715 
    1816class JobDeleted(ObjectEvent): 
  • plumimediaqueue/trunk/src/plumimediaqueue/events/interfaces.py

    r532 r922  
    1010    """ 
    1111 
    12 class IJobResetedEvent(grok.IObjectModifiedEvent): 
     12class IJobResetEvent(grok.IObjectModifiedEvent): 
    1313    """A job has been restarted. 
    1414    """ 
  • plumimediaqueue/trunk/src/plumimediaqueue/interfaces.py

    r658 r922  
    5151        the add will return false, unless 'replace' is True. 
    5252        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           """ 
    5654 
    5755    def get_job(self, uuid): 
     
    6563 
    6664    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        """ 
    6867 
    6968    def start_job(self,uuid): 
  • plumimediaqueue/trunk/src/plumimediaqueue/models.py

    r658 r922  
    6262            self.id = uuid 
    6363 
     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 
    6469class Queue(grok.Container): 
    6570    grok.implements(IQueue) 
     
    97102        job = self.get_job(uuid) 
    98103        job.set_status(status.STARTING) 
     104        evnt = events.JobReset(job) 
     105        evnt.newParent = self 
     106        notify(evnt) 
     107 
    99108        return True 
    100109 
  • plumimediaqueue/trunk/src/plumimediaqueue/queues/bittorrent.py

    r536 r922  
    3232    if IBittorrentQueue.providedBy(q) and obj.starting(): 
    3333        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  
    4646        url_parts = urlparse(download_url) 
    4747        rel_fp = url_parts[1]+url_parts[2] 
    48         incoming_filename = event.newParent.download_dir + '/' + rel_fp 
     48        incoming_filename = q.download_dir + '/' + rel_fp 
    4949        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])) 
    5050        logging.info("downloading media file from url %s, into location %s " % (download_url,incoming_filename)) 
     
    6161            #tell the queue we failed. 
    6262            q.fail_job(obj.uuid) 
     63            #nothing added to transcoding or bittorrent queues 
    6364            return 
     65 
     66        #XXX 
     67        #do an MD5 checksum on the file, and store it on the object 
     68 
    6469 
    6570        logging.info("finished downloading") 
     
    7075        #Add a jobitem for the transcoding queue, and bittorrent queues. 
    7176        t_nm=NetworkMediaItem() 
    72         t_nm.file_path = incoming_filename 
     77        t_nm.copy(obj) 
    7378        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 
    7582        q.__parent__['transcoding'].add_job(t_nm) 
     83 
    7684        q.__parent__['bittorrent'].add_job(bt_nm) 
     85 
  • plumimediaqueue/trunk/src/plumimediaqueue/queues/transcoding.py

    r656 r922  
    44 
    55from plumimediaqueue.models import Queue, NetworkMediaItem 
    6  
    7 import logging 
    8 import os 
     6from plumimediaqueue.events.interfaces import IJobResetEvent 
     7 
     8import logging , os , traceback , time, subprocess 
    99 
    1010class ITranscodingQueue(IQueue): 
     
    1414                    ) 
    1515 
     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 
    1631    mencoder_flv_options = Text( 
    1732                            title = u"MEncoder command line to produce FLV files.",  
    1833                            description=u"The set of options to pass to MEncoder when transcoding" 
    1934                            ) 
     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 
    2058 
    2159    file_extensions =  List( 
     
    2563                            ) 
    2664 
    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  
    3865class TranscodingQueue(Queue): 
    3966    grok.implements(ITranscodingQueue) 
    4067 
    4168    #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' 
    4374 
    4475    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' 
    4576 
     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 
    4679    file_extensions=['.avi','.qt','.mov','.mpeg','.mp4','.mpg','.asf','.wmv','.3gp','.m4v','.ogm','.ogg','.divx','flv'] 
    4780 
    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' 
    5186 
    5287    def __init__(self,id=None): 
     
    6398 
    6499@grok.subscribe(NetworkMediaItem, grok.IObjectAddedEvent) 
     100@grok.subscribe(NetworkMediaItem, IJobResetEvent) 
    65101def handle(obj, event): 
    66102    #check if the JobItem is STARTING 
     
    78114 
    79115def 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 """ 
    81117        #whether or not the transcoding worked for the given file 'f' 
    82118        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 
    83123 
    84124        #get filepath, and then split into stem and extension, and return false straight away if not in recognised set. 
     
    89129 
    90130        #setup filenames we will need. 
    91         videofile = f 
    92         lockfile = f+".trans_lock"  # we are encoding already 
    93         skipfile = f+".trans_skip"  # we tried and failed, don't bother again 
    94         flvfile  = transcoding_queue.transcoding_dir + stem +  ".flv" # output FLV file 
    95         theorafile = transcoding_queue.transcoding_dir + ".ogg" # output OGG file 
    96         includefile  = self.INCLUDE_FILE_DIRECTORY+stem+self.INCLUDE_FILE_SUFFIX 
    97         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)) 
    98138 
    99139        #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): 
    101141            #dont do it 
    102142            return False 
    103143 
    104144        #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)) 
    106146        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 
    107154            # touch the lock file 
    108155            #we should catch the exception here, and return FALSE! 
     
    112159                logging.info("lock file creation failed! ABORTING. %s " % lockfile) 
    113160                return False 
    114             #lets make sure all the directories are created 
    115             try: 
    116                 os.makedirs(os.path.dirname(flvfile)) 
    117             except: 
    118                 #the dirs may already exist 
    119                 pass 
    120161             
    121             logging.info('OK to try encoding: '+videofile) 
     162            logging.info('OK to try encoding: '+original_videofile) 
    122163            #mencoder flv conversion 
    123164            start_time=time.time() 
    124             encoder_command = self.MENCODER_LOCATION + " -quiet " + videofile + " -o " + flvfile + " " + self.MENCODER_OPTIONS 
    125             encoder_command_string = 'nice -n '+self.BE_HOW_NICE+' '+encoder_command 
     165            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 
    126167            output,error = subprocess.Popen([encoder_command_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 
    127168            logging.debug("FLV transcoder output: %s ; error: %s" %(output,error)) 
    128             flvtool_command = self.FLVTOOL_LOCATION+" -U stdin "+flvfile 
    129             flvtool_command_string = "cat "+ flvfile +" | "+ 'nice -n '+ self.BE_HOW_NICE+' '+flvtool_command 
     169            flvtool_command = transcoding_queue.flvtool_installed_location+" -U stdin "+flvfile 
     170            flvtool_command_string = "cat "+ flvfile +" | "+ 'nice -n '+ transcoding_queue.nice_level + ' '+flvtool_command 
    130171            output,error = subprocess.Popen([flvtool_command_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 
    131172            logging.debug("FLV tool output: %s ; error: %s" %(output,error)) 
    132173            #XXX update the set of transformed file paths on the item. 
    133174            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)) 
    135176 
    136177            #ffmpeg2theora , theora/ogg conversion 
    137178            start_time=time.time()   
    138             theora_cmd =  self.FFMPEG2THEORA_COMMAND + ' ' + videofile + " -o " + theorafile 
    139             theora_cmd_string='nice -n '+ self.BE_HOW_NICE+' '+ theora_cmd 
     179            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 
    140181            output,error = subprocess.Popen([theora_cmd_string],shell=True,stdout=subprocess.PIPE,cwd=os.getcwd()).communicate() 
    141182            logging.debug("Theora output: %s ; error: %s" %(output,error)) 
    142183            #XXX update the set of transformed file paths on the item. 
    143184            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)) 
    145186 
    146187            if os.path.exists(flvfile) and os.path.getsize(flvfile)>0 and os.path.exists(theorafile) and os.path.getsize(theorafile)>0: 
    147188                # OK ! It Worked. 
     189 
     190                #update the object with the details of the new file paths. 
     191                networkmediaitem.processed_filepaths=(flvfile,theorafile) 
     192                 
    148193                worked = True 
    149194            else: 
     
    154199                return False 
    155200 
    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 snippet 
    158             if os.path.exists(flvfile) and os.path.getsize(flvfile)>0: 
    159                     #lets make sure all the directories are created 
    160                     try: 
    161                         os.makedirs(os.path.dirname(includefile)) 
    162                     except: 
    163                         #the dirs may already exist 
    164                         pass 
    165  
    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                        
    182201        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())) 
    184203            #catch exception to remove lock file. 
    185204            os.remove(lockfile) 
    186205            return False 
    187206 
     207        os.remove(lockfile) 
    188208        #return a status value if we managed to get all the way here. 
    189209        return worked