From 53f199c5a82bcd460d3153814f2e057c747e2a3a Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Wed, 11 Jun 2008 00:07:28 +0000 Subject: add early version of DVDBurn plugin. Basic functionality is working, but it needs a major GUI redesign. Required tools: mplex, projectx, growisofs, mkisofs/genisoimage, dvdauthor --- lib/python/Plugins/Extensions/DVDBurn/Process.py | 248 +++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 lib/python/Plugins/Extensions/DVDBurn/Process.py (limited to 'lib/python/Plugins/Extensions/DVDBurn/Process.py') diff --git a/lib/python/Plugins/Extensions/DVDBurn/Process.py b/lib/python/Plugins/Extensions/DVDBurn/Process.py new file mode 100644 index 00000000..9163b8ae --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDBurn/Process.py @@ -0,0 +1,248 @@ +from Components.Task import Task, Job, job_manager, DiskspacePrecondition, Condition + +class DemuxTask(Task): + def __init__(self, job, inputfile, cutlist): + Task.__init__(self, job, "Demux video into ES") + + self.global_preconditions.append(DiskspacePrecondition(4*1024*1024)) + self.setTool("/opt/bin/projectx") + self.cutfile = self.job.workspace + "/cut.Xcl" + self.generated_files = [ ] + self.cutlist = cutlist + + self.end = 300 + self.prog_state = 0 + self.weighting = 1000 + + self.args += [inputfile, "-demux", "-out", self.job.workspace, "-cut", self.job.workspace + "/" + self.cutfile ] + + def prepare(self): + self.writeCutfile() + + def processOutputLine(self, line): + line = line[:-1] + MSG_NEW_FILE = "---> new File: " + MSG_PROGRESS = "[PROGRESS] " + + if line.startswith(MSG_NEW_FILE): + file = line[len(MSG_NEW_FILE):] + if file[0] == "'": + file = file[1:-1] + self.haveNewFile(file) + elif line.startswith(MSG_PROGRESS): + progress = line[len(MSG_PROGRESS):] + self.haveProgress(progress) + + def haveNewFile(self, file): + print "PRODUCED FILE [%s]" % file + self.generated_files.append(file) + + def haveProgress(self, progress): + print "PROGRESS [%s]" % progress + MSG_CHECK = "check & synchronize audio file" + MSG_DONE = "done..." + if progress == "preparing collection(s)...": + self.prog_state = 0 + elif progress[:len(MSG_CHECK)] == MSG_CHECK: + self.prog_state += 1 + else: + try: + print "have progress:", progress + p = int(progress) + p = p - 1 + self.prog_state * 100 + if p > self.progress: + self.progress = p + except ValueError: + print "val error" + pass + + def writeCutfile(self): + f = open(self.cutfile, "w") + f.write("CollectionPanel.CutMode=4\n") + for p in self.cutlist: + s = p / 90000 + m = s / 60 + h = m / 60 + + m %= 60 + s %= 60 + + f.write("%02d:%02d:%02d\n" % (h, m, s)) + f.close() + + def cleanup(self, failed): + if failed: + import os + for f in self.generated_files: + os.remove(f) + +class MplexTask(Task): + def __init__(self, job, outputfile, demux_task): + Task.__init__(self, job, "Mux ES into PS") + + self.weighting = 500 + self.demux_task = demux_task + self.setTool("/usr/bin/mplex") + self.args += ["-f8", "-o", self.job.workspace + "/" + outputfile, "-v1"] + + def prepare(self): + self.args += self.demux_task.generated_files + +class RemoveESFiles(Task): + def __init__(self, job, demux_task): + Task.__init__(self, job, "Remove temp. files") + self.demux_task = demux_task + self.setTool("/bin/rm") + + def prepare(self): + self.args += ["-f"] + self.args += self.demux_task.generated_files + self.args += [self.demux_task.cutfile] + +class DVDAuthorTask(Task): + def __init__(self, job, inputfiles, chapterlist): + Task.__init__(self, job, "dvdauthor") + + self.weighting = 300 + self.setTool("/usr/bin/dvdauthor") + chapterargs = "--chapters=" + ','.join(["%d:%02d:%02d.%03d" % (p / (90000 * 3600), p % (90000 * 3600) / (90000 * 60), p % (90000 * 60) / 90000, (p % 90000) / 90) for p in chapterlist]) + self.args += ["-t", chapterargs, "-o", self.job.workspace + "/dvd", "-f"] + inputfiles + +class RemovePSFile(Task): + def __init__(self, job, psfile): + Task.__init__(self, job, "Remove temp. files") + self.setTool("/bin/rm") + self.args += ["-f", psfile] + +class DVDAuthorFinalTask(Task): + def __init__(self, job): + Task.__init__(self, job, "dvdauthor finalize") + self.setTool("/usr/bin/dvdauthor") + self.args += ["-T", "-o", self.job.workspace + "/dvd"] + +class BurnTaskPostcondition(Condition): + def check(self, task): + return task.error is None + + def getErrorMessage(self, task): + return { + task.ERROR_MEDIA: ("Medium is not a writeable DVD!"), + task.ERROR_SIZE: ("Content does not fit on DVD!"), + task.ERROR_WRITE_FAILED: ("Write failed!"), + task.ERROR_DVDROM: ("No (supported) DVDROM found!"), + task.ERROR_UNKNOWN: ("An unknown error occured!") + }[task.error] + +class BurnTask(Task): + ERROR_MEDIA, ERROR_SIZE, ERROR_WRITE_FAILED, ERROR_DVDROM, ERROR_UNKNOWN = range(5) + def __init__(self, job): + Task.__init__(self, job, "burn") + + self.weighting = 500 + self.end = 120 # 100 for writing, 10 for buffer flush, 10 for closing disc + self.postconditions.append(BurnTaskPostcondition()) + self.setTool("/bin/growisofs") + self.args += ["-dvd-video", "-dvd-compat", "-Z", "/dev/cdroms/cdrom0", "-V", "Dreambox_DVD", "-use-the-force-luke=dummy", self.job.workspace + "/dvd"] + + def prepare(self): + self.error = None + + def processOutputLine(self, line): + line = line[:-1] + print "[GROWISOFS] %s" % line + if line[8:14] == "done, ": + self.progress = float(line[:6]) + print "progress:", self.progress + elif line.find("flushing cache") != -1: + self.progress = 100 + elif line.find("closing disc") != -1: + self.progress = 110 + elif line.startswith(":-["): + if line.find("ASC=30h") != -1: + self.error = self.ERROR_MEDIA + else: + self.error = self.ERROR_UNKNOWN + print "BurnTask: unknown error %s" % line + elif line.startswith(":-("): + if line.find("No space left on device") != -1: + self.error = self.ERROR_SIZE + elif line.find("write failed") != -1: + self.error = self.ERROR_WRITE_FAILED + elif line.find("unable to open64(\"/dev/cdroms/cdrom0\",O_RDONLY): No such file or directory") != -1: # fixme + self.error = self.ERROR_DVDROM + elif line.find("media is not recognized as recordable DVD") != -1: + self.error = self.ERROR_MEDIA + else: + self.error = self.ERROR_UNKNOWN + print "BurnTask: unknown error %s" % line + +class RemoveDVDFolder(Task): + def __init__(self, job): + Task.__init__(self, job, "Remove temp. files") + self.setTool("/bin/rm") + self.args += ["-rf", self.job.workspace + "/dvd"] + +class DVDJob(Job): + def __init__(self, cue): + Job.__init__(self, "DVD Burn") + self.cue = cue + self.workspace = "/media/hdd/tmp" + self.fromDescription(self.createDescription()) + + def fromDescription(self, description): + nr_titles = int(description["nr_titles"]) + + for i in range(nr_titles): + inputfile = description["inputfile%d" % i] + cutlist_entries = description["cutlist%d_entries" % i] + cutlist = [ ] + for j in range(cutlist_entries): + cutlist.append(int(description["cutlist%d_%d" % (i, j)])) + + chapterlist_entries = description["chapterlist%d_entries" % i] + chapterlist = [ ] + for j in range(chapterlist_entries): + chapterlist.append(int(description["chapterlist%d_%d" % (i, j)])) + + demux = DemuxTask(self, inputfile = inputfile, cutlist = cutlist) + + title_filename = self.workspace + "/dvd_title_%d.mpg" % i + + MplexTask(self, "dvd_title_%d.mpg" % i, demux) + RemoveESFiles(self, demux) + DVDAuthorTask(self, [title_filename], chapterlist = chapterlist) + RemovePSFile(self, title_filename) + DVDAuthorFinalTask(self) + BurnTask(self) + RemoveDVDFolder(self) + + def createDescription(self): + # self.cue is a list of titles, with + # each title being a tuple of + # inputfile, + # a list of cutpoints (in,out) + # a list of chaptermarks + # we turn this into a flat dict with + # nr_titles = the number of titles, + # cutlist%d_entries = the number of cutlist entries for title i, + # cutlist%d_%d = cutlist entry j for title i, + # chapterlist%d_entries = the number of chapters for title i, + # chapterlist%d_%d = chapter j for title i + res = { "nr_titles": len(self.cue) } + for i in range(len(self.cue)): + c = self.cue[i] + res["inputfile%d" % i] = c[0] + res["cutlist%d_entries" % i] = len(c[1]) + for j in range(len(c[1])): + res["cutlist%d_%d" % (i,j)] = c[1][j] + + res["chapterlist%d_entries" % i] = len(c[2]) + for j in range(len(c[2])): + res["chapterlist%d_%d" % (i,j)] = c[2][j] + return res + +def Burn(session, cue): + print "burning cuesheet!" + j = DVDJob(cue) + job_manager.AddJob(j) + return j -- cgit v1.2.3