def doTranscodeVC1(self, srcfile, outfile, trackinfo): id = trackinfo['unique id'] if self.h264bitrate is None: # use source stream bitrate # convert bits/sec to Kbits/sec bitrate = str(int(trackinfo['bit rate'] / 1000.)) else: bitrate = str(self.h264bitrate) framerate = trackinfo['frame rate'].split()[0] encopts = ":".join( ["%s=%s" % tuple(map(str, i)) for i in self.x264opts.iteritems()]) # TODO: necessary? (TEST) encopts += ":fps=%s" % framerate # really force this txcode_cmd = ['HandBrakeCLI', '-i', srcfile, '-o', outfile, # no audio '-a', 'none', '-e', 'x264', '--width', str(trackinfo['width']), '--height', str(trackinfo['height']), '-b', bitrate, '-r', framerate, '-x', encopts] if self.twoPassEncode: txcode_cmd += ['--two-pass'] if self.turboFirstPass: txcode_cmd += ['--turbo'] printFriendlyCmd = " ".join(txcode_cmd) common_util.Msg("Transcoding video track %s to H.264" % id) common_util.Babble("Video endoding cmd: %s" % printFriendlyCmd) mgr = self.getProcessManager() retcode, sout, serr = mgr.call(txcode_cmd) if retcode == 0: common_util.Msg("Transcode complete.") else: raise subp.CalledProcessError(retcode, printFriendlyCmd)
def extractTracks(self, srcfile, trackProcessData): procMgr = self.getProcessManager() files = [] for id, t in trackProcessData.iteritems(): if t.extractTo is not None: files.append("%s:%s" % (id, t.extractTo)) if len(files) > 0: common_util.Msg("Extracting tracks from %s" % srcfile) cmd = [self.mkvextract, 'tracks', srcfile] + files retcode, sout, serr = procMgr.call(cmd) if retcode != 0: common_util.Error("Failure to extract track data from %s" % srcfile) common_util.Msg("mkvextract output: %s\n%s" % (sout, serr)) return False for dat in trackProcessData.itervalues(): if hasattr(dat.doOnExtracted, '__call__'): if not dat.doOnExtracted(dat): # error condition # autoripd will clean up the working dir return False return True
def processRip(self, mediaFilePath, mediaMetadata, programSettings, workingDir, previousPluginData): """Remux a rip into an .m2ts file.""" self.assignSettings(programSettings) self.origFile = mediaFilePath # should we perform the mux? media_base = os.path.basename(mediaFilePath) fname, ext = os.path.splitext(media_base) if mediaMetadata['format'] != 'Matroska': return {} # find a name/place for the new file outdir = self.m2tsDir if outdir is None: # ship .m2ts files to the same place as the other rips outdir = self.autoripd_settings.destDir if not os.path.exists(outdir): os.makedirs(outdir) outname = fname + ".m2ts" outfile = common_util.uniquePath(os.path.join(outdir, outname)) # perform the mux newfile = self.remux(mediaFilePath, outfile, mediaMetadata, workingDir) # backup and/or delete the original source if newfile is not None: bkupdir = self.srcBackupDir if bkupdir is not None and \ self.preserveSrc and \ not os.path.samefile(bkupdir, os.path.dirname(mediaFilePath)): if not os.path.isdir(bkupdir): os.path.makedirs(bkupdir) dstpath = common_util.uniquePath(os.path.join(bkupdir, media_base)) os.rename(mediaFilePath, dstpath) elif not self.preserveSrc: os.unlink(mediaFilePath) common_util.Msg("Removed %s" % mediaFilePath) else: raise Exception("remuxer encountered a problem; aborted") return {'mux_new_m2tsfile' : newfile}
def doTranscodeDTS(self, tkinfo): pman = self.getProcessManager() metadata = tkinfo.metadata dtsfile = tkinfo.extractTo ac3file = tkinfo.ac3file common_util.Msg("Encoding DTS track %s to AC3" % metadata['unique id']) try: devnull = open(os.devnull, 'w') dcadec_cmd = [self.dcadec, '-o', 'wavall', dtsfile] # we directly pipe the decoded stream to aften for encoding to avoid # writing an enormous 2-hour 6-channel WAV file to disk with pman.Popen(dcadec_cmd, stdout=subp.PIPE, # really important; dcadec spews 'skip' x 1 billion stderr=devnull) as decodp: aften_cmd = [self.aften, '-b', str(self.dtsBitrate), '-w', str(self.dtsBandwidth), '-v', '0', '-', ac3file] with pman.Popen(aften_cmd, stderr=subp.PIPE, stdout=subp.PIPE, stdin=decodp.stdout) as encodp: decodp.stdout.close() # release our handle on this pipe e_sout, e_serr = encodp.communicate() d_ret = decodp.wait() e_ret = encodp.returncode devnull.close() except OSError, err: if err.errno == errno.ENOENT: Error("Trouble launching program while transcoding DTS. " "Are dcadec and aften installed?") try: devnull.close() except: pass raise
def remux(self, infile, outfile, info, workingdir): """Remux <infile> into an .m2ts at <outfile>, returning the complete path of <outfile> upon success, or None upon failure.""" fpath = os.path.abspath(infile) outfpath = os.path.abspath(common_util.uniquePath(outfile)) if not os.path.isfile(fpath): common_util.Error('File %s could not be found for remuxing' % fpath) return None titlename = os.path.splitext(info['file name'])[0] tkProcessData = {} # generate the .meta file # per spec at http://forum.doom9.org/archive/index.php/t-142559.html meta = "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr --vbv-len=500\n" for track in info['tracks']: if 'unique id' not in track or 'codec id' not in track: # not a mux-able track; i.e. a menu track continue id = track['unique id'] result = self.processTrack(titlename, fpath, track, workingdir) if result is None: continue else: meta += result.metaline tkProcessData[id] = result # do the remux with tempfile.NamedTemporaryFile(mode='w', suffix='.meta', dir=workingdir) as tmpf: # write metafile metaname = os.path.abspath(tmpf.name) tmpf.write(meta) tmpf.flush() # extract/process streams ok = self.extractTracks(fpath, tkProcessData) if not ok: return None common_util.Msg("Remuxing %s to %s" % (fpath, outfpath)) common_util.Babble("Metafile:\n%s\n" % meta) # do remux mgr = self.getProcessManager() retcode, sout, serr = mgr.call([self.tsMuxeR, metaname, outfpath]) if retcode != 0: common_util.Error('Failure to remux %s to %s' % (infile, outfpath)) common_util.Msg('tsMuxeR output: %s\n%s' % (sout,serr)) return None # clean up extracted tracks / extra files: for trackdat in tkProcessData.itervalues(): if trackdat.extractTo and os.path.exists(trackdat.extractTo): os.unlink(trackdat.extractTo) for extraf in trackdat.cleanupFiles: if os.path.exists(extraf): os.unlink(extraf) # .meta tmpfile is deleted automatically common_util.Msg("%s remuxed successfully" % outfpath) return outfpath