use multiple titlesets for dvd authoring which allows correct burning of videos with...
authorFraxinas <andreas.frisch@multimedia-labs.de>
Tue, 11 Nov 2008 18:19:09 +0000 (19:19 +0100)
committerFraxinas <andreas.frisch@multimedia-labs.de>
Tue, 11 Nov 2008 18:19:09 +0000 (19:19 +0100)
introduce title properties screen. this is still a draft version.

lib/python/Plugins/Extensions/DVDBurn/DVDProject.py
lib/python/Plugins/Extensions/DVDBurn/DVDTitle.py
lib/python/Plugins/Extensions/DVDBurn/DreamboxDVDtemplate.ddvdp.xml
lib/python/Plugins/Extensions/DVDBurn/Makefile.am
lib/python/Plugins/Extensions/DVDBurn/Process.py
lib/python/Plugins/Extensions/DVDBurn/TitleCutter.py
lib/python/Plugins/Extensions/DVDBurn/TitleList.py
lib/python/Plugins/Extensions/DVDBurn/TitleProperties.py [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDBurn/keymap.xml

index 8d02cb226eb7d0cb78275a8d3a46b1d5bf767735..55a72c10474670020e85afb80caaa07637e3e978 100644 (file)
@@ -1,5 +1,5 @@
 from Tools.Directories import fileExists
 from Tools.Directories import fileExists
-from Components.config import config, ConfigSubsection, ConfigInteger, ConfigYesNo, ConfigText, ConfigSelection, getConfigListEntry, ConfigSequence
+from Components.config import config, ConfigSubsection, ConfigInteger, ConfigText, ConfigSelection, getConfigListEntry, ConfigSequence
 
 class ConfigColor(ConfigSequence):
        def __init__(self):
 
 class ConfigColor(ConfigSequence):
        def __init__(self):
index 1bfb3d646beeb58d658694e46165090eb6808ffd..1ada9ce27a3cf1a25c9645e96d365ce515b65927 100644 (file)
@@ -1,17 +1,35 @@
+from Components.config import config, ConfigSubsection, ConfigSubList, ConfigInteger, ConfigText, ConfigSelection, getConfigListEntry, ConfigSequence, ConfigYesNo
+
+class ConfigFixedText(ConfigText):
+       def __init__(self, text, visible_width=60):
+               ConfigText.__init__(self, default = text, fixed_size = True, visible_width = visible_width)
+       def handleKey(self, key):
+               pass
+
+class ConfigActiveTrack(ConfigYesNo):
+       def __init__(self, default = True):
+               ConfigYesNo.__init__(self, default)
+
 class DVDTitle:
        def __init__(self):
 class DVDTitle:
        def __init__(self):
+               self.properties = ConfigSubsection()
+               self.properties.menutitle = ConfigText(fixed_size = False, visible_width = 80)
+               self.properties.menusubtitle = ConfigText(fixed_size = False, visible_width = 80)
+               self.DVBname = _("Title")
+               self.DVBdescr = _("Description")
+               self.DVBchannel = _("Channel")
+               self.properties.aspect = ConfigSelection(choices = [("4:3", "4:3"), ("16:9", "16:9")])
+               self.properties.widescreen = ConfigSelection(choices = [("nopanscan", "nopanscan"), ("noletterbox", "noletterbox")])
+               self.properties.audiotracks = ConfigSubList()
                self.cuesheet = [ ]
                self.source = None
                self.cuesheet = [ ]
                self.source = None
-               self.name = ""
-               self.descr = ""
                self.filesize = 0
                self.estimatedDiskspace = 0
                self.inputfile = ""
                self.cutlist = [ ]
                self.chaptermarks = [ ]
                self.filesize = 0
                self.estimatedDiskspace = 0
                self.inputfile = ""
                self.cutlist = [ ]
                self.chaptermarks = [ ]
-               self.audiotracks = [ ]
                self.timeCreate = None
                self.timeCreate = None
-               self.sVideoType = -1
+               self.VideoType = -1
 
        def addService(self, service):
                from os import path
 
        def addService(self, service):
                from os import path
@@ -21,18 +39,61 @@ class DVDTitle:
                self.source = service
                serviceHandler = eServiceCenter.getInstance()
                info = serviceHandler.info(service)
                self.source = service
                serviceHandler = eServiceCenter.getInstance()
                info = serviceHandler.info(service)
-               self.descr = info and " " + info.getInfoString(service, iServiceInformation.sDescription) or ""
+               sDescr = info and " " + info.getInfoString(service, iServiceInformation.sDescription) or ""
+               self.DVBdescr = sDescr
                sTimeCreate = info.getInfo(service, iServiceInformation.sTimeCreate)
                if sTimeCreate > 1:
                        self.timeCreate = localtime(sTimeCreate)
                serviceref = ServiceReference(info.getInfoString(service, iServiceInformation.sServiceref))
                sTimeCreate = info.getInfo(service, iServiceInformation.sTimeCreate)
                if sTimeCreate > 1:
                        self.timeCreate = localtime(sTimeCreate)
                serviceref = ServiceReference(info.getInfoString(service, iServiceInformation.sServiceref))
-               self.name = info and info.getName(service) or "Title" + t.descr
-               self.channel = serviceref.getServiceName()
+               name = info and info.getName(service) or "Title" + sDescr
+               self.DVBname = name
+               self.DVBchannel = serviceref.getServiceName()
                self.inputfile = service.getPath()
                self.filesize = path.getsize(self.inputfile)
                self.estimatedDiskspace = self.filesize
                self.length = info.getLength(service)
 
                self.inputfile = service.getPath()
                self.filesize = path.getsize(self.inputfile)
                self.estimatedDiskspace = self.filesize
                self.length = info.getLength(service)
 
+       def initDVDmenuText(self, project, track):
+               self.properties.menutitle.setValue(self.formatDVDmenuText(project.settings.titleformat.getValue(), track))
+               self.properties.menusubtitle.setValue(self.formatDVDmenuText(project.settings.subtitleformat.getValue(), track))
+
+       def formatDVDmenuText(self, template, track):
+               properties = self.properties
+               template = template.replace("$i", str(track))
+               template = template.replace("$t", self.DVBname)
+               template = template.replace("$d", self.DVBdescr)
+               template = template.replace("$c", str(len(self.chaptermarks)+1))
+               template = template.replace("$f", self.inputfile)
+               template = template.replace("$C", self.DVBchannel)
+               
+               #if template.find("$A") >= 0:
+               from TitleProperties import languageChoices
+               audiolist = [ ]
+               for audiotrack in self.properties.audiotracks:
+                       active = audiotrack.active.getValue()
+                       if active:
+                               trackstring = audiotrack.format.getValue()
+                               language = audiotrack.language.getValue()
+                               if languageChoices.langdict.has_key(language):
+                                       trackstring += ' (' + languageChoices.langdict[language] + ')'
+                               audiolist.append(trackstring)
+               audiostring = ', '.join(audiolist)
+               template = template.replace("$A", audiostring)
+               
+               if template.find("$l") >= 0:
+                       l = self.length
+                       lengthstring = "%d:%02d:%02d" % (l/3600, l%3600/60, l%60)
+                       template = template.replace("$l", lengthstring)
+               if self.timeCreate:
+                       template = template.replace("$Y", str(self.timeCreate[0]))
+                       template = template.replace("$M", str(self.timeCreate[1]))
+                       template = template.replace("$D", str(self.timeCreate[2]))
+                       timestring = "%d:%02d" % (self.timeCreate[3], self.timeCreate[4])
+                       template = template.replace("$T", timestring)
+               else:
+                       template = template.replace("$Y", "").replace("$M", "").replace("$D", "").replace("$T", "")
+               return template
+       
        def produceFinalCuesheet(self):
                CUT_TYPE_IN = 0
                CUT_TYPE_OUT = 1
        def produceFinalCuesheet(self):
                CUT_TYPE_IN = 0
                CUT_TYPE_OUT = 1
@@ -84,3 +145,13 @@ class DVDTitle:
                        while chapterpts < self.length*90000:
                                chapterpts += 90000 * 60 * minutes
                                self.chaptermarks.append(chapterpts)
                        while chapterpts < self.length*90000:
                                chapterpts += 90000 * 60 * minutes
                                self.chaptermarks.append(chapterpts)
+
+       def getChapterMarks(self):
+               timestamps = []
+               for p in self.chaptermarks:
+                       h = p / (90000 * 3600)
+                       m = p % (90000 * 3600) / (90000 * 60)
+                       s = p % (90000 * 60) / 90000
+                       ms = (p % 90000) / 90
+                       timestamps.append("%d:%02d:%02d.%03d" % (h, m, s, ms))
+               return timestamps
\ No newline at end of file
index d9831e63bafc35bee434ff532814892ad775d6b0..9a61214a6bd1dcb1183f4ccdd824dfe66f6fdbc5 100644 (file)
@@ -4,7 +4,7 @@
                name="Dreambox DVD record"
                authormode="menu_linked"
                titleformat="$i. $t"
                name="Dreambox DVD record"
                authormode="menu_linked"
                titleformat="$i. $t"
-               subtitleformat="$D.$M.$Y, $T $C, $d ($c chapters)"
+               subtitleformat="$D.$M.$Y, $T $C, $d"
                vmgm="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/vmgmdream.mpg"
                menubg="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/dreamdvd_boat.jpg"
                menuaudio="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/silence.mp2"
                vmgm="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/vmgmdream.mpg"
                menubg="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/dreamdvd_boat.jpg"
                menuaudio="/usr/lib/enigma2/python/Plugins/Extensions/DVDBurn/silence.mp2"
index cb65f56aa62ec1e3546aa2be57e7a2a9fa52337c..be89ebaa9e5f3f23ff5d5a2b6f213bb1565dae5b 100644 (file)
@@ -3,7 +3,7 @@ installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/DVDBurn
 install_PYTHON =       \
        __init__.py \
        plugin.py \
 install_PYTHON =       \
        __init__.py \
        plugin.py \
-       DVDProject.py DVDTitle.py TitleCutter.py TitleList.py Process.py ProjectSettings.py DVDToolbox.py
+       DVDProject.py DVDTitle.py TitleCutter.py TitleList.py TitleProperties.py Process.py ProjectSettings.py DVDToolbox.py
 
 install_DATA = *.xml *.jpg *.mpg *.mp2 *.png
 
 
 install_DATA = *.xml *.jpg *.mpg *.mp2 *.png
 
index 490545966e6995bec615795bb16f31a4aa0117da..3cf874c0b3ad16265c1c9d4eb40b107bad986bb5 100644 (file)
@@ -85,23 +85,34 @@ class DemuxTask(Task):
                title = job.project.titles[job.i]
                self.global_preconditions.append(DiskspacePrecondition(title.estimatedDiskspace))
                self.setTool("/usr/bin/projectx")
                title = job.project.titles[job.i]
                self.global_preconditions.append(DiskspacePrecondition(title.estimatedDiskspace))
                self.setTool("/usr/bin/projectx")
-               self.generated_files = [ ]
+               self.args += [inputfile, "-demux", "-out", self.job.workspace ]
                self.end = 300
                self.prog_state = 0
                self.weighting = 1000
                self.cutfile = self.job.workspace + "/cut_%d.Xcl" % (job.i+1)
                self.cutlist = title.cutlist
                self.end = 300
                self.prog_state = 0
                self.weighting = 1000
                self.cutfile = self.job.workspace + "/cut_%d.Xcl" % (job.i+1)
                self.cutlist = title.cutlist
-               self.args += [inputfile, "-demux", "-out", self.job.workspace ]
+               self.currentPID = None
+               self.relevantAudioPIDs = [ ]
+               self.getRelevantAudioPIDs(title)
+               self.generated_files = [ ]
+               self.mplex_streamfiles = [ ]
                if len(self.cutlist) > 1:
                        self.args += [ "-cut", self.cutfile ]
 
        def prepare(self):
                self.writeCutfile()
 
                if len(self.cutlist) > 1:
                        self.args += [ "-cut", self.cutfile ]
 
        def prepare(self):
                self.writeCutfile()
 
+       def getRelevantAudioPIDs(self, title):
+               for audiotrack in title.properties.audiotracks:
+                       if audiotrack.active.getValue():
+                               self.relevantAudioPIDs.append(audiotrack.pid.getValue())
+
        def processOutputLine(self, line):
                line = line[:-1]
                MSG_NEW_FILE = "---> new File: "
                MSG_PROGRESS = "[PROGRESS] "
        def processOutputLine(self, line):
                line = line[:-1]
                MSG_NEW_FILE = "---> new File: "
                MSG_PROGRESS = "[PROGRESS] "
+               MSG_NEW_MP2 = "--> MPEG Audio (0x"
+               MSG_NEW_AC3 = "--> AC-3/DTS Audio on PID "
 
                if line.startswith(MSG_NEW_FILE):
                        file = line[len(MSG_NEW_FILE):]
 
                if line.startswith(MSG_NEW_FILE):
                        file = line[len(MSG_NEW_FILE):]
@@ -111,10 +122,14 @@ class DemuxTask(Task):
                elif line.startswith(MSG_PROGRESS):
                        progress = line[len(MSG_PROGRESS):]
                        self.haveProgress(progress)
                elif line.startswith(MSG_PROGRESS):
                        progress = line[len(MSG_PROGRESS):]
                        self.haveProgress(progress)
+               elif line.startswith(MSG_NEW_MP2) or line.startswith(MSG_NEW_AC3):
+                       self.currentPID = str(int(line.rstrip()[-6:].rsplit('0x',1)[-1],16))
 
        def haveNewFile(self, file):
 
        def haveNewFile(self, file):
-               print "PRODUCED FILE [%s]" % file
+               print "[DemuxTask] produced file:", file
                self.generated_files.append(file)
                self.generated_files.append(file)
+               if self.currentPID in self.relevantAudioPIDs or file.endswith("m2v"):
+                       self.mplex_streamfiles.append(file)
 
        def haveProgress(self, progress):
                #print "PROGRESS [%s]" % progress
 
        def haveProgress(self, progress):
                #print "PROGRESS [%s]" % progress
@@ -131,7 +146,6 @@ class DemuxTask(Task):
                                if p > self.progress:
                                        self.progress = p
                        except ValueError:
                                if p > self.progress:
                                        self.progress = p
                        except ValueError:
-                               print "val error"
                                pass
 
        def writeCutfile(self):
                                pass
 
        def writeCutfile(self):
@@ -151,8 +165,8 @@ class DemuxTask(Task):
        def cleanup(self, failed):
                if failed:
                        import os
        def cleanup(self, failed):
                if failed:
                        import os
-                       for f in self.generated_files:
-                               os.remove(f)
+                       for file in self.generated_files.itervalues():
+                               os.remove(file)
 
 class MplexTaskPostcondition(Condition):
        def check(self, task):
 
 class MplexTaskPostcondition(Condition):
        def check(self, task):
@@ -185,9 +199,9 @@ class MplexTask(Task):
                # we don't want the ReturncodePostcondition in this case because for right now we're just gonna ignore the fact that mplex fails with a buffer underrun error on some streams (this always at the very end)
 
        def prepare(self):
                # we don't want the ReturncodePostcondition in this case because for right now we're just gonna ignore the fact that mplex fails with a buffer underrun error on some streams (this always at the very end)
 
        def prepare(self):
-               self.error = None                       
+               self.error = None
                if self.demux_task:
                if self.demux_task:
-                       self.args += self.demux_task.generated_files
+                       self.args += self.demux_task.mplex_streamfiles
 
        def processOutputLine(self, line):
                print "[MplexTask] ", line[:-1]
 
        def processOutputLine(self, line):
                print "[MplexTask] ", line[:-1]
@@ -206,7 +220,7 @@ class RemoveESFiles(Task):
 
        def prepare(self):
                self.args += ["-f"]
 
        def prepare(self):
                self.args += ["-f"]
-               self.args += self.demux_task.generated_files
+               self.args += self.demux_task.generated_files.values()
                self.args += [self.demux_task.cutfile]
 
 class DVDAuthorTask(Task):
                self.args += [self.demux_task.cutfile]
 
 class DVDAuthorTask(Task):
@@ -411,27 +425,6 @@ class PreviewTaskPostcondition(Condition):
        def getErrorMessage(self, task):
                return "Cancel"
 
        def getErrorMessage(self, task):
                return "Cancel"
 
-def formatTitle(template, title, track):
-       template = template.replace("$i", str(track))
-       template = template.replace("$t", title.name)
-       template = template.replace("$d", title.descr)
-       template = template.replace("$c", str(len(title.chaptermarks)+1))
-       template = template.replace("$A", str(title.audiotracks))
-       template = template.replace("$f", title.inputfile)
-       template = template.replace("$C", title.channel)
-       l = title.length
-       lengthstring = "%d:%02d:%02d" % (l/3600, l%3600/60, l%60)
-       template = template.replace("$l", lengthstring)
-       if title.timeCreate:
-               template = template.replace("$Y", str(title.timeCreate[0]))
-               template = template.replace("$M", str(title.timeCreate[1]))
-               template = template.replace("$D", str(title.timeCreate[2]))
-               timestring = "%d:%02d" % (title.timeCreate[3], title.timeCreate[4])
-               template = template.replace("$T", timestring)
-       else:
-               template = template.replace("$Y", "").replace("$M", "").replace("$D", "").replace("$T", "")
-       return template.decode("utf-8")
-
 class ImagingPostcondition(Condition):
        def check(self, task):
                return task.returncode == 0
 class ImagingPostcondition(Condition):
        def check(self, task):
                return task.returncode == 0
@@ -518,14 +511,13 @@ class MenuImageTask(Task):
                                menu_end_title = nr_titles+1
                        menu_i = 0
                        for title_no in range( menu_start_title , menu_end_title ):
                                menu_end_title = nr_titles+1
                        menu_i = 0
                        for title_no in range( menu_start_title , menu_end_title ):
-                               i = title_no-1
-                               top = s_top + ( menu_i * rowheight )
                                menu_i += 1
                                menu_i += 1
-                               title = self.job.project.titles[i]
-                               titleText = formatTitle(s.titleformat.getValue(), title, title_no)
+                               title = self.job.project.titles[title_no-1]
+                               top = s_top + ( menu_i * rowheight )
+                               titleText = title.formatDVDmenuText(s.titleformat.getValue(), title_no).decode("utf-8")
                                draw_bg.text((s_left,top), titleText, fill=self.Menus.color_button, font=fonts[1])
                                draw_high.text((s_left,top), titleText, fill=1, font=self.Menus.fonts[1])
                                draw_bg.text((s_left,top), titleText, fill=self.Menus.color_button, font=fonts[1])
                                draw_high.text((s_left,top), titleText, fill=1, font=self.Menus.fonts[1])
-                               subtitleText = formatTitle(s.subtitleformat.getValue(), title, title_no)
+                               subtitleText = title.formatDVDmenuText(s.subtitleformat.getValue(), title_no).decode("utf-8")
                                draw_bg.text((s_left,top+36), subtitleText, fill=self.Menus.color_button, font=fonts[2])
                                bottom = top+rowheight
                                if bottom > self.Menus.imgheight:
                                draw_bg.text((s_left,top+36), subtitleText, fill=self.Menus.color_button, font=fonts[2])
                                bottom = top+rowheight
                                if bottom > self.Menus.imgheight:
@@ -607,7 +599,7 @@ class Menus:
                        menuoutputfilename = job.workspace+"/dvdmenu"+num+".mpg"
                        spumuxTask(job, spuxmlfilename, menubgmpgfilename, menuoutputfilename)
                
                        menuoutputfilename = job.workspace+"/dvdmenu"+num+".mpg"
                        spumuxTask(job, spuxmlfilename, menubgmpgfilename, menuoutputfilename)
                
-def CreateAuthoringXML(job):
+def CreateAuthoringXML_simple(job):
        nr_titles = len(job.project.titles)
        mode = job.project.settings.authormode.getValue()
        authorxml = []
        nr_titles = len(job.project.titles)
        mode = job.project.settings.authormode.getValue()
        authorxml = []
@@ -649,9 +641,7 @@ def CreateAuthoringXML(job):
                authorxml.append('   </menus>\n')
        authorxml.append('   <titles>\n')
        for i in range( nr_titles ):
                authorxml.append('   </menus>\n')
        authorxml.append('   <titles>\n')
        for i in range( nr_titles ):
-               #for audiotrack in job.project.titles[i].audiotracks:
-                       #authorxml.append('    <audio lang="'+audiotrack[0][:2]+'" format="'+audiotrack[1]+'" />\n')
-               chapters = ','.join(["%d:%02d:%02d.%03d" % (p / (90000 * 3600), p % (90000 * 3600) / (90000 * 60), p % (90000 * 60) / 90000, (p % 90000) / 90) for p in job.project.titles[i].chaptermarks])
+               chapters = ','.join(job.project.titles[i].getChapterMarks())
                title_no = i+1
                title_filename = job.workspace + "/dvd_title_%d.mpg" % (title_no)
                if job.menupreview:
                title_no = i+1
                title_filename = job.workspace + "/dvd_title_%d.mpg" % (title_no)
                if job.menupreview:
@@ -677,6 +667,84 @@ def CreateAuthoringXML(job):
                f.write(x)
        f.close()
 
                f.write(x)
        f.close()
 
+def CreateAuthoringXML_multiset(job):
+       nr_titles = len(job.project.titles)
+       mode = job.project.settings.authormode.getValue()
+       authorxml = []
+       authorxml.append('<?xml version="1.0" encoding="utf-8"?>\n')
+       authorxml.append(' <dvdauthor dest="' + (job.workspace+"/dvd") + '" jumppad="yes">\n')
+       authorxml.append('  <vmgm>\n')
+       authorxml.append('   <menus>\n')
+       authorxml.append('    <video aspect="4:3"/>\n')
+       if mode.startswith("menu"):
+               for menu_count in range(1 , job.nr_menus+1):
+                       authorxml.append('    <pgc>\n')
+                       menu_start_title = (menu_count-1)*job.titles_per_menu + 1
+                       menu_end_title = (menu_count)*job.titles_per_menu + 1
+                       if menu_end_title > nr_titles:
+                               menu_end_title = nr_titles+1
+                       for i in range( menu_start_title , menu_end_title ):
+                               authorxml.append('     <button name="button' + (str(i).zfill(2)) + '"> jump titleset ' + str(i) +' title 1; </button>\n')
+                       if menu_count > 1:
+                               authorxml.append('     <button name="button_prev"> jump menu ' + str(menu_count-1) + '; </button>\n')
+                       if menu_count < job.nr_menus:
+                               authorxml.append('     <button name="button_next"> jump menu ' + str(menu_count+1) + '; </button>\n')
+                       menuoutputfilename = job.workspace+"/dvdmenu"+str(menu_count)+".mpg"
+                       authorxml.append('     <vob file="' + menuoutputfilename + '" pause="inf"/>\n')
+                       authorxml.append('    </pgc>\n')
+       else:
+               authorxml.append('    <pgc>\n')
+               authorxml.append('     <vob file="' + job.project.settings.vmgm.getValue() + '" />\n' )
+               authorxml.append('     <post> jump titleset 1 title 1; </post>\n')
+               authorxml.append('    </pgc>\n')
+       authorxml.append('   </menus>\n')
+       authorxml.append('  </vmgm>\n')
+
+       for i in range( nr_titles ):
+               title = job.project.titles[i]
+               authorxml.append('  <titleset>\n')
+               authorxml.append('   <titles>\n')
+               for audiotrack in title.properties.audiotracks:
+                       active = audiotrack.active.getValue()
+                       if active:
+                               format = audiotrack.format.getValue()
+                               language = audiotrack.language.getValue()
+                               audio_tag = '    <audio format="%s"' % format
+                               if language != "nolang":
+                                       audio_tag += ' lang="%s"' % language
+                               audio_tag += ' />\n'
+                               authorxml.append(audio_tag)
+               aspect = title.properties.aspect.getValue()
+               video_tag = '    <video aspect="'+aspect+'"'
+               if title.properties.widescreen.getValue() == "4:3":
+                       video_tag += ' widescreen="'+title.properties.widescreen.getValue()+'"'
+               video_tag += ' />\n'
+               authorxml.append(video_tag)
+               chapters = ','.join(title.getChapterMarks())
+               title_no = i+1
+               title_filename = job.workspace + "/dvd_title_%d.mpg" % (title_no)
+               if job.menupreview:
+                       LinkTS(job, job.project.settings.vmgm.getValue(), title_filename)
+               else:
+                       MakeFifoNode(job, title_no)
+               if mode.endswith("linked") and title_no < nr_titles:
+                       post_tag = "jump titleset %d title 1;" % ( title_no+1 )
+               elif mode.startswith("menu"):
+                       post_tag = "call vmgm menu 1;"
+               else:   post_tag = ""
+
+               authorxml.append('    <pgc>\n')
+               authorxml.append('     <vob file="' + title_filename + '" chapters="' + chapters + '" />\n')
+               authorxml.append('     <post> ' + post_tag + ' </post>\n')
+               authorxml.append('    </pgc>\n')
+               authorxml.append('   </titles>\n')
+               authorxml.append('  </titleset>\n')
+       authorxml.append(' </dvdauthor>\n')
+       f = open(job.workspace+"/dvdauthor.xml", "w")
+       for x in authorxml:
+               f.write(x)
+       f.close()
+
 def getISOfilename(isopath, volName):
        from Tools.Directories import fileExists
        i = 0
 def getISOfilename(isopath, volName):
        from Tools.Directories import fileExists
        i = 0
@@ -703,7 +771,7 @@ class DVDJob(Job):
                CheckDiskspaceTask(self)
                if self.project.settings.authormode.getValue().startswith("menu") or self.menupreview:
                        Menus(self)
                CheckDiskspaceTask(self)
                if self.project.settings.authormode.getValue().startswith("menu") or self.menupreview:
                        Menus(self)
-               CreateAuthoringXML(self)
+               CreateAuthoringXML_multiset(self)
 
                DVDAuthorTask(self)
                
 
                DVDAuthorTask(self)
                
@@ -713,14 +781,14 @@ class DVDJob(Job):
                        PreviewTask(self, self.workspace + "/dvd/VIDEO_TS/")
                else:
                        for self.i in range(nr_titles):
                        PreviewTask(self, self.workspace + "/dvd/VIDEO_TS/")
                else:
                        for self.i in range(nr_titles):
-                               title = self.project.titles[self.i]
+                               self.title = self.project.titles[self.i]
                                link_name =  self.workspace + "/source_title_%d.ts" % (self.i+1)
                                title_filename = self.workspace + "/dvd_title_%d.mpg" % (self.i+1)
                                link_name =  self.workspace + "/source_title_%d.ts" % (self.i+1)
                                title_filename = self.workspace + "/dvd_title_%d.mpg" % (self.i+1)
-                               LinkTS(self, title.inputfile, link_name)
+                               LinkTS(self, self.title.inputfile, link_name)
                                demux = DemuxTask(self, link_name)
                                self.mplextask = MplexTask(self, outputfile=title_filename, demux_task=demux)
                                self.mplextask.end = self.estimateddvdsize
                                demux = DemuxTask(self, link_name)
                                self.mplextask = MplexTask(self, outputfile=title_filename, demux_task=demux)
                                self.mplextask.end = self.estimateddvdsize
-                               RemoveESFiles(self, demux)
+                               #RemoveESFiles(self, demux)
                        WaitForResidentTasks(self)
                        PreviewTask(self, self.workspace + "/dvd/VIDEO_TS/")
                        output = self.project.settings.output.getValue()
                        WaitForResidentTasks(self)
                        PreviewTask(self, self.workspace + "/dvd/VIDEO_TS/")
                        output = self.project.settings.output.getValue()
index 163269c74ff05bbe9757ba439c8784398849d0fc..be5ad245a410ccf5f35905b73ee84f7c58813819 100644 (file)
@@ -20,16 +20,31 @@ class TitleCutter(CutListEditor):
                audio = service and service.audioTracks()
                n = audio and audio.getNumberOfTracks() or 0
                if n > 0:
                audio = service and service.audioTracks()
                n = audio and audio.getNumberOfTracks() or 0
                if n > 0:
+                       from DVDTitle import ConfigFixedText, ConfigActiveTrack
+                       from TitleProperties import languageChoices
+                       from Components.config import config, ConfigSubsection, ConfigSelection
                        for x in range(n):
                                i = audio.getTrackInfo(x)
                                language = i.getLanguage()
                                description = i.getDescription()
                        for x in range(n):
                                i = audio.getTrackInfo(x)
                                language = i.getLanguage()
                                description = i.getDescription()
+                               pid = str(i.getPID())
                                if description == "MPEG":
                                        description = "MP2"
                                if description == "MPEG":
                                        description = "MP2"
-                               self.t.audiotracks.append((language, description))
-               print "[DVDBurn getAudioTracks]", self.t.audiotracks
-               self.t.sVideoType = service.info().getInfo(iServiceInformation.sVideoType)
-               print "[DVDBurn getVideoType]", self.t.sVideoType
+                               if not languageChoices.langdict.has_key(language):
+                                       language="nolang"
+                               print "[audiotrack] pid:", pid, "description:", description, "language:", language
+                               self.t.properties.audiotracks.append(ConfigSubsection())
+                               self.t.properties.audiotracks[-1].active = ConfigActiveTrack()
+                               self.t.properties.audiotracks[-1].format = ConfigFixedText(description)
+                               self.t.properties.audiotracks[-1].language = ConfigSelection(choices = languageChoices.choices, default=language)
+                               self.t.properties.audiotracks[-1].pid = ConfigFixedText(pid)
+               sAspect = service.info().getInfo(iServiceInformation.sAspect)
+               if sAspect in ( 1, 2, 5, 6, 9, 0xA, 0xD, 0xE ):
+                       aspect = "4:3"
+               else:
+                       aspect = "16:9"
+               self.t.properties.aspect.setValue(aspect)
+               self.t.VideoType = service.info().getInfo(iServiceInformation.sVideoType)
 
        def exit(self):
                self.session.nav.stopService()
 
        def exit(self):
                self.session.nav.stopService()
index 19380af48793b1fcb257281ffbf5c6fb489b49b8..caec6198d82ab6e07c32d3a733bbb73ffb5375d9 100644 (file)
@@ -1,4 +1,4 @@
-import DVDProject, TitleList, TitleCutter, ProjectSettings, DVDToolbox, Process
+import DVDProject, TitleList, TitleCutter, TitleProperties, ProjectSettings, DVDToolbox, Process
 from Screens.Screen import Screen
 from Screens.ChoiceBox import ChoiceBox
 from Screens.InputBox import InputBox
 from Screens.Screen import Screen
 from Screens.ChoiceBox import ChoiceBox
 from Screens.InputBox import InputBox
@@ -41,7 +41,7 @@ class TitleList(Screen, HelpableScreen):
                self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
                        {
                                "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
                self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
                        {
                                "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
-                               "editTitle": (self.editTitle, _("Edit chapters of current title"), _("Edit title")),
+                               "titleProperties": (self.titleProperties, ("Properties of current title"), _("Title properties")),
                                "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
                                "settings": (self.settings, _("Collection settings"), _("Settings")),
                                "burnProject": (self.burnProject, _("Burn DVD"), _("Burn DVD")),
                                "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
                                "settings": (self.settings, _("Collection settings"), _("Settings")),
                                "burnProject": (self.burnProject, _("Burn DVD"), _("Burn DVD")),
@@ -59,7 +59,7 @@ class TitleList(Screen, HelpableScreen):
 
                self["key_red"] = StaticText(_("Remove title"))
                self["key_green"] = StaticText(_("Add title"))
 
                self["key_red"] = StaticText(_("Remove title"))
                self["key_green"] = StaticText(_("Add title"))
-               self["key_yellow"] = StaticText(_("Edit title"))
+               self["key_yellow"] = StaticText(_("Title properties"))
                self["key_blue"] = StaticText(_("Settings"))
 
                self["title_label"] = StaticText()
                self["key_blue"] = StaticText(_("Settings"))
 
                self["title_label"] = StaticText()
@@ -78,40 +78,31 @@ class TitleList(Screen, HelpableScreen):
        def showMenu(self):
                menu = []
                if self.project.settings.output.getValue() == "dvd":
        def showMenu(self):
                menu = []
                if self.project.settings.output.getValue() == "dvd":
-                       menu.append((_("Burn DVD"), "burn"));
+                       menu.append((_("Burn DVD"), self.burnProject))
                elif self.project.settings.output.getValue() == "iso":
                elif self.project.settings.output.getValue() == "iso":
-                       menu.append((_("Create DVD-ISO"), "burn"));
-               menu.append((_("Preview menu"), "previewMenu"));
-               menu.append((_("DVD media toolbox"), "toolbox"));
-               menu.append((_("Collection settings"), "settings"));
-               menu.append((_("Add a new title"), "addtitle"));
-               menu.append((_("Remove title"), "removetitle"));
-               menu.append((_("Edit chapters of current title"), "edittitle"));
-               menu.append((_("Burn existing image to DVD"), "burniso"));
-               menu.append((_("Exit"), "exit"));
+                       menu.append((_("Create DVD-ISO"), self.burnProject))
+               menu.append((_("Burn existing image to DVD"), self.selectImage))
+               menu.append((_("DVD media toolbox"), self.toolbox))
+               menu.append((_("Preview menu"), self.previewMenu))
+               menu.append((_("Collection settings"), self.settings))
+               menu.append(("Reset and renumerate title names", self.resetTitles))
+               menu.append((_("Edit chapters of current title"), self.editTitle))
+               menu.append(("Properties of current title", self.titleProperties))
+               menu.append((_("Add a new title"), self.addTitle))
+               menu.append((_("Remove title"), self.removeCurrentTitle))
+               menu.append((_("Exit"), self.leave))
                self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
 
        def menuCallback(self, choice):
                self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
 
        def menuCallback(self, choice):
-               if choice is None:
-                       return
-               if choice[1] == "removetitle":
-                       self.removeCurrentTitle()
-               elif choice[1] == "addtitle":
-                       self.addTitle()
-               elif choice[1] == "edittitle":
-                       self.editTitle()
-               elif choice[1] == "toolbox":
-                       self.toolbox()
-               elif choice[1] == "settings":
-                       self.settings()
-               elif choice[1] == "previewMenu":
-                       self.previewMenu()
-               elif choice[1] == "burn":
-                       self.burnProject()
-               elif choice[1] == "burniso":
-                       self.session.openWithCallback(self.burnISO, ProjectSettings.FileBrowser, "image", self.project.settings)
-               elif choice[1] == "exit":
-                       self.leave()
+               if choice:
+                       choice[1]()
+
+       def titleProperties(self):
+               if self.getCurrentTitle():
+                       self.session.openWithCallback(self.updateTitleList, TitleProperties.TitleProperties, self, self.project, self["titles"].getIndex())
+
+       def selectImage(self):
+               self.session.openWithCallback(self.burnISO, ProjectSettings.FileBrowser, "image", self.project.settings)
 
        def newProject(self):
                self.project = DVDProject.DVDProject()
 
        def newProject(self):
                self.project = DVDProject.DVDProject()
@@ -225,7 +216,7 @@ class TitleList(Screen, HelpableScreen):
                res = [ ]
                totalsize = 0
                for title in self.project.titles:
                res = [ ]
                totalsize = 0
                for title in self.project.titles:
-                       a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 10, 500, 50, 0, RT_HALIGN_LEFT, title.name)  ]
+                       a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 10, 500, 50, 0, RT_HALIGN_LEFT, title.properties.menutitle.getValue())  ]
                        res.append(a)
                        totalsize += title.estimatedDiskspace
                self["titles"].list = res
                        res.append(a)
                        totalsize += title.estimatedDiskspace
                self["titles"].list = res
