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
--- /dev/null
+*.pyc
+*.pyo
+Makefile
+Makefile.in
--- /dev/null
+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.
--- /dev/null
+SUBDIRS = src
+
+installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/DVDPlayer
+
+install_PYTHON = \
+ __init__.py \
+ plugin.py \
+ keymap.xml \
+ LICENSE
--- /dev/null
+<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>
--- /dev/null
+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)]
--- /dev/null
+*.pyc
+*.pyo
+*.so
+Makefile
+Makefile.in
--- /dev/null
+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
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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
-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