2 * MP3/MPlayer plugin to VDR (C++)
4 * (C) 2001-2007 Stefan Huelswitt <s.huelswitt@gmx.de>
6 * This code is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This code is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
29 #include <vdr/plugin.h>
30 #include <vdr/player.h>
31 #include <vdr/status.h>
33 #include <vdr/osdbase.h>
34 #include <vdr/menuitems.h>
35 #ifdef HAVE_BEAUTYPATCH
36 #include <vdr/fontsym.h>
38 #if APIVERSNUM >= 10307
39 #include <vdr/skins.h>
41 #if APIVERSNUM >= 10332
42 #include <vdr/remote.h>
45 #if APIVERSNUM > 10307
47 #elif APIVERSNUM == 10307
48 class cMenuText : public cOsdMenu {
52 cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
54 void SetText(const char *Text);
55 virtual void Display(void);
56 virtual eOSState ProcessKey(eKeys Key);
59 class cMenuText : public cOsdMenu {
61 cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
62 virtual eOSState ProcessKey(eKeys Key);
67 #include "setup-mplayer.h"
69 #include "player-mplayer.h"
76 const char *sourcesSub=0;
77 cFileSources MPlaySources;
79 static const char *plugin_name=0;
81 // --- cMenuSetupMPlayer --------------------------------------------------------
83 class cMenuSetupMPlayer : public cMenuSetupPage {
88 virtual void Store(void);
90 cMenuSetupMPlayer(void);
93 cMenuSetupMPlayer::cMenuSetupMPlayer(void)
96 SetSection(tr("MPlayer"));
97 Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"), &data.SlaveMode, tr("Traditional"), tr("Slave")));
98 #if APIVERSNUM < 10307
99 Add(new cMenuEditIntItem( tr("Setup.MPlayer$OSD position"), &data.OsdPos, 0, 6));
101 res[0]=tr("disabled");
102 res[1]=tr("global only");
103 res[2]=tr("local first");
104 Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"), &data.ResumeMode, 3, res));
105 Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu));
106 for(int i=0; i<10; i++) {
108 snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i);
109 static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" };
110 Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed));
114 void cMenuSetupMPlayer::Store(void)
117 SetupStore("ControlMode", MPlayerSetup.SlaveMode);
118 SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu);
119 SetupStore("ResumeMode", MPlayerSetup.ResumeMode);
120 #if APIVERSNUM < 10307
121 SetupStore("OsdPos", MPlayerSetup.OsdPos);
123 for(int i=0; i<10; i++) {
125 snprintf(name,sizeof(name),"KeyCmd%d",i);
126 SetupStore(name,MPlayerSetup.KeyCmd[i]);
130 // --- cMPlayerControl ---------------------------------------------------------
132 class cMPlayerControl : public cControl {
134 static cFileObj *file;
136 cMPlayerPlayer *player;
137 #if APIVERSNUM >= 10307
138 cSkinDisplayReplay *display;
140 bool visible, modeOnly, haveBeauty;
142 int lastCurrent, lastTotal;
145 bool jumpactive, jumphide, jumpmode;
149 void ShowTimed(int Seconds=0);
150 void DisplayAtBottom(const char *s);
151 void ShowProgress(void);
153 void ShowTitle(void);
155 void JumpProcess(eKeys Key);
156 void JumpDisplay(void);
158 cMPlayerControl(void);
159 virtual ~cMPlayerControl();
160 virtual eOSState ProcessKey(eKeys Key);
161 virtual void Show(void) { ShowTimed(); }
162 virtual void Hide(void);
163 static void SetFile(const cFileObj *File, bool Rewind);
166 cFileObj *cMPlayerControl::file=0;
167 bool cMPlayerControl::rewind=false;
169 cMPlayerControl::cMPlayerControl(void)
170 :cControl(player=new cMPlayerPlayer(file,rewind))
172 visible=modeOnly=jumpactive=haveBeauty=false;
174 #if APIVERSNUM >= 10307
177 #ifdef HAVE_BEAUTYPATCH
178 #if APIVERSNUM >= 10300
179 const cFont *sym=cFont::GetFont(fontSym);
180 const cFont *osd=cFont::GetFont(fontOsd);
181 const cFont::tCharData *symD=sym->CharData(32);
182 const cFont::tCharData *osdD=osd->CharData(32);
183 #else //APIVERSNUM >= 10300
184 cFont *sym=new cFont(fontSym);
185 cFont *osd=new cFont(fontOsd);
186 const cFont::tCharData *symD=sym->CharData(32);
187 const cFont::tCharData *osdD=osd->CharData(32);
190 #endif //APIVERSNUM >= 10300
191 if(symD != osdD) haveBeauty=true;
192 d(printf("mplayer: beauty patch %sdetected\n",haveBeauty?"":"NOT "))
193 #endif //HAVE_BEAUTYPATCH
194 #endif //APIVERSNUM >= 10307
198 cMPlayerControl::~cMPlayerControl()
201 #if APIVERSNUM >= 10338
202 cStatus::MsgReplaying(this,0,0,false);
204 cStatus::MsgReplaying(this, NULL);
209 void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind)
212 file=File ? new cFileObj(File) : 0;
216 void cMPlayerControl::Stop(void)
218 delete player; player=0;
221 void cMPlayerControl::ShowTimed(int Seconds)
226 timeoutShow = Seconds>0 ? time(0)+Seconds : 0;
230 void cMPlayerControl::Hide(void)
233 #if APIVERSNUM >= 10307
234 delete display; display=0;
238 visible=modeOnly=false;
239 #if APIVERSNUM >= 10500
240 SetNeedsFastResponse(false);
242 needsFastResponse=false;
247 void cMPlayerControl::DisplayAtBottom(const char *s)
249 #if APIVERSNUM < 10307
250 const int p=modeOnly ? 0 : 2;
252 const int d=max(Width()-cOsd::WidthInCells(s),0) / 2;
253 if(modeOnly) Interface->Fill(0, p, Interface->Width(), 1, clrTransparent);
254 Interface->Write(d, p, s);
257 Interface->Fill(12, p, Width() - 22, 1, clrBackground);
261 void cMPlayerControl::ShowTitle(void)
265 if(player) path=player->GetCurrentName();
267 path=file->FullPath();
271 const char *name=rindex(path,'/');
272 if(name) name++; else name=path;
273 if(!lastReplayMsg || strcmp(lastReplayMsg,path)) {
274 #if APIVERSNUM >= 10338
275 cStatus::MsgReplaying(this,name,path,true);
277 cStatus::MsgReplaying(this,path);
280 lastReplayMsg=strdup(path);
283 #if APIVERSNUM >= 10307
284 if(display) display->SetTitle(name);
288 n=n-Width()+4; if(n<0) n=0;
290 snprintf(str,sizeof(str),"... %s",name+n);
291 Interface->Write(0,0,str);
293 else Interface->Write(0,0,name);
297 if(release) free((void *)path);
300 void cMPlayerControl::ShowProgress(void)
304 if(GetIndex(Current,Total) && Total>0) {
307 #if APIVERSNUM >= 10307
308 display=Skins.Current()->DisplayReplay(false);
310 Interface->Open(Setup.OSDwidth,-MPlayerSetup.OsdPos-3);
312 if(MPlayerSetup.OsdPos>0) Interface->Fill(0,3,Interface->Width(),MPlayerSetup.OsdPos,clrTransparent);
314 visible=true; modeOnly=false;
315 #if APIVERSNUM >= 10500
316 SetNeedsFastResponse(true);
318 needsFastResponse=true;
320 lastCurrent=lastTotal=-1;
324 if(abs(Current-lastCurrent)>12) {
325 #if APIVERSNUM >= 10307
326 if(Total>0) display->SetProgress(Current, Total);
327 display->SetCurrent(IndexToHMSF(Current));
328 display->SetTotal(IndexToHMSF(Total));
331 if(GetReplayMode(Play,Forward,Speed))
332 display->SetMode(Play, Forward, Speed);
334 cProgressBar ProgressBar(Width() * cOsd::CellWidth(), cOsd::LineHeight(), Current, Total);
335 Interface->SetBitmap(0, cOsd::LineHeight(), ProgressBar);
336 Interface->Write(0,2,IndexToHMSF(Current));
337 Interface->Write(-7,2,IndexToHMSF(Total));
341 lastCurrent=Current; lastTotal=Total;
344 #if APIVERSNUM >= 10307
353 #if APIVERSNUM < 10307
354 #ifdef HAVE_BEAUTYPATCH
355 int forwSym[] = { FSYM_FORW,FSYM_FORW1,FSYM_FORW2,FSYM_FORW3 };
356 int backSym[] = { FSYM_BACK,FSYM_BACK1,FSYM_BACK2,FSYM_BACK3 };
360 void cMPlayerControl::ShowMode(void)
362 if(Setup.ShowReplayMode && !jumpactive) {
365 if(GetReplayMode(Play, Forward, Speed)) {
366 bool NormalPlay = (Play && Speed == -1);
369 if(NormalPlay) return;
370 #if APIVERSNUM >= 10307
371 display = Skins.Current()->DisplayReplay(true);
373 Interface->Open(0,-MPlayerSetup.OsdPos-1);
375 visible=modeOnly=true;
378 if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
380 #if APIVERSNUM >= 10307
381 display->SetMode(Play, Forward, Speed);
385 #ifdef HAVE_BEAUTYPATCH
388 if(!(Width()&1)) buf[i++]=' ';
389 buf[i]=FSYM_EMPTY; if(Speed>=0 && !Forward) buf[i]=backSym[Speed];
391 buf[i++]=Play?(Speed==-1?FSYM_PLAY:FSYM_EMPTY):FSYM_PAUSE;
392 buf[i]=FSYM_EMPTY; if(Speed>=0 && Forward) buf[i]=forwSym[Speed];
394 if(!(Width()&1)) buf[i++]=' ';
396 OldFont = Interface->SetFont(fontSym);
399 #endif //HAVE_BEAUTYPATCH
401 if (Speed == -1) Mode = Play ? " > " : " || ";
402 else if (Play) Mode = Forward ? " X>> " : " <<X ";
403 else Mode = Forward ? " X|> " : " <|X ";
404 strn0cpy(buf, Mode, sizeof(buf));
405 char *p = strchr(buf, 'X');
406 if(p) *p = Speed > 0 ? '1' + Speed - 1 : ' ';
407 OldFont = Interface->SetFont(fontFix);
408 #ifdef HAVE_BEAUTYPATCH
410 #endif //HAVE_BEAUTYPATCH
411 DisplayAtBottom(buf);
412 Interface->SetFont(OldFont);
413 #endif //APIVERSNUM >= 10307
418 void cMPlayerControl::JumpDisplay(void)
421 const char *j=trVDR("Jump: "), u=jumpmode?'%':'m';
422 if(!jumpval) sprintf(buf,"%s- %c", j,u);
423 else sprintf(buf,"%s%d- %c",j,jumpval,u);
424 #if APIVERSNUM >= 10307
425 display->SetJump(buf);
427 DisplayAtBottom(buf);
431 void cMPlayerControl::JumpProcess(eKeys Key)
437 const int max=jumpmode?100:lastTotal;
438 if(jumpval*10+n <= max) jumpval=jumpval*10+n;
443 jumpmode=!jumpmode; jumpval=0;
444 DisplayAtBottom(0); JumpDisplay();
448 player->Goto(jumpval*(jumpmode?1:60),jumpmode,false);
456 player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1));
468 #if APIVERSNUM >= 10307
476 void cMPlayerControl::Jump(void)
478 jumpval=0; jumphide=jumpmode=false;
480 ShowTimed(); if(!visible) return;
487 eOSState cMPlayerControl::ProcessKey(eKeys Key)
489 if(!player->Active()) { Hide(); Stop(); return osEnd; }
491 if(!player->SlaveMode()) {
492 if(Key==kBlue) { Hide(); Stop(); return osEnd; }
496 if(timeoutShow && time(0)>timeoutShow) {
501 if(modeOnly) ShowMode();
507 if(jumpactive && Key != kNone) {
512 bool DoShowMode = true;
515 case kUp: player->Play(); break;
518 case kDown: player->Pause(); break;
520 case kFastRew|k_Repeat:
523 case kLeft: player->SkipSeconds(-10); break;
525 case kFastFwd|k_Repeat:
527 case kRight|k_Repeat:
528 case kRight: player->SkipSeconds(10); break;
530 case kRed: Jump(); break;
532 case kGreen|k_Repeat: // temporary use
533 case kGreen: player->SkipSeconds(-60); break;
534 case kYellow|k_Repeat:
535 case kYellow: player->SkipSeconds(60); break;
536 // case kGreen|k_Repeat: // reserved for future use
537 // case kGreen: player->SkipPrev(); break;
538 // case kYellow|k_Repeat:
539 // case kYellow: player->SkipNext(); break;
542 #if APIVERSNUM >= 10332
544 cRemote::CallPlugin(plugin_name);
548 case kBlue: Hide(); Stop(); return osEnd;
553 case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; }
566 const char *cmd=MPlayerSetup.KeyCmd[Key-k0];
567 if(cmd[0]) player->KeyCmd(cmd);
575 if(DoShowMode) ShowMode();
580 // --- cMenuMPlayAid -----------------------------------------------------------
582 class cMenuMPlayAid : public cOsdMenu {
585 virtual eOSState ProcessKey(eKeys Key);
588 cMenuMPlayAid::cMenuMPlayAid(void)
589 :cOsdMenu(tr("MPlayer Audio ID"),20)
591 Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255));
595 eOSState cMenuMPlayAid::ProcessKey(eKeys Key)
597 eOSState state=cOsdMenu::ProcessKey(Key);
598 if(state==osUnknown) {
600 case kOk: state=osBack; break;
607 // --- cMenuMPlayBrowse ---------------------------------------------------------
609 class cMenuMPlayBrowse : public cMenuBrowse {
611 bool sourcing, aidedit;
612 eOSState Source(bool second);
613 eOSState Summary(void);
615 virtual void SetButtons(void);
617 cMenuMPlayBrowse(void);
618 virtual eOSState ProcessKey(eKeys Key);
621 static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 };
623 cMenuMPlayBrowse::cMenuMPlayBrowse(void)
624 :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum)
626 sourcing=aidedit=false;
630 void cMenuMPlayBrowse::SetButtons(void)
632 static char blue[12];
633 snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid);
634 SetHelp(trVDR(BUTTON"Play"), MPlayerSetup.ResumeMode ? trVDR(BUTTON"Rewind"):0, tr("Source"), blue);
638 eOSState cMenuMPlayBrowse::Source(bool second)
640 if(HasSubMenu()) return osContinue;
644 return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source")));
647 cFileSource *src=cMenuSource::GetSelected();
649 MPlaySources.SetSource(src);
656 eOSState cMenuMPlayBrowse::Summary(void)
658 cFileObj *item=CurrentItem();
659 if(item && item->Type()==otFile) {
660 static const char *exts[] = { ".summary",".txt",".nfo",0 };
661 for(int i=0; exts[i]; i++) {
663 strn0cpy(buff,item->FullPath(),sizeof(buff)-20);
664 char *e=&buff[strlen(buff)];
665 strn0cpy(e,exts[i],20);
666 int fd=open(buff,O_RDONLY);
668 if(fd<0 && (e=rindex(buff,'.'))) {
669 strn0cpy(e,exts[i],20);
670 fd=open(buff,O_RDONLY);
673 int r=read(fd,buff,sizeof(buff)-1);
677 return AddSubMenu(new cMenuText(tr("Summary"),buff));
685 eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key)
687 eOSState state=cOsdMenu::ProcessKey(Key);
688 if(state==osContinue && !HasSubMenu()) {
689 if(sourcing) return Source(true);
690 if(aidedit) { aidedit=false; SetButtons(); }
693 if(state==osUnknown) {
697 cFileObj *item=CurrentItem();
698 if(item && item->Type()==otFile) {
699 lastselect=new cFileObj(item);
703 else state=osContinue;
711 state=AddSubMenu(new cMenuMPlayAid);
720 if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
721 if(state==osBack && lastselect) {
722 cMPlayerControl::SetFile(lastselect,rew);
723 cControl::Launch(new cMPlayerControl);
729 // --- cPluginMPlayer ----------------------------------------------------------
731 static const char *VERSION = PLUGIN_VERSION;
732 static const char *DESCRIPTION = trNOOP("Media replay via MPlayer");
733 static const char *MAINMENUENTRY = "MPlayer";
735 class cPluginMPlayer : public cPlugin {
737 #if APIVERSNUM >= 10330
738 bool ExternalPlay(const char *path, bool test);
741 cPluginMPlayer(void);
742 virtual ~cPluginMPlayer();
743 virtual const char *Version(void) { return VERSION; }
744 virtual const char *Description(void) { return tr(DESCRIPTION); }
745 virtual const char *CommandLineHelp(void);
746 virtual bool ProcessArgs(int argc, char *argv[]);
747 #if APIVERSNUM >= 10131
748 virtual bool Initialize(void);
750 virtual bool Start(void);
752 virtual const char *MainMenuEntry(void);
753 virtual cOsdMenu *MainMenuAction(void);
754 virtual cMenuSetupPage *SetupMenu(void);
755 virtual bool SetupParse(const char *Name, const char *Value);
756 #if APIVERSNUM >= 10330
757 virtual bool Service(const char *Id, void *Data);
758 #if APIVERSNUM >= 10331
759 virtual const char **SVDRPHelpPages(void);
760 virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
765 cPluginMPlayer::cPluginMPlayer(void)
767 // Initialize any member variables here.
768 // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
769 // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
773 cPluginMPlayer::~cPluginMPlayer()
778 const char *cPluginMPlayer::CommandLineHelp(void)
780 static char *help_str=0;
782 free(help_str); // for easier orientation, this is column 80|
783 asprintf(&help_str," -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n"
785 " -M CMD, --mplayer=CMD use CMD when calling MPlayer\n"
787 " -S SUB, --sources=SUB search sources config in SUB subdirectory\n"
789 " -R DIR, --resume=DIR store global resume file in DIR\n"
793 sourcesSub ? sourcesSub:"none",
794 globalResumeDir ? globalResumeDir:"video dir"
799 bool cPluginMPlayer::ProcessArgs(int argc, char *argv[])
801 static struct option long_options[] = {
802 { "mount", required_argument, NULL, 'm' },
803 { "mplayer", required_argument, NULL, 'M' },
804 { "sources", required_argument, NULL, 'S' },
805 { "resume", required_argument, NULL, 'R' },
809 int c, option_index = 0;
810 while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) {
812 case 'm': mountscript=optarg; break;
813 case 'M': MPlayerCmd=optarg; break;
814 case 'S': sourcesSub=optarg; break;
815 case 'R': globalResumeDir=optarg; break;
816 default: return false;
822 #if APIVERSNUM >= 10131
823 bool cPluginMPlayer::Initialize(void)
825 bool cPluginMPlayer::Start(void)
828 if(!CheckVDRVersion(1,1,16,"mplayer")) return false;
829 plugin_name="mplayer";
830 #if APIVERSNUM < 10507
833 i18n_name="vdr-mplayer";
835 MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf"));
836 if(MPlaySources.Count()<1) {
837 esyslog("ERROR: you must have defined at least one source in mplayersources.conf");
838 fprintf(stderr,"No source(s) defined in mplayersources.conf\n");
841 #if APIVERSNUM < 10507
842 RegisterI18n(Phrases);
844 if(!(status=new cMPlayerStatus)) return false;
848 const char *cPluginMPlayer::MainMenuEntry(void)
850 return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
853 cOsdMenu *cPluginMPlayer::MainMenuAction(void)
855 return new cMenuMPlayBrowse;
858 cMenuSetupPage *cPluginMPlayer::SetupMenu(void)
860 return new cMenuSetupMPlayer;
863 bool cPluginMPlayer::SetupParse(const char *Name, const char *Value)
865 if( !strcasecmp(Name, "ControlMode")) MPlayerSetup.SlaveMode = atoi(Value);
866 else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value);
867 else if (!strcasecmp(Name, "ResumeMode")) MPlayerSetup.ResumeMode = atoi(Value);
868 else if (!strcasecmp(Name, "OsdPos")) MPlayerSetup.OsdPos = atoi(Value);
869 else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
870 strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
875 #if APIVERSNUM >= 10330
877 bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
879 char real[PATH_MAX+1];
880 if(realpath(path,real)) {
881 cFileSource *src=MPlaySources.FindSource(real);
883 cFileObj *item=new cFileObj(src,0,0,otFile);
885 item->SplitAndSet(real);
886 if(item->GuessType()) {
889 cMPlayerControl::SetFile(item,true);
890 cControl::Launch(new cMPlayerControl);
896 else dsyslog("MPlayer service: cannot play '%s'",path);
898 else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
902 else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
904 else if(errno!=ENOENT && errno!=ENOTDIR)
905 esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
909 bool cPluginMPlayer::Service(const char *Id, void *Data)
911 if(!strcasecmp(Id,"MPlayer-Play-v1")) {
913 struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
914 msd->result=ExternalPlay(msd->data.filename,false);
918 else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
920 struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
921 msd->result=ExternalPlay(msd->data.filename,true);
928 #if APIVERSNUM >= 10331
930 const char **cPluginMPlayer::SVDRPHelpPages(void)
932 static const char *HelpPages[] = {
934 " Triggers playback of file 'filename'.",
936 " Tests is playback of file 'filename' is possible.",
942 cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
944 if(!strcasecmp(Command,"PLAY")) {
946 if(ExternalPlay(Option,false)) return "Playback triggered";
947 else { ReplyCode=550; return "Playback failed"; }
949 else { ReplyCode=501; return "Missing filename"; }
951 else if(!strcasecmp(Command,"TEST")) {
953 if(ExternalPlay(Option,true)) return "Playback possible";
954 else { ReplyCode=550; return "Playback not possible"; }
956 else { ReplyCode=501; return "Missing filename"; }
964 VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!