@@ -263,13 +254,21 @@ class TitleList(Screen, HelpableScreen):
 
        def titleEditDone(self, cutlist):
                t = self.current_edit_title
 
        def titleEditDone(self, cutlist):
                t = self.current_edit_title
+               t.initDVDmenuText(self.project,len(self.project.titles))
                t.cuesheet = cutlist
                t.produceFinalCuesheet()
                t.cuesheet = cutlist
                t.produceFinalCuesheet()
-               if t.sVideoType != 0:
+               if t.VideoType != 0:
                        self.session.openWithCallback(self.DVDformatCB,MessageBox,text = _("The DVD standard doesn't support H.264 (HDTV) video streams. Do you want to create a Dreambox format data DVD (which will not play in stand-alone DVD players) instead?"), type = MessageBox.TYPE_YESNO)
                else:
                        self.updateTitleList()
 
                        self.session.openWithCallback(self.DVDformatCB,MessageBox,text = _("The DVD standard doesn't support H.264 (HDTV) video streams. Do you want to create a Dreambox format data DVD (which will not play in stand-alone DVD players) instead?"), type = MessageBox.TYPE_YESNO)
                else:
                        self.updateTitleList()
 
+       def resetTitles(self):
+               count = 0
+               for title in self.project.titles:
+                       count += 1
+                       title.initDVDmenuText(self.project,count)
+               self.updateTitleList()
+
        def DVDformatCB(self, answer):
                t = self.current_edit_title
                if answer == True:
        def DVDformatCB(self, answer):
                t = self.current_edit_title
                if answer == True:
