diff options
| author | Andreas Monzner <andreas.monzner@multimedia-labs.de> | 2008-04-15 12:47:41 +0000 |
|---|---|---|
| committer | Andreas Monzner <andreas.monzner@multimedia-labs.de> | 2008-04-15 12:47:41 +0000 |
| commit | 17be24380f07656d14b88baf5af0d9ef3d8eddfd (patch) | |
| tree | f4415b51ebf4ca4c5281883ea4cdde6107d5560c /lib/python/Plugins/Extensions/DVDPlayer | |
| parent | c50acf3391bec3f2abaf219c8f52c7d57d6149b5 (diff) | |
| download | enigma2-17be24380f07656d14b88baf5af0d9ef3d8eddfd.tar.gz enigma2-17be24380f07656d14b88baf5af0d9ef3d8eddfd.zip | |
add DVDPlayer plugin (not final yet)
not working without libdreamdvd (not in OE yet)
Diffstat (limited to 'lib/python/Plugins/Extensions/DVDPlayer')
10 files changed, 1637 insertions, 0 deletions
diff --git a/lib/python/Plugins/Extensions/DVDPlayer/.cvsignore b/lib/python/Plugins/Extensions/DVDPlayer/.cvsignore new file mode 100644 index 00000000..138b9cc2 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/.cvsignore @@ -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 index 00000000..99700593 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/LICENSE @@ -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 index 00000000..ed474154 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/Makefile.am @@ -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 index 00000000..8d1c8b69 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/__init__.py @@ -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 index 00000000..b8b4994d --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/keymap.xml @@ -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 index 00000000..856c7d18 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/plugin.py @@ -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 index 00000000..41818695 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/src/.cvsignore @@ -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 index 00000000..bb02291c --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/src/Makefile.am @@ -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 index 00000000..016e16a1 --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.cpp @@ -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 index 00000000..ed5d49bd --- /dev/null +++ b/lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.h @@ -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 |
