From: Tom C. <te...@us...> - 2004-03-18 01:39:58
|
Update of /cvsroot/quickrip/ng In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30742 Modified Files: base.py Log Message: Added remaining encoding functions (mp3/ogg audio, divx/xvid/mpeg2 video, avi/ogm container) Added ability to detect PAL/NTSC/NTSCPROG format Index: base.py =================================================================== RCS file: /cvsroot/quickrip/ng/base.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** base.py 7 Mar 2004 23:36:03 -0000 1.8 --- base.py 18 Mar 2004 01:30:26 -0000 1.9 *************** *** 67,70 **** --- 67,72 ---- 'oggenc': ['paths', self.findProgram("oggenc")], \ 'ogmmerge': ['paths', self.findProgram("ogmmerge")], \ + 'ffmpeg': ['paths', self.findProgram("ffmpeg")], \ + 'tcmplex': ['paths', self.findProgram("tcmplex")], \ 'outputdir': ['paths', os.path.expanduser("~")], \ 'dvd_device': ['paths', os.path.join("/", "dev", "dvd")], \ *************** *** 176,180 **** if self.config['logging'] == 'Off': return ! elif self.config['logging'] == 'Normal' and level == 'Normal': if not os.path.isfile(self.config['logfile']): create_log = open(self.config['logfile'], 'w') --- 178,182 ---- if self.config['logging'] == 'Off': return ! elif self.config['logging'] in ['Normal', 'Debug'] and level == 'Normal': if not os.path.isfile(self.config['logfile']): create_log = open(self.config['logfile'], 'w') *************** *** 182,189 **** create_log.close() log = open(self.config['logfile'], 'a') ! log.write(entry + "\n") log.close() # The following functions are threaded, but are processed in the order # in which they appear here. - biggs --- 184,208 ---- create_log.close() log = open(self.config['logfile'], 'a') ! log.write("\n\n\n" + entry + "\n") ! log.close() ! elif self.config['logging'] == 'Debug' and level == 'Debug': ! if not os.path.isfile(self.config['logfile']): ! create_log = open(self.config['logfile'], 'w') ! create_log.write("QuickRip log file\n\n") ! create_log.close() ! #entry = re.sub('\n', '', entry) ! log = open(self.config['logfile'], 'a') ! log.write(entry) log.close() + def cleanCWD(self): + """Clean out the current working directory""" + for file in ['/frameno.avi', '/audio.wav', '/audio.ogg', '/audio.mpa', \ + '/video.mpv', '/video.mpg', '/video.avi']: + os.popen("".join(["rm ", self.config['outputdir'], file, \ + " 2>/dev/null"])) + + # The following functions are threaded, but are processed in the order # in which they appear here. - biggs *************** *** 206,209 **** --- 225,229 ---- for t in self.raw_dvd.tracks: title = {} + title['format'] = 'pal' title['rip'] = 'no' title['id'] = t['trackno'] *************** *** 229,233 **** self.titles.append(title) self.notify_dispTitle(title) - self.notify_finishScanning() --- 249,252 ---- *************** *** 255,271 **** for title in self.torip: # Clean up output directory ! os.popen("".join(["rm ", self.config['outputdir'], "/frameno.avi", \ ! " 2>/dev/null"])) ! os.popen("".join(["rm ", self.config['outputdir'], "/audio.wav", \ ! " 2>/dev/null"])) ! os.popen("".join(["rm ", self.config['outputdir'], "/audio.ogg", \ ! " 2>/dev/null"])) ! os.popen("".join(["rm ", self.config['outputdir'], "/video.avi", \ ! " 2>/dev/null"])) self.notify_newTitle(title['name'], i, self.numrips, title['vbr']) i = i + 1 ! # Look for cropping if not title.has_key('crop'): sstep = int(title['length']) / 31 --- 274,283 ---- for title in self.torip: # Clean up output directory ! self.cleanCWD() self.notify_newTitle(title['name'], i, self.numrips, title['vbr']) i = i + 1 ! # Look for cropping and format if not title.has_key('crop'): sstep = int(title['length']) / 31 *************** *** 282,286 **** # Rip title if self.config['videocodec'] == 'mpeg2': ! self.ripSVCD(title) while self.state == 'ripping': sleep(1) --- 294,310 ---- # Rip title if self.config['videocodec'] == 'mpeg2': ! self.ripWavAudio(title) ! while self.state == 'ripping': ! sleep(1) ! self.ffmpegEnc(title) ! while self.state == 'ripping': ! sleep(1) ! self.ripVideo(title) ! while self.state == 'ripping': ! sleep(1) ! self.extractRawVideo(title) ! while self.state == 'ripping': ! sleep(1) ! self.tcmplex(title) while self.state == 'ripping': sleep(1) *************** *** 292,301 **** while self.state == 'ripping': sleep(1) ! #self.ripVideo(title) ! #while self.state == 'ripping': ! # sleep(1) ! #self.ogmMerge(title) ! #while self.state == 'ripping': ! # sleep(1) else: self.ripMp3Audio(title) --- 316,325 ---- while self.state == 'ripping': sleep(1) ! self.ripVideo(title) ! while self.state == 'ripping': ! sleep(1) ! self.ogmMerge(title) ! while self.state == 'ripping': ! sleep(1) else: self.ripMp3Audio(title) *************** *** 305,318 **** while self.state == 'ripping': sleep(1) ! self.notify_finishRipping() def cropDetect(self, lines, data): re_crop = re.compile('.*-vop crop=(\d*:\d*:\d*:\d*).*') crop_options = {} common_crop = "" cc_hits = 0 title = data for line in lines: if re_crop.search(line): --- 329,348 ---- while self.state == 'ripping': sleep(1) ! ! # Clean up and notify of end of process ! self.cleanCWD() self.notify_finishRipping() def cropDetect(self, lines, data): + """Detect cropping and video format""" re_crop = re.compile('.*-vop crop=(\d*:\d*:\d*:\d*).*') + re_ntscprog = re.compile('24fps progressive NTSC content detected') + re_pal = re.compile('25.000 fps') crop_options = {} common_crop = "" cc_hits = 0 title = data + found_format = 0 for line in lines: if re_crop.search(line): *************** *** 324,342 **** except: crop_options[crop] = 1 title['crop'] = common_crop - - - def ripSVCD(self, title): - """Rip a DVD title for an SVCD""" - self.notify_newPass("svcd") - self.state = "ripping" - - # Work out filename - output = os.path.join(self.config['outputdir'], str(title['name'])) - output = ''.join([output, ".mpeg"]) - - ## Assemble basic command - # I tried transcode, but failed to understand it - # I'll look into mencvcd (in mplayer source tarball in mplayer/TOOLS) --- 354,367 ---- except: crop_options[crop] = 1 + # Based on freevo code (www.freevo.org) + if re_ntscprog.search(line): + title['format'] = 'ntscprog' + found_format = 1 + if re_pal.search(line): + title['format'] = 'pal' + found_format = 1 + if not found_format: + title['format'] = 'ntsc' title['crop'] = common_crop *************** *** 346,350 **** self.state = "ripping" # Work out options to send to mplayer ! arguments = ["-dvd", str(title['id']), "-alang", title['alang'], \ "-ao", "pcm", "-vo", "null", "-vc", "dummy", "-aofile", \ os.path.join(self.config['outputdir'], "audio.wav")] --- 371,375 ---- self.state = "ripping" # Work out options to send to mplayer ! arguments = ["-dvd", str(title['id']), "-alang", title['alang'], '-waveheader', \ "-ao", "pcm", "-vo", "null", "-vc", "dummy", "-aofile", \ os.path.join(self.config['outputdir'], "audio.wav")] *************** *** 358,370 **** self.notify_newPass("oggenc") self.state = "ripping" ! # Work out options to send to mplayer arguments = [''.join(["-b", str(title['abr'])]), ''.join(["-o", \ os.path.join(self.config['outputdir'], "audio.ogg")]), \ os.path.join(self.config['outputdir'], "audio.wav")] ! # Run mplayer self.run('oggenc', arguments, self.pipeFinished, self.oggencProgress, \ flushbuffer=100, data=("oggenc",title)) def ripMp3Audio(self, title): """Rip the audio in mp3 format""" --- 383,408 ---- self.notify_newPass("oggenc") self.state = "ripping" ! # Work out options to send to oggenc arguments = [''.join(["-b", str(title['abr'])]), ''.join(["-o", \ os.path.join(self.config['outputdir'], "audio.ogg")]), \ os.path.join(self.config['outputdir'], "audio.wav")] ! # Run oggenc self.run('oggenc', arguments, self.pipeFinished, self.oggencProgress, \ flushbuffer=100, data=("oggenc",title)) + def ffmpegEnc(self, title): + """Encode a wav into an ogg""" + self.notify_newPass("ffmpeg") + self.state = "ripping" + # Work out options to send to ffmpeg + arguments = ['-y', '-i', os.path.join(self.config['outputdir'], "audio.wav"), \ + '-ab', str(title['abr']), '-ar', '44100', '-ac', '2', '-f', 'mp2', \ + os.path.join(self.config['outputdir'], "audio.mpa")] + # Run ffmpeg + self.run('ffmpeg', arguments, self.pipeFinished, self.ffmpegProgress, \ + flushbuffer=100, data=("ffmpeg",title)) + + def ripMp3Audio(self, title): """Rip the audio in mp3 format""" *************** *** 391,396 **** # Work out filename ! output = os.path.join(self.config['outputdir'], str(title['name'])) ! output = ''.join([output, ".avi"]) ## Work out options to send to mencoder --- 429,439 ---- # Work out filename ! if self.config['audiocodec'] == 'ogg': ! output = os.path.join(self.config['outputdir'], 'video.avi') ! elif self.config['videocodec'] == 'mpeg2': ! output = os.path.join(self.config['outputdir'], 'video.mpg') ! else: ! output = os.path.join(self.config['outputdir'], str(title['name'])) ! output = ''.join([output, ".avi"]) ## Work out options to send to mencoder *************** *** 398,408 **** if self.config['pdamode'] == 'On': resolution = "320" else: resolution = "720" - # Audio? - if self.config['audiocodec'] == 'mp3': - oac = "copy" - else: - oac = "null" # Video? if self.config['videocodec'] == 'xvid': --- 441,448 ---- if self.config['pdamode'] == 'On': resolution = "320" + elif self.config['videocodec'] == 'mpeg2': + resolution = "480" else: resolution = "720" # Video? if self.config['videocodec'] == 'xvid': *************** *** 411,414 **** --- 451,459 ---- ovc_opts = "".join(["4mv:me_quality=6:mod_quant:quant_range=1-31/1-31:", \ "bitrate=", str(int(title['vbr']))]) + elif self.config['videocodec'] == 'mpeg2': + ovc = "lavc" + ovc_opts_type = "-lavcopts" + ovc_opts = "".join(["vcodec=mpeg1video:vhq:vrc_minrate=300:vrc_maxrate=2400:", \ + "vbitrate=", str(int(title['vbr']))]) else: ovc = "lavc" *************** *** 416,427 **** ovc_opts = "".join(["vcodec=mpeg4:vhq:vbitrate=", str(int(title['vbr']))]) # Cropping ! vop = "".join(["scale,crop=", title['crop']]) # Deinterlacing? if self.config['deinterlacing'] == 'On': vop = "".join([vop, ",dint"]) # Build it all up ! arguments = ["-dvd", str(title['id']), "-alang", title['alang'], "-oac", oac, \ "-ovc", ovc, ovc_opts_type, ovc_opts, "-vop", vop, "-zoom", \ ! "-xy", resolution, "-o", output] # Non-default aspect ratio? if self.config['aspectratio'] != 'Default': --- 461,492 ---- ovc_opts = "".join(["vcodec=mpeg4:vhq:vbitrate=", str(int(title['vbr']))]) # Cropping ! if self.config['videocodec'] == 'mpeg2': ! vop = "".join(["scale=480:576,expand=480:576,crop=", title['crop']]) ! else: ! vop = "".join(["scale,crop=", title['crop']]) # Deinterlacing? if self.config['deinterlacing'] == 'On': vop = "".join([vop, ",dint"]) + # FPS, based on video format + if title['format'] == 'pal': + fps = '25' + elif title['format'] == 'ntsc': + fps = '30' + elif title['format'] == 'ntscprog': + fps = '24' # Build it all up ! arguments = ["-dvd", str(title['id']), "-alang", title['alang'], \ "-ovc", ovc, ovc_opts_type, ovc_opts, "-vop", vop, "-zoom", \ ! "-ofps", fps, "-xy", resolution, "-o", output] ! # Audio? ! if self.config['audiocodec'] in ['ogg', 'mpeg2']: ! arguments.insert(4, "-nosound") ! else: ! arguments.insert(4, "-oac") ! arguments.insert(5, "copy") ! # Output format? ! if self.config['videocodec'] == 'mpeg2': ! arguments.insert(4, "-of") ! arguments.insert(5, "mpeg") # Non-default aspect ratio? if self.config['aspectratio'] != 'Default': *************** *** 437,440 **** --- 502,560 ---- + def ogmMerge(self, title): + """Merge the OGG and AVI files into an OGM""" + self.notify_newPass("ogmmerge") + self.state = "ripping" + + # Work out filenames + video = os.path.join(self.config['outputdir'], str(title['name'])) + video = ''.join([video, ".avi"]) + output = os.path.join(self.config['outputdir'], str(title['name'])) + output = ''.join([output, ".ogm"]) + + # Work out options to send to ogmmerge + arguments = ["-o", output, '-A', video, 'audio.ogg'] + + # Run ogmmerge + self.run('ogmmerge', arguments, self.pipeFinished, self.ogmmergeProgress, \ + flushbuffer=100, data=("ogmmerge",title)) + + + def extractRawVideo(self, title): + """Extract raw video""" + self.state = "ripping" + + # Work out filenames + video = os.path.join(self.config['outputdir'], 'video.mpg') + vidtmp = os.path.join(self.config['outputdir'], 'video.mpv') + + # Work out options to send to mplayer + arguments = ["-noframedrop", '-vc', 'dummy', '-vo', 'null', '-dumpvideo', \ + '-dumpfile', vidtmp, video] + + # Run mplayer to extract raw video + self.run('mplayer', arguments, self.pipeFinishedSilent, None, \ + flushbuffer=100, data=("mplayer",title)) + + + def tcmplex(self, title): + """Merge video with audio into an MPEG""" + self.notify_newPass("tcmplex") + self.state = "ripping" + + # Work out filenames + audio = os.path.join(self.config['outputdir'], 'audio.mpa') + vidtmp = os.path.join(self.config['outputdir'], 'video.mpv') + output = os.path.join(self.config['outputdir'], str(title['name'])) + output = ''.join([output, ".mpeg"]) + + # Work out options to send to tcmplex + arguments = ["-m", 's', '-i', vidtmp, '-p', audio, '-o', output] + + # Run tcmplex + self.run('tcmplex', arguments, self.pipeFinished, self.tcmplexProgress, \ + flushbuffer=100, data=("tcmplex",title)) + + def mencodeProgress(self, line, (passtype,title)): """Report progress of mencoder pass""" *************** *** 466,469 **** --- 586,625 ---- trem = re_progress.search(line).group(2) self.notify_updateProgress(perc, trem, passtype) + + + def ffmpegProgress(self, line, (passtype,title)): + """Report progress of ffmpeg pass""" + perc = 0 + re_progress = re.compile('time=(\d+.\d)') + if re_progress.search(line): + progress = re_progress.search(line).group(1) + perc = int((float(progress) / float(title['length']) * 100)) + self.notify_updateProgress(perc, None, passtype) + + + def ogmmergeProgress(self, line, (passtype,title)): + """Report progress of ogmmerge pass""" + perc = 0 + re_progress = re.compile('frames \((\d+)\%\)') + if re_progress.search(line): + perc = float(re_progress.search(line).group(1)) + self.notify_updateProgress(perc, None, passtype) + + + def tcmplexProgress(self, line, (passtype,title)): + """Report progress of ogmmerge pass""" + perc = 0 + re_video = re.compile('Scanning video stream: (\d*)\%') + re_audio = re.compile('Scanning audio stream: (\d*)\%') + re_mplex = re.compile('Multiplexing: (\d*)\%') + if re_video.search(line): + perc = float(re_video.search(line).group(1)) * (1.0/3.0) + self.notify_updateProgress(perc, None, passtype) + elif re_audio.search(line): + perc = (float(re_audio.search(line).group(1)) * (1.0/3.0)) + (100.0/3.0) + self.notify_updateProgress(perc, None, passtype) + elif re_mplex.search(line): + perc = (float(re_mplex.search(line).group(1)) * (1.0/3.0)) + (100.0/1.5) + self.notify_updateProgress(perc, None, passtype) *************** *** 473,476 **** --- 629,638 ---- sleep(2) self.state = "still" + + + def pipeFinishedSilent(self, lines, passtype): + """Finish off odds and ends after pipe silently""" + sleep(2) + self.state = "still" *************** *** 547,557 **** else: totallines.append(line) if self.updateFunc: self.updateFunc(line, self.data) - #try: - # stderr_line = os.read(self.pipe.childerr.fileno(), 100) - # self.log('Debug', stderr_line) - #except: - # pass except: # For PyGtk... weird! --- 709,715 ---- else: totallines.append(line) + self.parent.log('Debug', line) if self.updateFunc: self.updateFunc(line, self.data) except: # For PyGtk... weird! |