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