add DVDPlayer plugin (not final yet)
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 15 Apr 2008 12:47:41 +0000 (12:47 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 15 Apr 2008 12:47:41 +0000 (12:47 +0000)
not working without libdreamdvd (not in OE yet)

12 files changed:
configure.ac
lib/python/Plugins/Extensions/DVDPlayer/.cvsignore [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/LICENSE [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/Makefile.am [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/__init__.py [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/keymap.xml [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/plugin.py [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/src/.cvsignore [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/src/Makefile.am [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.cpp [new file with mode: 0644]
lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.h [new file with mode: 0644]
lib/python/Plugins/Extensions/Makefile.am

index 20b9736..b429a17 100644 (file)
@@ -114,6 +114,9 @@ lib/python/Plugins/Extensions/FileManager/Makefile
 lib/python/Plugins/Extensions/CutListEditor/Makefile
 lib/python/Plugins/Extensions/MediaScanner/Makefile
 lib/python/Plugins/Extensions/MediaPlayer/Makefile
+lib/python/Plugins/Extensions/DVDPlayer/Makefile
+lib/python/Plugins/Extensions/DVDPlayer/src/Makefile
+lib/python/Plugins/Extensions/DVDPlayer/data/Makefile
 lib/python/Plugins/Extensions/PicturePlayer/Makefile
 lib/python/Plugins/Extensions/PicturePlayer/data/Makefile
 lib/python/Plugins/Extensions/GraphMultiEPG/Makefile
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/.cvsignore b/lib/python/Plugins/Extensions/DVDPlayer/.cvsignore
new file mode 100644 (file)
index 0000000..138b9cc
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+Makefile
+Makefile.in
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/LICENSE b/lib/python/Plugins/Extensions/DVDPlayer/LICENSE
new file mode 100644 (file)
index 0000000..9970059
--- /dev/null
@@ -0,0 +1,12 @@
+This plugin is licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Alternatively, this plugin may be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/Makefile.am b/lib/python/Plugins/Extensions/DVDPlayer/Makefile.am
new file mode 100644 (file)
index 0000000..ed47415
--- /dev/null
@@ -0,0 +1,9 @@
+SUBDIRS = src
+
+installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/DVDPlayer
+
+install_PYTHON = \
+       __init__.py \
+       plugin.py \
+       keymap.xml \
+       LICENSE
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/__init__.py b/lib/python/Plugins/Extensions/DVDPlayer/__init__.py
new file mode 100644 (file)
index 0000000..8d1c8b6
--- /dev/null
@@ -0,0 +1 @@
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/keymap.xml b/lib/python/Plugins/Extensions/DVDPlayer/keymap.xml
new file mode 100644 (file)
index 0000000..b8b4994
--- /dev/null
@@ -0,0 +1,36 @@
+<keymap>
+       <map context="DVDPlayerActions">
+               <key id="KEY_MENU" mapto="dvdMenu" flags="m" />
+               <key id="KEY_INFO" mapto="toggleInfo" flags="m" />
+               <device name="dreambox remote control (native)">
+                       <key id="KEY_PREVIOUS" mapto="prevChapter" flags="m" />
+                       <key id="KEY_NEXT" mapto="nextChapter" flags="m" />
+                       <key id="KEY_TV" mapto="tv" flags="m" />
+                       <key id="KEY_AUDIO" mapto="dvdAudioMenu" flags="m" />
+                       <key id="KEY_RADIO" mapto="nextAudioTrack" flags="m" />
+                       <key id="KEY_TEXT" mapto="nextSubtitleTrack" flags="m" />
+                       <key id="KEY_CHANNELUP" mapto="nextTitle" flags="m" />
+                       <key id="KEY_CHANNELDOWN" mapto="prevTitle" flags="m" />
+                       <key id="KEY_VIDEO" mapto="seekBeginning" flags="l" />
+               </device>
+               <!--device name="dreambox advanced remote control (native)">
+                       <key id="KEY_PLAYPAUSE" mapto="pause" flags="m" />
+                       <key id="KEY_STOP" mapto="stop" flags="b" />
+                       <key id="KEY_STOP" mapto="shift_stop" flags="l" />
+                       <key id="KEY_RECORD" mapto="shift_record" flags="l" />
+                       <key id="KEY_PREVIOUS" mapto="previous" flags="m" />
+                       <key id="KEY_NEXT" mapto="next" flags="m" />
+                       <key id="KEY_RED" mapto="previous" flags="m" />
+                       <key id="KEY_BLUE" mapto="next" flags="m" />
+               </device>
+               <device name="dreambox ir keyboard">
+                       <key id="KEY_PAUSE" mapto="pause" flags="m" />
+                       <key id="KEY_PLAY" mapto="play" flags="m" />
+                       <key id="KEY_STOP" mapto="stop" flags="b" />
+                       <key id="KEY_STOP" mapto="shift_stop" flags="l" />
+                       <key id="KEY_RECORD" mapto="shift_record" flags="l" />
+                       <key id="KEY_PREVIOUSSONG" mapto="previous" flags="m" />
+                       <key id="KEY_NEXTSONG" mapto="next" flags="m" />
+               </device-->
+       </map>
+</keymap>
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/plugin.py b/lib/python/Plugins/Extensions/DVDPlayer/plugin.py
new file mode 100644 (file)
index 0000000..856c7d1
--- /dev/null
@@ -0,0 +1,535 @@
+from os import path as os_path, remove as os_remove, listdir as os_listdir, system
+from time import strftime
+from enigma import eTimer, iPlayableService, eServiceCenter, iServiceInformation, eServiceReference, iServiceKeys
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.InputBox import InputBox
+from Screens.HelpMenu import HelpableScreen
+from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications
+from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
+from Components.Label import Label
+from Components.FileList import FileList
+from Components.ServiceEventTracker import ServiceEventTracker
+from Components.config import config
+from Components.ProgressBar import ProgressBar
+from ServiceReference import ServiceReference
+from Tools.Directories import pathExists, fileExists
+
+import random
+import servicedvd # load c++ part of dvd player plugin
+
+class FileBrowser(Screen):
+       skin = """
+       <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
+               <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
+       </screen>"""
+       def __init__(self, session):
+               Screen.__init__(self, session)
+               currDir = "/media/dvd/"
+               if not pathExists(currDir):
+                       currDir = "/"
+               #else:
+                       #print system("mount "+currDir)
+               self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
+               self["filelist"] = self.filelist
+
+               self["FilelistActions"] = ActionMap(["OkCancelActions"],
+                       {
+                               "ok": self.ok,
+                               "cancel": self.exit
+                       })
+
+       def ok(self):
+               if self["filelist"].getFilename().upper().endswith("VIDEO_TS/"):
+                       print "dvd structure found, trying to open..."
+                       self.close(self["filelist"].getFilename()[0:-9])
+               
+               elif self["filelist"].canDescent(): # isDir
+                       self["filelist"].descent()
+                       
+               else:
+                       self.close(self["filelist"].getFilename())
+                       
+       def exit(self):
+               self.close(None)
+               
+class DVDSummary(Screen):
+       skin = """
+       <screen position="0,0" size="132,64">
+               <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
+                       <convert type="ServiceName">Name</convert>
+               </widget>
+               <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
+               <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
+               <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
+                       <convert type="ServicePosition">Position</convert>
+               </widget>
+               <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
+                       <convert type="ServicePosition">Position</convert>
+               </widget>
+       </screen>"""
+
+       def __init__(self, session, parent):
+               Screen.__init__(self, session, parent)
+
+               self["DVDPlayer"] = Label("DVD Player")
+               self["Title"] = Label("")
+               self["Time"] = Label("")
+               self["Chapter"] = Label("")
+
+       def updateChapter(self, chapter):
+               self["Chapter"].setText(chapter)
+
+       def setTitle(self, title):
+               self["Title"].setText(title)
+
+class DVDOverlay(Screen):
+       skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
+       def __init__(self, session, args = None):
+               Screen.__init__(self, session)
+               
+class ChapterZap(Screen):
+       skin = """
+       <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
+               <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
+               <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
+       </screen>"""
+       
+       def quit(self):
+               self.Timer.stop()
+               self.close(0)
+
+       def keyOK(self):
+               self.Timer.stop()
+               self.close(int(self["number"].getText()))
+
+       def keyNumberGlobal(self, number):
+               self.Timer.start(3000, True)            #reset timer
+               self.field = self.field + str(number)
+               self["number"].setText(self.field)
+               if len(self.field) >= 4:
+                       self.keyOK()
+
+       def __init__(self, session, number):
+               Screen.__init__(self, session)
+               self.field = str(number)
+
+               self["chapter"] = Label(_("Chapter:"))
+
+               self["number"] = Label(self.field)
+
+               self["actions"] = NumberActionMap( [ "SetupActions" ],
+                       {
+                               "cancel": self.quit,
+                               "ok": self.keyOK,
+                               "1": self.keyNumberGlobal,
+                               "2": self.keyNumberGlobal,
+                               "3": self.keyNumberGlobal,
+                               "4": self.keyNumberGlobal,
+                               "5": self.keyNumberGlobal,
+                               "6": self.keyNumberGlobal,
+                               "7": self.keyNumberGlobal,
+                               "8": self.keyNumberGlobal,
+                               "9": self.keyNumberGlobal,
+                               "0": self.keyNumberGlobal
+                       })
+
+               self.Timer = eTimer()
+               self.Timer.callback.append(self.keyOK)
+               self.Timer.start(3000, True)
+
+class DVDPlayer(Screen, InfoBarNotifications, InfoBarSeek, InfoBarCueSheetSupport, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
+       ALLOW_SUSPEND = True
+       ENABLE_RESUME_SUPPORT = True
+       
+       skin = """
+       <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
+               <!-- Background -->
+               <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
+               <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
+               <!-- colorbuttons -->
+               <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
+               <!-- Servicename -->
+               <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
+               <widget source="session.CurrentService" render="Label" position="230,73" size="300,22" font="Regular;20" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" noWrap="1">
+                       <convert type="ServiceName">Name</convert>
+               </widget>
+               <!-- Chapter info -->
+               <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
+               <!-- Audio track info -->
+               <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
+               <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
+               <!-- Subtitle track info -->
+               <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
+                       <convert type="ServiceInfo">HasTelext</convert>
+                       <convert type="ConditionalShowHide" />
+               </widget>
+               <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
+               <!-- Elapsed time -->
+               <widget source="session.CurrentService" render="Label" position="205,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" >
+                       <convert type="ServicePosition">Position,ShowHours</convert>
+               </widget>
+               <!-- Progressbar (movie position)-->
+               <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
+                       <convert type="ServicePosition">Gauge</convert>
+               </widget>
+               <!-- Remaining time -->
+               <widget source="session.CurrentService" render="Label" position="576,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" >
+                       <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
+               </widget>
+       </screen>"""
+
+       def save_infobar_seek_config(self):
+               self.saved_config_speeds_forward = config.seek.speeds_forward.value
+               self.saved_config_speeds_backward = config.seek.speeds_backward.value
+               self.saved_config_enter_forward = config.seek.enter_forward.value
+               self.saved_config_enter_backward = config.seek.enter_backward.value
+               self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
+               self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
+               self.saved_config_seek_on_pause = config.seek.on_pause.value
+               self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
+
+       def change_infobar_seek_config(self):
+               config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
+               config.seek.speeds_backward.value = [8, 16, 32, 64]
+               config.seek.speeds_slowmotion.value = [ ]
+               config.seek.enter_forward.value = "2"
+               config.seek.enter_backward.value = "2"
+               config.seek.stepwise_minspeed.value = "Never"
+               config.seek.stepwise_repeat.value = "3"
+               config.seek.on_pause.value = "play"
+
+       def restore_infobar_seek_config(self):
+               config.seek.speeds_forward.value = self.saved_config_speeds_forward
+               config.seek.speeds_backward.value = self.saved_config_speeds_backward
+               config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
+               config.seek.enter_forward.value = self.saved_config_enter_forward
+               config.seek.enter_backward.value = self.saved_config_enter_backward
+               config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
+               config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
+               config.seek.on_pause.value = self.saved_config_seek_on_pause
+
+       def __init__(self, session, args = None):
+               Screen.__init__(self, session)
+               InfoBarNotifications.__init__(self)
+               InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
+               InfoBarShowHide.__init__(self)
+               HelpableScreen.__init__(self)
+               self.save_infobar_seek_config()
+               self.change_infobar_seek_config()
+               InfoBarSeek.__init__(self)
+               InfoBarPVRState.__init__(self)
+               self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
+
+               self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
+               self.session.nav.stopService()
+               self["audioLabel"] = Label("1")
+               self["subtitleLabel"] = Label("")
+               self["chapterLabel"] = Label("")
+               self.totalChapters = 0
+               self.currentChapter = 0
+               self.totalTitles = 0
+               self.currentTitle = 0
+
+               self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+                       {
+                               iPlayableService.evUser: self.__timeUpdated,
+                               iPlayableService.evUser+1: self.__statePlay,
+                               iPlayableService.evUser+2: self.__statePause,
+                               iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
+                               iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
+                               iPlayableService.evUser+5: self.__osdStringAvail,
+                               iPlayableService.evUser+6: self.__osdAudioInfoAvail,
+                               iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
+                               iPlayableService.evUser+8: self.__chapterUpdated,
+                               iPlayableService.evUser+9: self.__titleUpdated,
+                               #iPlayableService.evUser+10: self.__initializeDVDinfo,
+                               iPlayableService.evUser+11: self.__menuOpened,
+                               iPlayableService.evUser+12: self.__menuClosed
+                       })
+
+               self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
+                       {
+                               #MENU KEY DOWN ACTIONS
+                               "left": (self.keyLeft, _("DVD left key")),
+                               "right": (self.keyRight, _("DVD right key")),
+                               "up": (self.keyUp, _("DVD up key")),
+                               "down": (self.keyDown, _("DVD down key")),
+
+                               #MENU KEY REPEATED ACTIONS
+                               "leftRepeated": self.doNothing,
+                               "rightRepeated": self.doNothing,
+                               "upRepeated": self.doNothing,
+                               "downRepeated": self.doNothing,
+
+                               #MENU KEY UP ACTIONS
+                               "leftUp": self.doNothing,
+                               "rightUp": self.doNothing,
+                               "upUp": self.doNothing,
+                               "downUp": self.doNothing,
+                       }, -2)
+
+               self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
+                       {
+                               "ok": (self.keyOk, _("DVD ENTER key")),
+                               "cancel": self.keyCancel,
+                       }, -2)
+
+               self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
+                       {
+                               #PLAYER ACTIONS
+                               "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
+                               "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
+                               "nextChapter": (self.nextChapter, _("forward to the next chapter")),
+                               "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
+                               "nextTitle": (self.nextTitle, _("jump forward to the next title")),
+                               "prevTitle": (self.prevTitle, _("jump back to the previous title")),
+                               "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
+                               "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
+                               "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
+                               "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
+                               "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
+                       }, -2)
+                       
+               self["NumberActions"] = NumberActionMap( [ "NumberActions"],
+                       {
+                               "1": self.keyNumberGlobal,
+                               "2": self.keyNumberGlobal,
+                               "3": self.keyNumberGlobal,
+                               "4": self.keyNumberGlobal,
+                               "5": self.keyNumberGlobal,
+                               "6": self.keyNumberGlobal,
+                               "7": self.keyNumberGlobal,
+                               "8": self.keyNumberGlobal,
+                               "9": self.keyNumberGlobal,
+                               "0": self.keyNumberGlobal,
+                       })
+
+               self.onClose.append(self.__onClose)
+               self.onFirstExecBegin.append(self.showFileBrowser)
+               self.service = None
+               self.in_menu = False
+               
+       def keyNumberGlobal(self, number):
+               print "You pressed number " + str(number)
+               self.session.openWithCallback(self.numberEntered, ChapterZap, number)
+
+       def numberEntered(self, retval):
+#              print self.servicelist
+               if retval > 0:
+                       self.zapToNumber(retval)
+
+       def serviceStarted(self): #override InfoBarShowHide function
+               pass
+
+       def doEofInternal(self, playing):
+               if self.in_menu:
+                       self.hide()
+
+       def __menuOpened(self):
+               self.hide()
+               self.in_menu = True
+
+       def __menuClosed(self):
+               self.show()
+               self.in_menu = False
+
+       def setChapterLabel(self):
+               chapterLCD = "Menu"
+               chapterOSD = "DVD Menu"
+               if self.currentTitle > 0:
+                       chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
+                       chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
+                       chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
+               self["chapterLabel"].setText(chapterOSD)
+               try:
+                       self.session.summary.updateChapter(chapterLCD)
+               except:
+                       pass
+
+       def doNothing(self):
+               pass
+
+       def toggleInfo(self):
+               if not self.in_menu:
+                       self.toggleShow()
+                       print "toggleInfo"
+
+       def __timeUpdated(self):
+               print "timeUpdated"
+
+       def __statePlay(self):
+               print "statePlay"
+
+       def __statePause(self):
+               print "statePause"
+
+       def __osdFFwdInfoAvail(self):
+               self.setChapterLabel()
+               print "FFwdInfoAvail"
+
+       def __osdFBwdInfoAvail(self):
+               self.setChapterLabel()
+               print "FBwdInfoAvail"
+
+       def __osdStringAvail(self):
+               print "StringAvail"
+
+       def __osdAudioInfoAvail(self):
+               audioString = self.service.info().getInfoString(iPlayableService.evUser+6)
+               print "AudioInfoAvail "+audioString
+               self["audioLabel"].setText(audioString)
+               self.doShow()
+
+       def __osdSubtitleInfoAvail(self):
+               subtitleString = self.service.info().getInfoString(iPlayableService.evUser+7)
+               print "SubtitleInfoAvail "+subtitleString
+               self["subtitleLabel"].setText(subtitleString)
+               self.doShow()
+
+       def __chapterUpdated(self):
+               self.currentChapter = self.service.info().getInfo(iPlayableService.evUser+8)
+               self.totalChapters = self.service.info().getInfo(iPlayableService.evUser+80)
+               self.setChapterLabel()
+               print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
+
+       def __titleUpdated(self):
+               self.currentTitle = self.service.info().getInfo(iPlayableService.evUser+9)
+               self.totalTitles = self.service.info().getInfo(iPlayableService.evUser+90)
+               self.setChapterLabel()
+               print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
+               self.doShow()
+               
+       #def __initializeDVDinfo(self):
+               #self.__osdAudioInfoAvail()
+               #self.__osdSubtitleInfoAvail()
+
+       def askLeavePlayer(self):
+               self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Exit"), "exit"), (_("Return to file browser"), "browser"), (_("Continue playing"), "play")])
+
+       def nextAudioTrack(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser)
+
+       def nextSubtitleTrack(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+1)
+
+       def enterDVDAudioMenu(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+2)
+
+       def nextChapter(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+3)
+
+       def prevChapter(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+4)
+
+       def nextTitle(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+5)
+
+       def prevTitle(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+6)
+
+       def enterDVDMenu(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUser+7)
+                       
+       def seekBeginning(self):
+               if self.service:
+                       seekable = self.getSeek()
+                       if seekable is not None:
+                               seekable.seekTo(0)
+                               
+       def zapToNumber(self, number):
+               if self.service:
+                       seekable = self.getSeek()
+                       if seekable is not None:
+                               print "seek to chapter %d" % number
+                               seekable.seekChapter(number)
+
+#      MENU ACTIONS
+       def keyRight(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyRight)
+
+       def keyLeft(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyLeft)
+
+       def keyUp(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyUp)
+
+       def keyDown(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyDown)
+
+       def keyOk(self):
+               if self.service:
+                       self.service.keys().keyPressed(iServiceKeys.keyOk)
+
+       def keyCancel(self):
+               self.askLeavePlayer()
+
+       def showFileBrowser(self):
+               self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
+
+       def FileBrowserClosed(self, val):
+               curref = self.session.nav.getCurrentlyPlayingServiceReference()
+               print "FileBrowserClosed", val
+               if val is None:
+                       self.askLeavePlayer()
+               else:
+                       newref = eServiceReference(4369, 0, val)
+                       print "play", newref.toString()
+                       if curref is None or curref != newref:
+                               self.session.nav.playService(newref)
+                               self.service = self.session.nav.getCurrentService()
+                               print "self.service", self.service
+                               print "cur_dlg", self.session.current_dialog
+                               self.dvdScreen.show()
+                               self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
+
+       def exitCB(self, answer):
+               if answer is not None:
+                       if answer[1] == "exit":
+                               if self.service:
+                                       self.dvdScreen.hide()
+                                       self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
+                                       self.service = None
+                               self.close()
+                       if answer[1] == "browser":
+                               #TODO check here if a paused dvd playback is already running... then re-start it...
+                               #else
+                               self.showFileBrowser()
+                       else:
+                               pass
+
+       def __onClose(self):
+               self.restore_infobar_seek_config()
+               self.session.nav.playService(self.oldService)
+
+       def showAfterCuesheetOperation(self):
+               self.show()
+
+       def createSummary(self):
+               print "DVDCreateSummary"
+               return DVDSummary
+
+def main(session, **kwargs):
+       session.open(DVDPlayer)
+
+def menu(menuid, **kwargs):
+       if menuid == "mainmenu":
+               return [(_("DVD Player"), main, "dvd_player", 46)]
+       return []
+
+from Plugins.Plugin import PluginDescriptor
+def Plugins(**kwargs):
+       return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu)]
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/src/.cvsignore b/lib/python/Plugins/Extensions/DVDPlayer/src/.cvsignore
new file mode 100644 (file)
index 0000000..4181869
--- /dev/null
@@ -0,0 +1,5 @@
+*.pyc
+*.pyo
+*.so
+Makefile
+Makefile.in
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/src/Makefile.am b/lib/python/Plugins/Extensions/DVDPlayer/src/Makefile.am
new file mode 100644 (file)
index 0000000..bb02291
--- /dev/null
@@ -0,0 +1,11 @@
+servicedvd.so:
+       $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) -I$(top_srcdir)/include -Wall -W servicedvd.cpp -shared -fPIC -Wl,-soname,servicedvd.so -o servicedvd.so $(LDFLAGS) -ldreamdvd
+
+#-nostartfiles 
+
+all: servicedvd.so
+
+CLEANFILES = servicedvd.so
+
+install: all
+       $(INSTALL) servicedvd.so $(DESTDIR)/$(LIBDIR)/enigma2/python/Plugins/Extensions/DVDPlayer
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.cpp b/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.cpp
new file mode 100644 (file)
index 0000000..016e16a
--- /dev/null
@@ -0,0 +1,858 @@
+/* yes, it's dvd  */
+#include "servicedvd.h"
+#include <lib/base/eerror.h>
+#include <lib/base/object.h>
+#include <lib/base/ebase.h>
+#include <string>
+#include <lib/service/service.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+#include <lib/gui/esubtitle.h>
+#include <lib/gdi/gpixmap.h>
+
+#ifdef cue
+#include <byteswap.h>
+#include <netinet/in.h>
+#ifndef BYTE_ORDER
+#error no byte order defined!
+#endif
+#endif //cue
+
+extern "C" {
+#include <dreamdvd/ddvdlib.h>
+}
+
+// eServiceFactoryDVD
+
+eServiceFactoryDVD::eServiceFactoryDVD()
+{
+       ePtr<eServiceCenter> sc;
+       
+       eServiceCenter::getPrivInstance(sc);
+       if (sc)
+       {
+               std::list<std::string> extensions;
+               extensions.push_back("iso");
+               sc->addServiceFactory(eServiceFactoryDVD::id, this, extensions);
+       }
+}
+
+eServiceFactoryDVD::~eServiceFactoryDVD()
+{
+       ePtr<eServiceCenter> sc;
+       
+       eServiceCenter::getPrivInstance(sc);
+       if (sc)
+               sc->removeServiceFactory(eServiceFactoryDVD::id);
+}
+
+DEFINE_REF(eServiceFactoryDVD)
+
+       // iServiceHandler
+RESULT eServiceFactoryDVD::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+               // check resources...
+       ptr = new eServiceDVD(ref.path.c_str());
+       return 0;
+}
+
+RESULT eServiceFactoryDVD::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
+{
+       ptr=0;
+       return -1;
+}
+
+RESULT eServiceFactoryDVD::list(const eServiceReference &, ePtr<iListableService> &ptr)
+{
+       ptr=0;
+       return -1;
+}
+
+
+RESULT eServiceFactoryDVD::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
+{
+       ptr=0;
+       return -1;
+}
+
+RESULT eServiceFactoryDVD::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
+{
+       ptr = 0;
+       return -1;
+}
+
+// eServiceDVD
+
+DEFINE_REF(eServiceDVD);
+
+eServiceDVD::eServiceDVD(const char *filename):
+       m_filename(filename),
+       m_ddvdconfig(ddvd_create()),
+       m_pixmap(new gPixmap(eSize(720, 576), 32)),
+       m_subtitle_widget(0),
+       m_state(stIdle),
+       m_current_trick(0),
+       m_sn(eApp, ddvd_get_messagepipe_fd(m_ddvdconfig), eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup),
+       m_pump(eApp, 1)
+{
+       eDebug("SERVICEDVD construct!");
+       // create handle
+       ddvd_set_dvd_path(m_ddvdconfig, filename);
+       ddvd_set_ac3thru(m_ddvdconfig, 0);
+       ddvd_set_language(m_ddvdconfig, "de");
+       ddvd_set_video(m_ddvdconfig, DDVD_16_9, DDVD_PAL);
+       ddvd_set_lfb(m_ddvdconfig, (unsigned char *)m_pixmap->surface->data, 720, 576, 4, 720*4);
+       CONNECT(m_sn.activated, eServiceDVD::gotMessage);
+       CONNECT(m_pump.recv_msg, eServiceDVD::gotThreadMessage);
+       strcpy(m_ddvd_titlestring,"");
+       m_doSeekTo = 0;
+       m_seekTitle = 0;
+#ifdef cue
+       m_cue_pts = 0;
+#endif
+}
+
+void eServiceDVD::gotThreadMessage(const int &msg)
+{
+       switch(msg)
+       {
+       case 1: // thread stopped
+               m_state = stStopped;
+               m_event(this, evStopped);
+               break;
+       }
+}
+
+void eServiceDVD::gotMessage(int what)
+{
+       switch(ddvd_get_next_message(m_ddvdconfig,1))
+       {
+               case DDVD_COLORTABLE_UPDATE:
+               {
+/*
+                       struct ddvd_color ctmp[4];
+                       ddvd_get_last_colortable(ddvdconfig, ctmp);
+                       int i=0;
+                       while (i < 4)
+                       {
+                               rd1[252+i]=ctmp[i].red;
+                               bl1[252+i]=ctmp[i].blue;
+                               gn1[252+i]=ctmp[i].green;
+                               tr1[252+i]=ctmp[i].trans;
+                               i++;
+                       }
+                       if(ioctl(fb, FBIOPUTCMAP, &colormap) == -1)
+                       {
+                               printf("Framebuffer: <FBIOPUTCMAP failed>\n");
+                               return 1;
+                       }
+*/
+                       eDebug("no support for 8bpp framebuffer in dvdplayer yet!");
+                       break;
+               }
+               case DDVD_SCREEN_UPDATE:
+                       eDebug("DVD_SCREEN_UPDATE!");
+                       if (m_subtitle_widget)
+                               m_subtitle_widget->setPixmap(m_pixmap, eRect(0, 0, 720, 576));
+                       break;
+               case DDVD_SHOWOSD_STATE_PLAY:
+               {
+                       eDebug("DVD_SHOWOSD_STATE_PLAY!");
+                       m_current_trick = 0;
+                       m_event(this, evUser+1);
+                       break;
+               }
+               case DDVD_SHOWOSD_STATE_PAUSE:
+               {
+                       eDebug("DVD_SHOWOSD_STATE_PAUSE!");
+                       m_event(this, evUser+2);
+                       break;
+               }
+               case DDVD_SHOWOSD_STATE_FFWD:
+               {
+                       eDebug("DVD_SHOWOSD_STATE_FFWD!");
+                       m_event(this, evUser+3);
+                       break;
+               }
+               case DDVD_SHOWOSD_STATE_FBWD:
+               {
+                       eDebug("DVD_SHOWOSD_STATE_FBWD!");
+                       m_event(this, evUser+4);
+                       break;
+               }
+               case DDVD_SHOWOSD_STRING:
+               {
+                       eDebug("DVD_SHOWOSD_STRING!");
+                       m_event(this, evUser+5);
+                       break;
+               }
+               case DDVD_SHOWOSD_AUDIO:
+               {
+                       eDebug("DVD_SHOWOSD_STRING!");
+                       m_event(this, evUser+6);
+                       break;
+               }
+               case DDVD_SHOWOSD_SUBTITLE:
+               {
+                       eDebug("DVD_SHOWOSD_SUBTITLE!");
+                       m_event((iPlayableService*)this, evUpdatedInfo);
+                       m_event(this, evUser+7);
+                       break;
+               }
+               case DDVD_EOF_REACHED:
+                       eDebug("DVD_EOF_REACHED!");
+                       m_event(this, evEOF);
+                       break;
+
+               case DDVD_SOF_REACHED:
+                       eDebug("DVD_SOF_REACHED!");
+                       m_event(this, evSOF);
+                       break;
+               case DDVD_SHOWOSD_TIME:
+               {
+                       static struct ddvd_time last_info;
+                       struct ddvd_time info;
+                       ddvd_get_last_time(m_ddvdconfig, &info);
+                       int spu_id;
+                       uint16_t spu_lang;
+                       ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
+                       if ( info.pos_chapter != last_info.pos_chapter )
+                       {
+                               eDebug("DVD_SHOWOSD_TIME!");
+                               m_event(this, evUser+8); // chapterUpdated
+                       }
+                       if (  info.pos_title != last_info.pos_title )
+                       {
+                               m_event(this, evUser+9); // titleUpdated
+                       }
+                       if ( info.pos_title == m_seekTitle && m_doSeekTo )
+                       {
+                               seekRelative( +1, m_doSeekTo );
+                               m_doSeekTo = 0;
+                               m_seekTitle = 0;
+                       }
+                       ddvd_get_last_time(m_ddvdconfig, &last_info);
+                       break;
+               }
+               case DDVD_SHOWOSD_TITLESTRING:
+               {
+                       ddvd_get_title_string(m_ddvdconfig, m_ddvd_titlestring);
+                       eDebug("DDVD_SHOWOSD_TITLESTRING: %s",m_ddvd_titlestring);
+                       loadCuesheet();
+                       m_event(this, evStart);
+//                     m_event((iPlayableService*)this, evUpdatedEventInfo);
+//                     m_event(this, evUser+10);
+                       break;
+               }
+               case DDVD_MENU_OPENED:
+                       eDebug("DVD_MENU_OPENED!");
+                       m_event(this, evUser+11);
+                       break;
+               case DDVD_MENU_CLOSED:
+                       eDebug("DVD_MENU_CLOSED!");
+                       m_event(this, evUser+12);
+                       break;
+               default:
+                       break;
+       }
+}
+
+eServiceDVD::~eServiceDVD()
+{
+       eDebug("SERVICEDVD destruct!");
+       kill();
+       ddvd_close(m_ddvdconfig);
+}
+
+RESULT eServiceDVD::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
+{
+       connection = new eConnection((iPlayableService*)this, m_event.connect(event));
+       return 0;
+}
+
+RESULT eServiceDVD::start()
+{
+       assert(m_state == stIdle);
+       m_state = stRunning;
+       eDebug("eServiceDVD starting");
+       run();
+//     m_event(this, evStart);
+       return 0;
+}
+
+RESULT eServiceDVD::stop()
+{
+       assert(m_state != stIdle);
+       if (m_state == stStopped)
+               return -1;
+       eDebug("DVD: stop %s", m_filename.c_str());
+       m_state = stStopped;
+       ddvd_send_key(m_ddvdconfig, DDVD_KEY_EXIT);
+#ifdef cue
+       struct ddvd_time info;
+       ddvd_get_last_time(m_ddvdconfig, &info);
+       if ( info.pos_chapter < info.end_chapter )
+       {
+               pts_t pos;
+               pos = info.pos_hours * 3600;
+               pos += info.pos_minutes * 60;
+               pos += info.pos_seconds;
+               pos *= 90000;
+               m_cue_pts = pos;
+       }
+       else    // last chapter - usually credits, don't save cue
+               m_cue_pts = 0;
+       saveCuesheet();
+#endif
+       return 0;
+}
+
+RESULT eServiceDVD::setTarget(int target)
+{
+       return -1;
+}
+
+RESULT eServiceDVD::pause(ePtr<iPauseableService> &ptr)
+{
+       ptr=this;
+       return 0;
+}
+
+RESULT eServiceDVD::seek(ePtr<iSeekableService> &ptr)
+{
+       ptr=this;
+       return 0;
+}
+
+RESULT eServiceDVD::subtitle(ePtr<iSubtitleOutput> &ptr)
+{
+       ptr=this;
+       return 0;
+}
+
+RESULT eServiceDVD::keys(ePtr<iServiceKeys> &ptr)
+{
+       ptr=this;
+       return 0;
+}
+
+       // iPausableService
+RESULT eServiceDVD::setSlowMotion(int ratio)
+{
+       return -1;
+}
+
+RESULT eServiceDVD::setFastForward(int trick)
+{
+       eDebug("setTrickmode(%d)", trick);
+       while (m_current_trick > trick && m_current_trick != -64)
+       {
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_FBWD);
+               if (m_current_trick == 0)
+                       m_current_trick = -2;
+               else if (m_current_trick > 0)
+               {
+                       m_current_trick /= 2;
+                       if (abs(m_current_trick) == 1)
+                               m_current_trick=0;
+               }
+               else
+                       m_current_trick *= 2;
+       }
+       while (m_current_trick < trick && m_current_trick != 64)
+       {
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_FFWD);
+               if (m_current_trick == 0)
+                       m_current_trick = 2;
+               else if (m_current_trick < 0)
+               {
+                       m_current_trick /= 2;
+                       if (abs(m_current_trick) == 1)
+                               m_current_trick=0;
+               }
+               else
+                       m_current_trick *= 2;
+       }
+       return 0;
+}
+
+RESULT eServiceDVD::pause()
+{
+       ddvd_send_key(m_ddvdconfig, DDVD_KEY_PAUSE);
+       return 0;
+}
+
+RESULT eServiceDVD::unpause()
+{
+       ddvd_send_key(m_ddvdconfig, DDVD_KEY_PLAY);
+       return 0;
+}
+
+void eServiceDVD::thread()
+{
+       eDebug("eServiceDVD dvd thread started");
+       hasStarted();
+       ddvd_run(m_ddvdconfig);
+}
+
+void eServiceDVD::thread_finished()
+{
+       eDebug("eServiceDVD dvd thread finished");
+       m_pump.send(1); // inform main thread
+}
+
+RESULT eServiceDVD::info(ePtr<iServiceInformation>&i)
+{
+       i = this;
+       return 0;
+}
+
+RESULT eServiceDVD::getName(std::string &name)
+{
+       if ( m_ddvd_titlestring[0] != '\0' )
+               name = m_ddvd_titlestring;
+       else
+               name = m_filename;
+       return 0;
+}
+
+int eServiceDVD::getInfo(int w)
+{
+       switch (w)
+               {
+               case sUser:
+               case sArtist:
+               case sAlbum:
+                       return resIsPyObject;  // then getInfoObject should be called
+               case sComment:
+               case sTracknumber:
+               case sGenre:
+                       return resIsString;  // then getInfoString should be called
+               case evUser+8:
+               {
+                       struct ddvd_time info;
+                       ddvd_get_last_time(m_ddvdconfig, &info);
+                       return info.pos_chapter;
+               }
+               case evUser+80:
+               {
+                       struct ddvd_time info;
+                       ddvd_get_last_time(m_ddvdconfig, &info);
+                       return info.end_chapter;
+               }
+       
+               case evUser+9:
+               {
+                       struct ddvd_time info;
+                       ddvd_get_last_time(m_ddvdconfig, &info);
+                       return info.pos_title;
+               }
+               case evUser+90:
+               {
+                       struct ddvd_time info;
+                       ddvd_get_last_time(m_ddvdconfig, &info);
+                       return info.end_title;
+               }
+       
+               case sTXTPID:   // we abuse HAS_TELEXT icon in InfoBar to signalize subtitles status
+               {
+                       int spu_id;
+                       uint16_t spu_lang;
+                       ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
+                       return spu_id;
+               }
+               default:
+                       return resNA;
+       }
+}
+
+std::string eServiceDVD::getInfoString(int w)
+{
+       switch(w)
+       {
+               case evUser+7: {
+                       int spu_id;
+                       uint16_t spu_lang;
+                       ddvd_get_last_spu(m_ddvdconfig, &spu_id, &spu_lang);
+                       unsigned char spu_string[3]={spu_lang >> 8, spu_lang, 0};
+                       char osd[100];
+                       if (spu_id == -1)
+                               sprintf(osd,"");
+                       else
+                               sprintf(osd,"%d - %s",spu_id+1,spu_string);
+//                     lbo_changed=1;
+                       return osd;
+                       }
+               case evUser+6:
+                       {
+                       int audio_id,audio_type;
+                       uint16_t audio_lang;
+                       ddvd_get_last_audio(m_ddvdconfig, &audio_id, &audio_lang, &audio_type);
+                       char audio_string[3]={audio_lang >> 8, audio_lang, 0};
+                       char audio_form[5];
+                       switch(audio_type)
+                       {
+                               case DDVD_MPEG:
+                                       sprintf(audio_form,"MPEG");
+                                       break;
+                               case DDVD_AC3:
+                                       sprintf(audio_form,"AC3");
+                                       break;
+                               case DDVD_DTS:
+                                       sprintf(audio_form,"DTS");
+                                       break;
+                               case DDVD_LPCM:
+                                       sprintf(audio_form,"LPCM");
+                                       break;
+                               default:
+                                       sprintf(audio_form,"-");
+                       }
+                       char osd[100];
+                       sprintf(osd,"%d - %s (%s)",audio_id+1,audio_string,audio_form);
+                       return osd;
+                       }
+               default:
+                       eDebug("unhandled getInfoString(%d)", w);
+       }
+       return "";
+}
+
+PyObject *eServiceDVD::getInfoObject(int w)
+{
+       switch(w)
+       {
+               default:
+                       eDebug("unhandled getInfoObject(%d)", w);
+       }
+       Py_RETURN_NONE;
+}
+
+RESULT eServiceDVD::enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) entry)
+{
+       if (m_subtitle_widget)
+               delete m_subtitle_widget;
+       m_subtitle_widget = new eSubtitleWidget(parent);
+       m_subtitle_widget->resize(parent->size());
+       m_subtitle_widget->setPixmap(m_pixmap, eRect(0, 0, 720, 576));
+       m_subtitle_widget->setZPosition(-1);
+       m_subtitle_widget->show();
+       return 0;
+}
+
+RESULT eServiceDVD::disableSubtitles(eWidget *parent)
+{
+       delete m_subtitle_widget;
+       m_subtitle_widget = 0;
+       return 0;
+}
+
+PyObject *eServiceDVD::getSubtitleList()
+{
+       eDebug("eServiceDVD::getSubtitleList nyi");
+       Py_RETURN_NONE;
+}
+
+PyObject *eServiceDVD::getCachedSubtitle()
+{
+       eDebug("eServiceDVD::getCachedSubtitle nyi");
+       Py_RETURN_NONE;
+}
+
+RESULT eServiceDVD::getLength(pts_t &len)
+{
+//     eDebug("eServiceDVD::getLength");
+       struct ddvd_time info;
+       ddvd_get_last_time(m_ddvdconfig, &info);
+       len = info.end_hours * 3600;
+       len += info.end_minutes * 60;
+       len += info.end_seconds;
+       len *= 90000;
+       return 0;
+}
+
+// RESULT eServiceDVD::seekTo(pts_t to)
+// {
+//     struct ddvd_time info;
+//     to /= 90000;
+//     int cur;
+//     ddvd_get_last_time(m_ddvdconfig, &info);
+//     cur = info.pos_hours * 3600;
+//     cur += info.pos_minutes * 60;
+//     cur += info.pos_seconds;
+//     eDebug("seekTo %lld, cur %d, diff %lld", to, cur, cur - to);
+//     ddvd_skip_seconds(m_ddvdconfig, cur - to);
+//     return 0;
+// }
+
+RESULT eServiceDVD::seekTo(pts_t to)
+{
+       m_seekTitle = 1;
+       eDebug("seekTo %lld", to);
+       ddvd_set_title(m_ddvdconfig, m_seekTitle);
+       m_doSeekTo = to;
+       return 0;
+}
+
+RESULT eServiceDVD::seekRelative(int direction, pts_t to)
+{
+       int seconds = to / 90000;
+       seconds *= direction;
+       eDebug("seekRelative %d %d", direction, seconds);
+       ddvd_skip_seconds(m_ddvdconfig, seconds);
+       return 0;
+}
+
+RESULT eServiceDVD::getPlayPosition(pts_t &pos)
+{
+       struct ddvd_time info;
+       ddvd_get_last_time(m_ddvdconfig, &info);
+       pos = info.pos_hours * 3600;
+       pos += info.pos_minutes * 60;
+       pos += info.pos_seconds;
+//     eDebug("getPlayPosition %lld", pos);
+       pos *= 90000;
+       return 0;
+}
+
+RESULT eServiceDVD::seekChapter(int chapter)
+{
+       eDebug("setChapter %d", chapter);
+       if ( chapter > 0 )
+               ddvd_set_chapter(m_ddvdconfig, chapter);
+       return 0;
+}
+
+RESULT eServiceDVD::setTrickmode(int trick)
+{
+       return -1;
+}
+
+RESULT eServiceDVD::isCurrentlySeekable()
+{
+       return 1;
+}
+
+RESULT eServiceDVD::keyPressed(int key)
+{
+       switch(key)
+       {
+       case iServiceKeys::keyLeft:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_LEFT);
+               break;
+       case iServiceKeys::keyRight:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_RIGHT);
+               break;
+       case iServiceKeys::keyUp:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_UP);
+               break;
+       case iServiceKeys::keyDown:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_DOWN);
+               break;
+       case iServiceKeys::keyOk:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_OK);
+               break;
+       case iServiceKeys::keyUser:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIO);
+               break;
+       case iServiceKeys::keyUser+1:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_SUBTITLE);
+               break;
+       case iServiceKeys::keyUser+2:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_AUDIOMENU);
+               break;
+       case iServiceKeys::keyUser+3:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_CHAPTER);
+               break;
+       case iServiceKeys::keyUser+4:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_CHAPTER);
+               break;
+       case iServiceKeys::keyUser+5:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_NEXT_TITLE);
+               break;
+       case iServiceKeys::keyUser+6:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_PREV_TITLE);
+               break;
+       case iServiceKeys::keyUser+7:
+               ddvd_send_key(m_ddvdconfig, DDVD_KEY_MENU);
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+#ifdef cue
+RESULT eServiceDVD::cueSheet(ePtr<iCueSheet> &ptr)
+{
+       if (m_cue_pts)
+       {
+               ptr = this;
+               return 0;
+       }
+       ptr = 0;
+       return -1;
+}
+
+PyObject *eServiceDVD::getCutList()
+{
+       ePyObject list = PyList_New(0);
+       
+//     for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
+//     {
+               ePyObject tuple = PyTuple_New(2);
+//             PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
+               PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(m_cue_pts));
+//             PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
+               PyTuple_SetItem(tuple, 1, PyInt_FromLong(3));
+               PyList_Append(list, tuple);
+               Py_DECREF(tuple);
+//     }
+
+//     eDebug("eServiceDVD::getCutList() pts=%lld",m_cue_pts);
+
+       return list;
+}
+
+void eServiceDVD::setCutList(ePyObject list)
+{
+       eDebug("eServiceDVD::setCutList()");
+
+       if (!PyList_Check(list))
+               return;
+       int size = PyList_Size(list);
+       int i;
+       
+//     m_cue_entries.clear();
+       
+       for (i=0; i<size; ++i)
+       {
+               ePyObject tuple = PyList_GET_ITEM(list, i);
+               if (!PyTuple_Check(tuple))
+               {
+                       eDebug("non-tuple in cutlist");
+                       continue;
+               }
+               if (PyTuple_Size(tuple) != 2)
+               {
+                       eDebug("cutlist entries need to be a 2-tuple");
+                       continue;
+               }
+               ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
+               if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
+               {
+                       eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
+                       continue;
+               }
+//             pts_t pts = PyLong_AsLongLong(ppts);
+               m_cue_pts = PyLong_AsLongLong(ppts);
+               int type = PyInt_AsLong(ptype);
+//             m_cue_entries.insert(cueEntry(pts, type));
+               eDebug("eServiceDVD::setCutList() adding %08llx, %d", m_cue_pts, type);
+       }
+       m_cuesheet_changed = 1;
+       
+//     cutlistToCuesheet();
+       m_event((iPlayableService*)this, evCuesheetChanged);
+}
+
+void eServiceDVD::setCutListEnable(int enable)
+{
+       eDebug("eServiceDVD::setCutListEnable()");
+       m_cutlist_enabled = enable;
+//     cutlistToCuesheet();
+}
+
+
+void eServiceDVD::loadCuesheet()
+{
+       eDebug("eServiceDVD::loadCuesheet()");
+       char filename[128];
+       if ( m_ddvd_titlestring[0] != '\0' )
+               snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
+
+       eDebug("eServiceDVD::loadCuesheet() filename=%s",filename);
+//     m_cue_entries.clear();
+
+       FILE *f = fopen(filename, "rb");
+
+       if (f)
+       {
+               eDebug("loading cuts..");
+//             while (1)
+               {
+                       unsigned long long where;
+                       unsigned int what;
+                       
+                       if (!fread(&where, sizeof(where), 1, f))
+                               return;
+                       if (!fread(&what, sizeof(what), 1, f))
+                               return;
+                       
+#if BYTE_ORDER == LITTLE_ENDIAN
+                       where = bswap_64(where);
+#endif
+                       what = ntohl(what);
+                       
+//                     if (what > 3)
+//                             break;
+
+                       m_cue_pts = where;
+                       
+//                     m_cue_entries.insert(cueEntry(where, what));
+               }
+               fclose(f);
+//             eDebug("%d entries", m_cue_entries.size());
+       } else
+               eDebug("cutfile not found!");
+       
+       m_cuesheet_changed = 0;
+//     cutlistToCuesheet();
+       eDebug("eServiceDVD::loadCuesheet() pts=%lld",m_cue_pts);
+
+       if (m_cue_pts)
+               m_event((iPlayableService*)this, evCuesheetChanged);
+}
+
+void eServiceDVD::saveCuesheet()
+{
+       eDebug("eServiceDVD::saveCuesheet() pts=%lld",m_cue_pts);
+       char filename[128];
+       if ( m_ddvd_titlestring[0] != '\0' )
+               snprintf(filename, 128, "/home/root/dvd-%s.cuts", m_ddvd_titlestring);
+       
+       FILE *f = fopen(filename, "wb");
+
+       if (f)
+       {
+               unsigned long long where;
+               int what;
+
+//             for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
+               {
+#if BYTE_ORDER == BIG_ENDIAN
+                       where = m_cue_pts;
+//                     where = i->where;
+#else
+//                     where = bswap_64(i->where);
+                       where = bswap_64(m_cue_pts);
+#endif
+//                     what = htonl(i->what);
+                       what = 3;
+                       fwrite(&where, sizeof(where), 1, f);
+                       fwrite(&what, sizeof(what), 1, f);
+                       
+               }
+               fclose(f);
+       }
+       
+       m_cuesheet_changed = 0;
+}
+#endif
+
+eAutoInitPtr<eServiceFactoryDVD> init_eServiceFactoryDVD(eAutoInitNumbers::service+1, "eServiceFactoryDVD");
+
+PyMODINIT_FUNC
+initservicedvd(void)
+{
+       Py_InitModule("servicedvd", NULL);
+}
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.h b/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.h
new file mode 100644 (file)
index 0000000..ed5d49b
--- /dev/null
@@ -0,0 +1,166 @@
+#ifndef __servicedvd_h
+#define __servicedvd_h
+
+#include <lib/base/message.h>
+#include <lib/base/ebase.h>
+#include <lib/base/thread.h>
+#include <lib/service/iservice.h>
+
+#define cue
+
+class eSubtitleWidget;
+class gPixmap;
+class eStaticServiceDVDInfo;
+
+class eServiceFactoryDVD: public iServiceHandler
+{
+DECLARE_REF(eServiceFactoryDVD);
+public:
+       eServiceFactoryDVD();
+       virtual ~eServiceFactoryDVD();
+       enum { id = 0x1111 };
+
+               // iServiceHandler
+       RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+       RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+       RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+       RESULT info(const eServiceReference &, ePtr<iStaticServiceInformation> &ptr);
+       RESULT offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr);
+};
+
+class eServiceDVD: public iPlayableService, public iPauseableService, public iSeekableService,
+       public iServiceInformation, public iSubtitleOutput, public iServiceKeys, public eThread, public Object
+#ifdef cue
+, public iCueSheet
+#endif
+{
+       friend class eServiceFactoryDVD;
+DECLARE_REF(eServiceDVD);
+public:
+       virtual ~eServiceDVD();
+               // not implemented (yet)
+       RESULT audioChannel(ePtr<iAudioChannelSelection> &ptr) { ptr = 0; return -1; }
+       RESULT audioTracks(ePtr<iAudioTrackSelection> &ptr) { ptr = 0; return -1; }
+       RESULT frontendInfo(ePtr<iFrontendInformation> &ptr) { ptr = 0; return -1; }
+       RESULT subServices(ePtr<iSubserviceList> &ptr) { ptr = 0; return -1; }
+       RESULT timeshift(ePtr<iTimeshiftService> &ptr) { ptr = 0; return -1; }
+       RESULT audioDelay(ePtr<iAudioDelay> &ptr) { ptr = 0; return -1; }
+       RESULT rdsDecoder(ePtr<iRdsDecoder> &ptr) { ptr = 0; return -1; }
+       RESULT stream(ePtr<iStreamableService> &ptr) { ptr = 0; return -1; }
+#ifdef cue
+       RESULT cueSheet(ePtr<iCueSheet> &ptr);
+#else
+       RESULT cueSheet(ePtr<iCueSheet> &ptr) { ptr = 0; return -1; }
+#endif
+
+               // iPlayableService
+       RESULT connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection);
+       RESULT start();
+       RESULT stop();
+       RESULT setTarget(int target);
+       RESULT info(ePtr<iServiceInformation> &ptr);
+       RESULT pause(ePtr<iPauseableService> &ptr);
+       RESULT subtitle(ePtr<iSubtitleOutput> &ptr);
+       RESULT seek(ePtr<iSeekableService> &ptr);
+       RESULT keys(ePtr<iServiceKeys> &ptr);
+
+               // iPausableService
+       RESULT pause();
+       RESULT unpause();
+       RESULT setSlowMotion(int ratio);
+       RESULT setFastForward(int ratio);
+
+               // iSubtitleOutput
+       RESULT enableSubtitles(eWidget *parent, SWIG_PYOBJECT(ePyObject) entry);
+       RESULT disableSubtitles(eWidget *parent);
+       PyObject *getSubtitleList();
+       PyObject *getCachedSubtitle();
+
+#if 1
+               // iSeekableService
+       RESULT getLength(pts_t &len);
+       RESULT seekTo(pts_t to);
+       RESULT seekRelative(int direction, pts_t to);
+       RESULT getPlayPosition(pts_t &pos);
+       RESULT setTrickmode(int trick=0);
+       RESULT isCurrentlySeekable();
+       RESULT seekChapter(int chapter);
+#endif
+
+               // iServiceInformation
+       RESULT getName(std::string &name);
+       int getInfo(int w);
+       std::string getInfoString(int w);
+       virtual PyObject *getInfoObject(int w);
+
+#ifdef cue
+               // iCueSheet
+       PyObject *getCutList();
+       void setCutList(SWIG_PYOBJECT(ePyObject));
+       void setCutListEnable(int enable);
+#endif
+               // iServiceKeys
+       RESULT keyPressed(int key);
+private:
+       eServiceDVD(const char *filename);
+
+       void gotMessage(int); // message from dvdlib
+       void gotThreadMessage(const int &); // message from dvd thread
+
+               // eThread
+       void thread();
+       void thread_finished();
+
+       std::string m_filename;
+
+       Signal2<void,iPlayableService*,int> m_event;
+
+       struct ddvd *m_ddvdconfig;
+       ePtr<gPixmap> m_pixmap;
+       eSubtitleWidget *m_subtitle_widget;
+
+       enum
+       {
+               stIdle, stRunning, stStopped,
+       };
+
+       int m_state;
+       int m_current_trick;
+
+       pts_t m_doSeekTo;
+       int m_seekTitle;
+       char m_ddvd_titlestring[96];
+
+       eSocketNotifier m_sn;
+       eFixedMessagePump<int> m_pump;
+
+#ifdef cue
+//     ePtr<eCueSheet> m_cue;
+// 
+//     struct cueEntry
+//     {
+//             pts_t where;
+//             unsigned int what;
+//             
+//             bool operator < (const struct cueEntry &o) const
+//             {
+//                     return where < o.where;
+//             }
+//             cueEntry(const pts_t &where, unsigned int what) :
+//                     where(where), what(what)
+//             {
+//             }
+//     };
+       
+//     std::multiset<cueEntry> m_cue_entries;
+       int m_cuesheet_changed, m_cutlist_enabled;
+       pts_t m_cue_pts;
+       
+       void loadCuesheet();
+       void saveCuesheet();
+       
+//     void cutlistToCuesheet();
+#endif
+};
+
+#endif
index e0a7f81..5970477 100644 (file)
@@ -1,2 +1,2 @@
-SUBDIRS = TuxboxPlugins FileManager CutListEditor PicturePlayer MediaScanner MediaPlayer IpkgInstaller GraphMultiEPG SocketMMI
+SUBDIRS = TuxboxPlugins FileManager CutListEditor PicturePlayer MediaScanner MediaPlayer IpkgInstaller GraphMultiEPG SocketMMI DVDPlayer
 # SimpleRSS is still not finished