diff --git a/lib/python/Plugins/Extensions/DVDBurn/TitleProperties.py b/lib/python/Plugins/Extensions/DVDBurn/TitleProperties.py
new file mode 100644 (file)
index 0000000..72071a5
--- /dev/null
@@ -0,0 +1,152 @@
+from Screens.Screen import Screen
+from Screens.ChoiceBox import ChoiceBox
+from Screens.InputBox import InputBox
+from Screens.MessageBox import MessageBox
+from Screens.HelpMenu import HelpableScreen
+from Components.ActionMap import HelpableActionMap, ActionMap
+from Components.Sources.List import List
+from Components.Sources.StaticText import StaticText
+from Components.Sources.Progress import Progress
+from Components.FileList import FileList
+from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT
+from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_FONTS, SCOPE_HDD
+from Components.config import config, getConfigListEntry, ConfigInteger, ConfigSubsection, ConfigSelection
+from Components.ConfigList import ConfigListScreen
+import DVDTitle
+
+class TitleProperties(Screen,ConfigListScreen):
+       skin = """
+               <screen position="90,83" size="560,445" title="Title properties" >
+                   <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
+                   <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
+                   <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
+                   <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
+                   <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
+                   <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
+                   <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
+                   <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
+                   <widget name="config" position="10,50" size="540,276" scrollbarMode="showOnDemand" />
+                   <widget source="serviceinfo_headline" render="Label" position="20,350" size="520,20" font="Regular;20" />
+                   <widget source="serviceinfo" render="Label" position="20,374" size="520,66" font="Regular;16" />
+               </screen>"""
+
+       def __init__(self, session, parent, project, title_idx):
+               Screen.__init__(self, session)
+               self.parent = parent
+               self.project = project
+               self.title_idx = title_idx
+
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("OK"))
+               self["key_yellow"] = StaticText(_("Edit Title"))
+               self["key_blue"] = StaticText(_("Save"))
+               self["serviceinfo_headline"] = StaticText("DVB info:")
+               self["serviceinfo"] = StaticText()
+
+               self.properties = project.titles[title_idx].properties
+               ConfigListScreen.__init__(self, [])
+               self.properties.crop = DVDTitle.ConfigFixedText("crop")
+               self.initConfigList()
+                       
+               self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
+               {
+                   "green": self.exit,
+                   "red": self.cancel,
+                   #"blue": self.saveProject,
+                   "yellow": self.editTitle,
+                   "cancel": self.cancel,
+                   "ok": self.ok,
+               }, -2)
+
+       def initConfigList(self):
+               self.properties.position = ConfigInteger(default = self.title_idx+1, limits = (1, len(self.project.titles)))
+               title = self.project.titles[self.title_idx]
+               self.list = []
+               self.list.append(getConfigListEntry("DVD " + _("Track"), self.properties.position))
+               self.list.append(getConfigListEntry("DVD " + _("Title"), self.properties.menutitle))
+               self.list.append(getConfigListEntry("DVD " + _("Description"), self.properties.menusubtitle))
+               for audiotrack in self.properties.audiotracks:
+                       pid = audiotrack.pid.getValue()
+                       self.list.append(getConfigListEntry("burn audio track (%s)" % pid, audiotrack.active))
+                       if audiotrack.active.getValue():
+                               self.list.append(getConfigListEntry("audio track (%s) format" % pid, audiotrack.format))
+                               self.list.append(getConfigListEntry("audio track (%s) language" % pid, audiotrack.language))
+                               
+               self.list.append(getConfigListEntry("DVD " + _("Aspect Ratio"), self.properties.aspect))
+               if self.properties.aspect.getValue() == "16:9":
+                       self.list.append(getConfigListEntry("DVD " + "widescreen", self.properties.widescreen))
+               else:
+                       self.list.append(getConfigListEntry("DVD " + "widescreen", self.properties.crop))
+               
+               self["config"].setList(self.list)
+               
+               infotext = _("Available format variables") + ":\n$i=" + _("Track") + ", $t=" + _("Title") + ", $d=" + _("Description") + ", $l=" + _("length") + ", $c=" + _("chapters") + ",\n" + _("Record") + " $T=" + _("Begin time") + ", $Y=" + _("year") + ", $M=" + _("month") + ", $D=" + _("day") + ",\n$A=" + _("audio tracks") + ", $C=" + _("Channel") + ", $f=" + _("filename")
+               self["info"] = StaticText(infotext)
+               
+               chapters_count = len(title.chaptermarks)
+               infotext = _("Title") + ': ' + title.DVBname + "\n" + _("Description") + ': ' + title.DVBdescr + "\n" + _("Channel") + ': ' + title.DVBchannel
+               if chapters_count:
+                       infotext += ', ' + str(chapters_count+1) + ' ' + _("chapters") + ' ('
+                       infotext += ' / '.join(title.getChapterMarks()) + ')'
+               self["serviceinfo"].setText(infotext)
+
+       def editTitle(self):
+               self.parent.editTitle()
+               self.initConfigList()
+
+       def changedConfigList(self):
+               self.initConfigList()
+       
+       def keyLeft(self):
+               ConfigListScreen.keyLeft(self)
+               if type(self["config"].getCurrent()[1]) in [DVDTitle.ConfigActiveTrack, ConfigSelection]:
+                       self.initConfigList()
+
+       def keyRight(self):
+               ConfigListScreen.keyRight(self)
+               if type(self["config"].getCurrent()[1]) in [DVDTitle.ConfigActiveTrack, ConfigSelection]:
+                       self.initConfigList()
+
+       def exit(self):
+               self.applySettings()
+               self.close()
+
+       def applySettings(self):
+               for x in self["config"].list:
+                       x[1].save()
+               current_pos = self.title_idx+1
+               new_pos = self.properties.position.getValue()
+               if new_pos != current_pos:
+                       print "title got repositioned from ", current_pos, "to", new_pos
+                       swaptitle = self.project.titles.pop(current_pos-1)
+                       self.project.titles.insert(new_pos-1, swaptitle)
+
+       def ok(self):
+               #key = self.keydict[self["config"].getCurrent()[1]]
+               #if key in self.project.filekeys:
+                       #self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, key, self.settings)
+               pass
+
+       def cancel(self):
+               self.close()
+
+class LanguageChoices():
+       def __init__(self):
+               from Tools.ISO639 import LanguageCodes
+               from Components.Language import language as syslanguage
+               syslang = syslanguage.getLanguage()[:2]
+               self.langdict = { }
+               self.choices = []
+               for key, val in LanguageCodes.iteritems():
+                       if len(key) == 2:
+                               self.langdict[key] = val[0]
+               for key, val in self.langdict.iteritems():
+                       if key not in [syslang, 'en']:
+                               self.langdict[key] = val
+                               self.choices.append((key, val))
+               self.choices.sort()
+               self.choices.insert(0,("nolang", ("unspecified")))
+               self.choices.insert(1,(syslang, self.langdict[syslang]))
+               self.choices.insert(2,("en", self.langdict["en"]))
+
+languageChoices = LanguageChoices()
\ No newline at end of file
index 13fa3ee0bf1335261fd9e0609c08994a2689ed16..e8bc10452279f9b2e827bc12aedc7faad1721316 100644 (file)
@@ -2,7 +2,7 @@
        <map context="DVDTitleList">
                <key id="KEY_RED" mapto="removeCurrentTitle" flags="m" />
                <key id="KEY_GREEN" mapto="addTitle" flags="m" />
        <map context="DVDTitleList">
                <key id="KEY_RED" mapto="removeCurrentTitle" flags="m" />
                <key id="KEY_GREEN" mapto="addTitle" flags="m" />
-               <key id="KEY_YELLOW" mapto="editTitle" flags="m" />
+               <key id="KEY_YELLOW" mapto="titleProperties" flags="m" />
                <key id="KEY_BLUE" mapto="settings" flags="m" />
                <key id="KEY_RECORD" mapto="burnProject" flags="m" />
                <key id="KEY_0" mapto="burnProject" flags="m" />
                <key id="KEY_BLUE" mapto="settings" flags="m" />
                <key id="KEY_RECORD" mapto="burnProject" flags="m" />
                <key id="KEY_0" mapto="burnProject" flags="m" />