nathan@0: /* nathan@0: * MP3/MPlayer plugin to VDR (C++) nathan@0: * nathan@22: * (C) 2001-2009 Stefan Huelswitt nathan@0: * nathan@0: * This code is free software; you can redistribute it and/or nathan@0: * modify it under the terms of the GNU General Public License nathan@0: * as published by the Free Software Foundation; either version 2 nathan@0: * of the License, or (at your option) any later version. nathan@0: * nathan@0: * This code is distributed in the hope that it will be useful, nathan@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of nathan@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nathan@0: * GNU General Public License for more details. nathan@0: * nathan@0: * You should have received a copy of the GNU General Public License nathan@0: * along with this program; if not, write to the Free Software nathan@0: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. nathan@0: * Or, point your browser to http://www.gnu.org/copyleft/gpl.html nathan@0: */ nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: nathan@0: #include "common.h" nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: nathan@0: #include "setup.h" nathan@0: #include "setup-mplayer.h" nathan@0: #include "menu.h" nathan@0: #include "player-mplayer.h" nathan@0: #include "data.h" nathan@0: #include "data-src.h" nathan@0: #include "i18n.h" nathan@0: #include "version.h" nathan@0: #include "service.h" nathan@0: nathan@0: const char *sourcesSub=0; nathan@0: cFileSources MPlaySources; nathan@0: nathan@2: static const char *plugin_name=0; nathan@12: const char *i18n_name=0; nathan@2: nathan@0: // --- cMenuSetupMPlayer -------------------------------------------------------- nathan@0: nathan@0: class cMenuSetupMPlayer : public cMenuSetupPage { nathan@0: private: nathan@0: cMPlayerSetup data; nathan@0: const char *res[3]; nathan@0: protected: nathan@0: virtual void Store(void); nathan@0: public: nathan@0: cMenuSetupMPlayer(void); nathan@0: }; nathan@0: nathan@0: cMenuSetupMPlayer::cMenuSetupMPlayer(void) nathan@0: { nathan@0: data=MPlayerSetup; nathan@0: SetSection(tr("MPlayer")); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"), &data.SlaveMode, tr("Traditional"), tr("Slave"))); nathan@0: res[0]=tr("disabled"); nathan@0: res[1]=tr("global only"); nathan@0: res[2]=tr("local first"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"), &data.ResumeMode, 3, res)); nathan@0: Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu)); nathan@0: for(int i=0; i<10; i++) { nathan@0: char name[32]; nathan@0: snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i); nathan@0: static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" }; nathan@0: Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed)); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMenuSetupMPlayer::Store(void) nathan@0: { nathan@0: MPlayerSetup=data; nathan@0: SetupStore("ControlMode", MPlayerSetup.SlaveMode); nathan@0: SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu); nathan@0: SetupStore("ResumeMode", MPlayerSetup.ResumeMode); nathan@0: for(int i=0; i<10; i++) { nathan@0: char name[16]; nathan@0: snprintf(name,sizeof(name),"KeyCmd%d",i); nathan@0: SetupStore(name,MPlayerSetup.KeyCmd[i]); nathan@0: } nathan@0: } nathan@0: nathan@0: // --- cMPlayerControl --------------------------------------------------------- nathan@0: nathan@0: class cMPlayerControl : public cControl { nathan@0: private: nathan@0: static cFileObj *file; nathan@0: static bool rewind; nathan@0: cMPlayerPlayer *player; nathan@0: cSkinDisplayReplay *display; nathan@24: bool visible, modeOnly; nathan@0: time_t timeoutShow; nathan@0: int lastCurrent, lastTotal; nathan@0: char *lastReplayMsg; nathan@0: // nathan@0: bool jumpactive, jumphide, jumpmode; nathan@0: int jumpval; nathan@0: // nathan@0: void Stop(void); nathan@0: void ShowTimed(int Seconds=0); nathan@0: void ShowProgress(void); nathan@0: void ShowMode(void); nathan@0: void ShowTitle(void); nathan@0: void Jump(void); nathan@0: void JumpProcess(eKeys Key); nathan@0: void JumpDisplay(void); nathan@0: public: nathan@0: cMPlayerControl(void); nathan@0: virtual ~cMPlayerControl(); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: virtual void Show(void) { ShowTimed(); } nathan@0: virtual void Hide(void); nathan@0: static void SetFile(const cFileObj *File, bool Rewind); nathan@0: }; nathan@0: nathan@0: cFileObj *cMPlayerControl::file=0; nathan@0: bool cMPlayerControl::rewind=false; nathan@0: nathan@0: cMPlayerControl::cMPlayerControl(void) nathan@0: :cControl(player=new cMPlayerPlayer(file,rewind)) nathan@0: { nathan@24: visible=modeOnly=jumpactive=false; nathan@0: lastReplayMsg=0; nathan@0: display=0; nathan@0: ShowTitle(); nathan@0: } nathan@0: nathan@0: cMPlayerControl::~cMPlayerControl() nathan@0: { nathan@0: Stop(); nathan@0: cStatus::MsgReplaying(this,0,0,false); nathan@0: free(lastReplayMsg); nathan@0: } nathan@0: nathan@0: void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind) nathan@0: { nathan@0: delete file; nathan@0: file=File ? new cFileObj(File) : 0; nathan@0: rewind=Rewind; nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Stop(void) nathan@0: { nathan@0: delete player; player=0; nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowTimed(int Seconds) nathan@0: { nathan@0: if(modeOnly) Hide(); nathan@0: if(!visible) { nathan@0: ShowProgress(); nathan@0: timeoutShow = Seconds>0 ? time(0)+Seconds : 0; nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Hide(void) nathan@0: { nathan@0: if(visible) { nathan@0: delete display; display=0; nathan@0: visible=modeOnly=false; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(false); nathan@0: #else nathan@0: needsFastResponse=false; nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowTitle(void) nathan@0: { nathan@0: const char *path=0; nathan@0: bool release=true; nathan@0: if(player) path=player->GetCurrentName(); nathan@0: if(!path) { nathan@0: path=file->FullPath(); nathan@0: release=false; nathan@0: } nathan@0: if(path) { nathan@0: const char *name=rindex(path,'/'); nathan@0: if(name) name++; else name=path; nathan@0: if(!lastReplayMsg || strcmp(lastReplayMsg,path)) { nathan@0: cStatus::MsgReplaying(this,name,path,true); nathan@0: free(lastReplayMsg); nathan@0: lastReplayMsg=strdup(path); nathan@0: } nathan@0: if(visible) { nathan@0: if(display) display->SetTitle(name); nathan@0: } nathan@0: } nathan@0: if(release) free((void *)path); nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowProgress(void) nathan@0: { nathan@0: int Current, Total; nathan@0: nathan@0: if(GetIndex(Current,Total) && Total>0) { nathan@0: bool flush=false; nathan@0: if(!visible) { nathan@0: display=Skins.Current()->DisplayReplay(false); nathan@0: visible=true; modeOnly=false; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(true); nathan@0: #else nathan@0: needsFastResponse=true; nathan@0: #endif nathan@0: lastCurrent=lastTotal=-1; nathan@0: flush=true; nathan@0: } nathan@0: nathan@0: if(abs(Current-lastCurrent)>12) { nathan@0: if(Total>0) display->SetProgress(Current, Total); nathan@0: display->SetCurrent(IndexToHMSF(Current)); nathan@0: display->SetTotal(IndexToHMSF(Total)); nathan@0: bool Play, Forward; nathan@0: int Speed; nathan@0: if(GetReplayMode(Play,Forward,Speed)) nathan@0: display->SetMode(Play, Forward, Speed); nathan@0: ShowTitle(); nathan@0: flush=true; nathan@0: lastCurrent=Current; lastTotal=Total; nathan@0: } nathan@0: if(flush) nathan@0: Skins.Flush(); nathan@0: ShowMode(); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowMode(void) nathan@0: { nathan@0: if(Setup.ShowReplayMode && !jumpactive) { nathan@0: bool Play, Forward; nathan@0: int Speed; nathan@0: if(GetReplayMode(Play, Forward, Speed)) { nathan@0: bool NormalPlay = (Play && Speed == -1); nathan@0: nathan@0: if(!visible) { nathan@0: if(NormalPlay) return; nathan@0: display = Skins.Current()->DisplayReplay(true); nathan@0: visible=modeOnly=true; nathan@0: } nathan@0: nathan@0: if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; nathan@0: nathan@0: display->SetMode(Play, Forward, Speed); nathan@0: } nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::JumpDisplay(void) nathan@0: { nathan@0: char buf[64]; nathan@2: const char *j=trVDR("Jump: "), u=jumpmode?'%':'m'; nathan@0: if(!jumpval) sprintf(buf,"%s- %c", j,u); nathan@0: else sprintf(buf,"%s%d- %c",j,jumpval,u); nathan@0: display->SetJump(buf); nathan@0: } nathan@0: nathan@0: void cMPlayerControl::JumpProcess(eKeys Key) nathan@0: { nathan@0: const int n=Key-k0; nathan@0: switch (Key) { nathan@0: case k0 ... k9: nathan@0: { nathan@0: const int max=jumpmode?100:lastTotal; nathan@0: if(jumpval*10+n <= max) jumpval=jumpval*10+n; nathan@0: JumpDisplay(); nathan@0: } nathan@0: break; nathan@0: case kBlue: nathan@0: jumpmode=!jumpmode; jumpval=0; nathan@22: JumpDisplay(); nathan@0: break; nathan@0: case kPlay: nathan@0: case kUp: nathan@0: player->Goto(jumpval*(jumpmode?1:60),jumpmode,false); nathan@0: jumpactive=false; nathan@0: break; nathan@0: case kFastRew: nathan@0: case kFastFwd: nathan@0: case kLeft: nathan@0: case kRight: nathan@0: if(!jumpmode) { nathan@0: player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1)); nathan@0: jumpactive=false; nathan@0: } nathan@0: break; nathan@0: default: nathan@0: jumpactive=false; nathan@0: break; nathan@0: } nathan@0: nathan@0: if(!jumpactive) { nathan@0: if(jumphide) Hide(); nathan@0: else nathan@0: display->SetJump(0); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Jump(void) nathan@0: { nathan@0: jumpval=0; jumphide=jumpmode=false; nathan@0: if(!visible) { nathan@0: ShowTimed(); if(!visible) return; nathan@0: jumphide=true; nathan@0: } nathan@0: JumpDisplay(); nathan@0: jumpactive=true; nathan@0: } nathan@0: nathan@0: eOSState cMPlayerControl::ProcessKey(eKeys Key) nathan@0: { nathan@0: if(!player->Active()) { Hide(); Stop(); return osEnd; } nathan@0: nathan@0: if(!player->SlaveMode()) { nathan@0: if(Key==kBlue) { Hide(); Stop(); return osEnd; } nathan@0: } nathan@0: else { nathan@0: if(visible) { nathan@0: if(timeoutShow && time(0)>timeoutShow) { nathan@0: Hide(); ShowMode(); nathan@0: timeoutShow = 0; nathan@0: } nathan@0: else { nathan@0: if(modeOnly) ShowMode(); nathan@0: else ShowProgress(); nathan@0: } nathan@0: } nathan@0: else ShowTitle(); nathan@0: nathan@0: if(jumpactive && Key != kNone) { nathan@0: JumpProcess(Key); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: bool DoShowMode = true; nathan@0: switch (Key) { nathan@0: case kPlay: nathan@0: case kUp: player->Play(); break; nathan@0: nathan@0: case kPause: nathan@0: case kDown: player->Pause(); break; nathan@0: nathan@0: case kFastRew|k_Repeat: nathan@0: case kFastRew: nathan@0: case kLeft|k_Repeat: nathan@0: case kLeft: player->SkipSeconds(-10); break; nathan@0: nathan@0: case kFastFwd|k_Repeat: nathan@0: case kFastFwd: nathan@0: case kRight|k_Repeat: nathan@0: case kRight: player->SkipSeconds(10); break; nathan@0: nathan@0: case kRed: Jump(); break; nathan@0: nathan@0: case kGreen|k_Repeat: // temporary use nathan@0: case kGreen: player->SkipSeconds(-60); break; nathan@0: case kYellow|k_Repeat: nathan@0: case kYellow: player->SkipSeconds(60); break; nathan@0: // case kGreen|k_Repeat: // reserved for future use nathan@0: // case kGreen: player->SkipPrev(); break; nathan@0: // case kYellow|k_Repeat: nathan@0: // case kYellow: player->SkipNext(); break; nathan@0: nathan@0: case kBack: nathan@0: Hide(); nathan@2: cRemote::CallPlugin(plugin_name); nathan@0: return osBack; nathan@0: case kStop: nathan@0: case kBlue: Hide(); Stop(); return osEnd; nathan@0: nathan@0: default: nathan@0: DoShowMode = false; nathan@0: switch(Key) { nathan@0: case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; } nathan@0: else ShowTimed(); nathan@0: break; nathan@20: case kAudio: nathan@20: player->KeyCmd("switch_audio"); nathan@20: break; nathan@27: case kNext: nathan@27: player->KeyCmd("seek_chapter +1"); nathan@27: break; nathan@27: case kPrev: nathan@27: player->KeyCmd("seek_chapter -1"); nathan@27: break; nathan@0: case k0: nathan@0: case k1: nathan@0: case k2: nathan@0: case k3: nathan@0: case k4: nathan@0: case k5: nathan@0: case k6: nathan@0: case k7: nathan@0: case k8: nathan@0: case k9: { nathan@0: const char *cmd=MPlayerSetup.KeyCmd[Key-k0]; nathan@0: if(cmd[0]) player->KeyCmd(cmd); nathan@0: } nathan@0: break; nathan@0: default: break; nathan@0: } nathan@0: break; nathan@0: } nathan@0: nathan@0: if(DoShowMode) ShowMode(); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: // --- cMenuMPlayAid ----------------------------------------------------------- nathan@0: nathan@0: class cMenuMPlayAid : public cOsdMenu { nathan@0: public: nathan@0: cMenuMPlayAid(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuMPlayAid::cMenuMPlayAid(void) nathan@0: :cOsdMenu(tr("MPlayer Audio ID"),20) nathan@0: { nathan@0: Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255)); nathan@0: Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayAid::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state=cOsdMenu::ProcessKey(Key); nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kOk: state=osBack; break; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cMenuMPlayBrowse --------------------------------------------------------- nathan@0: nathan@0: class cMenuMPlayBrowse : public cMenuBrowse { nathan@0: private: nathan@0: bool sourcing, aidedit; nathan@0: eOSState Source(bool second); nathan@0: eOSState Summary(void); nathan@0: protected: nathan@0: virtual void SetButtons(void); nathan@0: public: nathan@0: cMenuMPlayBrowse(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 }; nathan@0: nathan@0: cMenuMPlayBrowse::cMenuMPlayBrowse(void) nathan@0: :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum) nathan@0: { nathan@0: sourcing=aidedit=false; nathan@0: SetButtons(); nathan@0: } nathan@0: nathan@0: void cMenuMPlayBrowse::SetButtons(void) nathan@0: { nathan@0: static char blue[12]; nathan@0: snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid); nathan@23: SetHelp(trVDR("Button$Play"), MPlayerSetup.ResumeMode ? trVDR("Button$Rewind"):0, tr("Source"), blue); nathan@0: Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::Source(bool second) nathan@0: { nathan@0: if(HasSubMenu()) return osContinue; nathan@0: nathan@0: if(!second) { nathan@0: sourcing=true; nathan@0: return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source"))); nathan@0: } nathan@0: sourcing=false; nathan@0: cFileSource *src=cMenuSource::GetSelected(); nathan@0: if(src) { nathan@0: MPlaySources.SetSource(src); nathan@0: SetSource(src); nathan@0: NewDir(0); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::Summary(void) nathan@0: { nathan@0: cFileObj *item=CurrentItem(); nathan@0: if(item && item->Type()==otFile) { nathan@0: static const char *exts[] = { ".summary",".txt",".nfo",0 }; nathan@0: for(int i=0; exts[i]; i++) { nathan@0: char buff[4096]; nathan@0: strn0cpy(buff,item->FullPath(),sizeof(buff)-20); nathan@0: char *e=&buff[strlen(buff)]; nathan@0: strn0cpy(e,exts[i],20); nathan@0: int fd=open(buff,O_RDONLY); nathan@0: *e=0; nathan@0: if(fd<0 && (e=rindex(buff,'.'))) { nathan@0: strn0cpy(e,exts[i],20); nathan@0: fd=open(buff,O_RDONLY); nathan@0: } nathan@0: if(fd>=0) { nathan@0: int r=read(fd,buff,sizeof(buff)-1); nathan@0: close(fd); nathan@0: if(r>0) { nathan@0: buff[r]=0; nathan@0: return AddSubMenu(new cMenuText(tr("Summary"),buff)); nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state=cOsdMenu::ProcessKey(Key); nathan@0: if(state==osContinue && !HasSubMenu()) { nathan@0: if(sourcing) return Source(true); nathan@0: if(aidedit) { aidedit=false; SetButtons(); } nathan@0: } nathan@0: bool rew=false; nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kGreen: nathan@0: { nathan@0: cFileObj *item=CurrentItem(); nathan@0: if(item && item->Type()==otFile) { nathan@0: lastselect=new cFileObj(item); nathan@0: state=osBack; nathan@0: rew=true; nathan@0: } nathan@0: else state=osContinue; nathan@0: break; nathan@0: } nathan@0: case kYellow: nathan@0: state=Source(false); nathan@0: break; nathan@0: case kBlue: nathan@0: aidedit=true; nathan@0: state=AddSubMenu(new cMenuMPlayAid); nathan@0: break; nathan@0: case k0: nathan@0: state=Summary(); nathan@0: break; nathan@0: default: nathan@0: break; nathan@0: } nathan@0: } nathan@0: if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); nathan@0: if(state==osBack && lastselect) { nathan@0: cMPlayerControl::SetFile(lastselect,rew); nathan@0: cControl::Launch(new cMPlayerControl); nathan@0: return osEnd; nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cPluginMPlayer ---------------------------------------------------------- nathan@0: nathan@2: static const char *DESCRIPTION = trNOOP("Media replay via MPlayer"); nathan@0: static const char *MAINMENUENTRY = "MPlayer"; nathan@0: nathan@0: class cPluginMPlayer : public cPlugin { nathan@0: private: nathan@0: bool ExternalPlay(const char *path, bool test); nathan@0: public: nathan@0: cPluginMPlayer(void); nathan@0: virtual ~cPluginMPlayer(); nathan@9: virtual const char *Version(void) { return PluginVersion; } nathan@0: virtual const char *Description(void) { return tr(DESCRIPTION); } nathan@0: virtual const char *CommandLineHelp(void); nathan@0: virtual bool ProcessArgs(int argc, char *argv[]); nathan@0: virtual bool Initialize(void); nathan@0: virtual const char *MainMenuEntry(void); nathan@0: virtual cOsdMenu *MainMenuAction(void); nathan@0: virtual cMenuSetupPage *SetupMenu(void); nathan@0: virtual bool SetupParse(const char *Name, const char *Value); nathan@0: virtual bool Service(const char *Id, void *Data); nathan@0: virtual const char **SVDRPHelpPages(void); nathan@0: virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); nathan@0: }; nathan@0: nathan@0: cPluginMPlayer::cPluginMPlayer(void) nathan@0: { nathan@0: // Initialize any member variables here. nathan@0: // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL nathan@0: // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! nathan@0: status=0; nathan@0: } nathan@0: nathan@0: cPluginMPlayer::~cPluginMPlayer() nathan@0: { nathan@0: delete status; nathan@0: } nathan@0: nathan@0: const char *cPluginMPlayer::CommandLineHelp(void) nathan@0: { nathan@0: static char *help_str=0; nathan@0: nathan@0: free(help_str); // for easier orientation, this is column 80| nathan@29: help_str=aprintf( " -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" nathan@0: " (default: %s)\n" nathan@0: " -M CMD, --mplayer=CMD use CMD when calling MPlayer\n" nathan@0: " (default: %s)\n" nathan@0: " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" nathan@0: " (default: %s)\n" nathan@0: " -R DIR, --resume=DIR store global resume file in DIR\n" nathan@0: " (default: %s)\n", nathan@0: mountscript, nathan@0: MPlayerCmd, nathan@0: sourcesSub ? sourcesSub:"none", nathan@0: globalResumeDir ? globalResumeDir:"video dir" nathan@0: ); nathan@0: return help_str; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::ProcessArgs(int argc, char *argv[]) nathan@0: { nathan@0: static struct option long_options[] = { nathan@0: { "mount", required_argument, NULL, 'm' }, nathan@0: { "mplayer", required_argument, NULL, 'M' }, nathan@0: { "sources", required_argument, NULL, 'S' }, nathan@0: { "resume", required_argument, NULL, 'R' }, nathan@0: { NULL } nathan@0: }; nathan@0: nathan@0: int c, option_index = 0; nathan@0: while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) { nathan@0: switch (c) { nathan@0: case 'm': mountscript=optarg; break; nathan@0: case 'M': MPlayerCmd=optarg; break; nathan@0: case 'S': sourcesSub=optarg; break; nathan@0: case 'R': globalResumeDir=optarg; break; nathan@0: default: return false; nathan@0: } nathan@0: } nathan@0: return true; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::Initialize(void) nathan@22: { nathan@22: if(!CheckVDRVersion(1,4,5,"mplayer")) return false; nathan@2: plugin_name="mplayer"; nathan@2: #if APIVERSNUM < 10507 nathan@2: i18n_name="mplayer"; nathan@2: #else nathan@2: i18n_name="vdr-mplayer"; nathan@2: #endif nathan@0: MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf")); nathan@0: if(MPlaySources.Count()<1) { nathan@0: esyslog("ERROR: you must have defined at least one source in mplayersources.conf"); nathan@0: fprintf(stderr,"No source(s) defined in mplayersources.conf\n"); nathan@0: return false; nathan@0: } nathan@2: #if APIVERSNUM < 10507 nathan@0: RegisterI18n(Phrases); nathan@2: #endif nathan@0: if(!(status=new cMPlayerStatus)) return false; nathan@0: return true; nathan@0: } nathan@0: nathan@0: const char *cPluginMPlayer::MainMenuEntry(void) nathan@0: { nathan@0: return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY); nathan@0: } nathan@0: nathan@0: cOsdMenu *cPluginMPlayer::MainMenuAction(void) nathan@0: { nathan@0: return new cMenuMPlayBrowse; nathan@0: } nathan@0: nathan@0: cMenuSetupPage *cPluginMPlayer::SetupMenu(void) nathan@0: { nathan@0: return new cMenuSetupMPlayer; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::SetupParse(const char *Name, const char *Value) nathan@0: { nathan@0: if( !strcasecmp(Name, "ControlMode")) MPlayerSetup.SlaveMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value); nathan@0: else if (!strcasecmp(Name, "ResumeMode")) MPlayerSetup.ResumeMode = atoi(Value); nathan@0: else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6])) nathan@0: strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0])); nathan@0: else return false; nathan@0: return true; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::ExternalPlay(const char *path, bool test) nathan@0: { nathan@0: char real[PATH_MAX+1]; nathan@0: if(realpath(path,real)) { nathan@0: cFileSource *src=MPlaySources.FindSource(real); nathan@0: if(src) { nathan@0: cFileObj *item=new cFileObj(src,0,0,otFile); nathan@0: if(item) { nathan@0: item->SplitAndSet(real); nathan@0: if(item->GuessType()) { nathan@0: if(item->Exists()) { nathan@0: if(!test) { nathan@0: cMPlayerControl::SetFile(item,true); nathan@0: cControl::Launch(new cMPlayerControl); nathan@0: cControl::Attach(); nathan@0: } nathan@0: delete item; nathan@0: return true; nathan@0: } nathan@0: else dsyslog("MPlayer service: cannot play '%s'",path); nathan@0: } nathan@0: else dsyslog("MPlayer service: GuessType() failed for '%s'",path); nathan@0: delete item; nathan@0: } nathan@0: } nathan@0: else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real); nathan@0: } nathan@0: else if(errno!=ENOENT && errno!=ENOTDIR) nathan@0: esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); nathan@0: return false; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::Service(const char *Id, void *Data) nathan@0: { nathan@0: if(!strcasecmp(Id,"MPlayer-Play-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,false); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: else if(!strcasecmp(Id,"MPlayer-Test-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,true); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: return false; nathan@0: } nathan@0: nathan@0: const char **cPluginMPlayer::SVDRPHelpPages(void) nathan@0: { nathan@0: static const char *HelpPages[] = { nathan@0: "PLAY \n" nathan@0: " Triggers playback of file 'filename'.", nathan@0: "TEST \n" nathan@0: " Tests is playback of file 'filename' is possible.", nathan@0: NULL nathan@0: }; nathan@0: return HelpPages; nathan@0: } nathan@0: nathan@0: cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) nathan@0: { nathan@0: if(!strcasecmp(Command,"PLAY")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,false)) return "Playback triggered"; nathan@0: else { ReplyCode=550; return "Playback failed"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: else if(!strcasecmp(Command,"TEST")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,true)) return "Playback possible"; nathan@0: else { ReplyCode=550; return "Playback not possible"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: return NULL; nathan@0: } nathan@0: nathan@0: VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!