mplayer.c
author nathan
Wed, 04 Feb 2009 12:30:14 +0800
branchtrunk
changeset 23 3b14b8aacaa0
parent 22 93aaf15c145a
child 24 0598c933ccae
permissions -rw-r--r--
remove unecessary compatibility code
     1 /*
     2  * MP3/MPlayer plugin to VDR (C++)
     3  *
     4  * (C) 2001-2009 Stefan Huelswitt <s.huelswitt@gmx.de>
     5  *
     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.
    10  *
    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.
    15  *
    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
    20  */
    21 
    22 #include <getopt.h>
    23 #include <malloc.h>
    24 #include <stdlib.h>
    25 #include <ctype.h>
    26 
    27 #include "common.h"
    28 
    29 #include <vdr/plugin.h>
    30 #include <vdr/player.h>
    31 #include <vdr/status.h>
    32 #include <vdr/font.h>
    33 #include <vdr/osdbase.h>
    34 #include <vdr/menuitems.h>
    35 #include <vdr/skins.h>
    36 #include <vdr/remote.h>
    37 #include <vdr/menu.h>
    38 
    39 #include "setup.h"
    40 #include "setup-mplayer.h"
    41 #include "menu.h"
    42 #include "player-mplayer.h"
    43 #include "data.h"
    44 #include "data-src.h"
    45 #include "i18n.h"
    46 #include "version.h"
    47 #include "service.h"
    48 
    49 const char *sourcesSub=0;
    50 cFileSources MPlaySources;
    51 
    52 static const char *plugin_name=0;
    53 const char *i18n_name=0;
    54 
    55 // --- cMenuSetupMPlayer --------------------------------------------------------
    56 
    57 class cMenuSetupMPlayer : public cMenuSetupPage {
    58 private:
    59   cMPlayerSetup data;
    60   const char *res[3];
    61 protected:
    62   virtual void Store(void);
    63 public:
    64   cMenuSetupMPlayer(void);
    65   };
    66 
    67 cMenuSetupMPlayer::cMenuSetupMPlayer(void)
    68 {
    69   data=MPlayerSetup;
    70   SetSection(tr("MPlayer"));
    71   Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"),  &data.SlaveMode, tr("Traditional"), tr("Slave")));
    72   res[0]=tr("disabled");
    73   res[1]=tr("global only");
    74   res[2]=tr("local first");
    75   Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"),   &data.ResumeMode, 3, res));
    76   Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"),         &data.HideMainMenu));
    77   for(int i=0; i<10; i++) {
    78     char name[32];
    79     snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i);
    80     static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" };
    81     Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed));
    82     }
    83 }
    84 
    85 void cMenuSetupMPlayer::Store(void)
    86 {
    87   MPlayerSetup=data;
    88   SetupStore("ControlMode", MPlayerSetup.SlaveMode);
    89   SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu);
    90   SetupStore("ResumeMode",  MPlayerSetup.ResumeMode);
    91   for(int i=0; i<10; i++) {
    92     char name[16];
    93     snprintf(name,sizeof(name),"KeyCmd%d",i);
    94     SetupStore(name,MPlayerSetup.KeyCmd[i]);
    95     }
    96 }
    97 
    98 // --- cMPlayerControl ---------------------------------------------------------
    99 
   100 class cMPlayerControl : public cControl {
   101 private:
   102   static cFileObj *file;
   103   static bool rewind;
   104   cMPlayerPlayer *player;
   105   cSkinDisplayReplay *display;
   106   bool visible, modeOnly, haveBeauty;
   107   time_t timeoutShow;
   108   int lastCurrent, lastTotal;
   109   char *lastReplayMsg;
   110   //
   111   bool jumpactive, jumphide, jumpmode;
   112   int jumpval;
   113   //
   114   void Stop(void);
   115   void ShowTimed(int Seconds=0);
   116   void ShowProgress(void);
   117   void ShowMode(void);
   118   void ShowTitle(void);
   119   void Jump(void);
   120   void JumpProcess(eKeys Key);
   121   void JumpDisplay(void);
   122 public:
   123   cMPlayerControl(void);
   124   virtual ~cMPlayerControl();
   125   virtual eOSState ProcessKey(eKeys Key);
   126   virtual void Show(void) { ShowTimed(); }
   127   virtual void Hide(void);
   128   static void SetFile(const cFileObj *File, bool Rewind);
   129   };
   130 
   131 cFileObj *cMPlayerControl::file=0;
   132 bool cMPlayerControl::rewind=false;
   133 
   134 cMPlayerControl::cMPlayerControl(void)
   135 :cControl(player=new cMPlayerPlayer(file,rewind))
   136 {
   137   visible=modeOnly=jumpactive=haveBeauty=false;
   138   lastReplayMsg=0;
   139   display=0;
   140   ShowTitle();
   141 }
   142 
   143 cMPlayerControl::~cMPlayerControl()
   144 {
   145   Stop();
   146   cStatus::MsgReplaying(this,0,0,false);
   147   free(lastReplayMsg);
   148 }
   149 
   150 void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind)
   151 {
   152   delete file;
   153   file=File ? new cFileObj(File) : 0;
   154   rewind=Rewind;
   155 }
   156 
   157 void cMPlayerControl::Stop(void)
   158 {
   159   delete player; player=0;
   160 }
   161 
   162 void cMPlayerControl::ShowTimed(int Seconds)
   163 {
   164   if(modeOnly) Hide();
   165   if(!visible) {
   166     ShowProgress();
   167     timeoutShow = Seconds>0 ? time(0)+Seconds : 0;
   168     }
   169 }
   170 
   171 void cMPlayerControl::Hide(void)
   172 {
   173   if(visible) {
   174     delete display; display=0;
   175     visible=modeOnly=false;
   176 #if APIVERSNUM >= 10500
   177     SetNeedsFastResponse(false);
   178 #else
   179     needsFastResponse=false;
   180 #endif
   181     }
   182 }
   183 
   184 void cMPlayerControl::ShowTitle(void)
   185 {
   186   const char *path=0;
   187   bool release=true;
   188   if(player) path=player->GetCurrentName();
   189   if(!path) {
   190     path=file->FullPath();
   191     release=false;
   192     }
   193   if(path) {
   194     const char *name=rindex(path,'/');
   195     if(name) name++; else name=path;
   196     if(!lastReplayMsg || strcmp(lastReplayMsg,path)) {
   197       cStatus::MsgReplaying(this,name,path,true);
   198       free(lastReplayMsg);
   199       lastReplayMsg=strdup(path);
   200       }
   201     if(visible) {
   202       if(display) display->SetTitle(name);
   203       }
   204     }
   205   if(release) free((void *)path);
   206 }
   207 
   208 void cMPlayerControl::ShowProgress(void)
   209 {
   210   int Current, Total;
   211 
   212   if(GetIndex(Current,Total) && Total>0) {
   213     bool flush=false;
   214     if(!visible) {
   215       display=Skins.Current()->DisplayReplay(false);
   216       visible=true; modeOnly=false;
   217 #if APIVERSNUM >= 10500
   218       SetNeedsFastResponse(true);
   219 #else
   220       needsFastResponse=true;
   221 #endif
   222       lastCurrent=lastTotal=-1;
   223       flush=true;
   224       }
   225 
   226     if(abs(Current-lastCurrent)>12) {
   227       if(Total>0) display->SetProgress(Current, Total);
   228       display->SetCurrent(IndexToHMSF(Current));
   229       display->SetTotal(IndexToHMSF(Total));
   230       bool Play, Forward;
   231       int Speed;
   232       if(GetReplayMode(Play,Forward,Speed)) 
   233         display->SetMode(Play, Forward, Speed);
   234       ShowTitle();
   235       flush=true;
   236       lastCurrent=Current; lastTotal=Total;
   237       }
   238     if(flush) 
   239       Skins.Flush();
   240     ShowMode();
   241     }
   242 }
   243 
   244 void cMPlayerControl::ShowMode(void)
   245 {
   246   if(Setup.ShowReplayMode && !jumpactive) {
   247     bool Play, Forward;
   248     int Speed;
   249     if(GetReplayMode(Play, Forward, Speed)) {
   250        bool NormalPlay = (Play && Speed == -1);
   251 
   252        if(!visible) {
   253          if(NormalPlay) return;
   254          display = Skins.Current()->DisplayReplay(true);
   255          visible=modeOnly=true;
   256          }
   257 
   258        if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
   259 
   260        display->SetMode(Play, Forward, Speed);
   261        }
   262     }
   263 }
   264 
   265 void cMPlayerControl::JumpDisplay(void)
   266 {
   267   char buf[64];
   268   const char *j=trVDR("Jump: "), u=jumpmode?'%':'m';
   269   if(!jumpval) sprintf(buf,"%s- %c",  j,u);
   270   else         sprintf(buf,"%s%d- %c",j,jumpval,u);
   271   display->SetJump(buf);
   272 }
   273 
   274 void cMPlayerControl::JumpProcess(eKeys Key)
   275 {
   276   const int n=Key-k0;
   277   switch (Key) {
   278     case k0 ... k9:
   279       {
   280       const int max=jumpmode?100:lastTotal;
   281       if(jumpval*10+n <= max) jumpval=jumpval*10+n;
   282       JumpDisplay();
   283       }
   284       break;
   285     case kBlue:
   286       jumpmode=!jumpmode; jumpval=0;
   287       JumpDisplay();
   288       break;
   289     case kPlay:
   290     case kUp:
   291       player->Goto(jumpval*(jumpmode?1:60),jumpmode,false);
   292       jumpactive=false;
   293       break;
   294     case kFastRew:
   295     case kFastFwd:
   296     case kLeft:
   297     case kRight:
   298       if(!jumpmode) {
   299         player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1));
   300         jumpactive=false;
   301         }
   302       break;
   303     default:
   304       jumpactive=false;
   305       break;
   306     }
   307 
   308   if(!jumpactive) {
   309     if(jumphide) Hide();
   310     else 
   311       display->SetJump(0);
   312     }
   313 }
   314 
   315 void cMPlayerControl::Jump(void)
   316 {
   317   jumpval=0; jumphide=jumpmode=false;
   318   if(!visible) {
   319     ShowTimed(); if(!visible) return;
   320     jumphide=true;
   321     }
   322   JumpDisplay();
   323   jumpactive=true;
   324 }
   325 
   326 eOSState cMPlayerControl::ProcessKey(eKeys Key)
   327 {
   328   if(!player->Active()) { Hide(); Stop(); return osEnd; }
   329 
   330   if(!player->SlaveMode()) {
   331     if(Key==kBlue) { Hide(); Stop(); return osEnd; }
   332     }
   333   else {
   334     if(visible) {
   335       if(timeoutShow && time(0)>timeoutShow) {
   336         Hide(); ShowMode();
   337         timeoutShow = 0;
   338         }
   339       else {
   340         if(modeOnly) ShowMode();
   341         else ShowProgress();
   342         }
   343       }
   344     else ShowTitle();
   345 
   346     if(jumpactive && Key != kNone) {
   347       JumpProcess(Key);
   348       return osContinue;
   349       }
   350 
   351     bool DoShowMode = true;
   352     switch (Key) {
   353       case kPlay:
   354       case kUp:      player->Play(); break;
   355 
   356       case kPause:
   357       case kDown:    player->Pause(); break;
   358 
   359       case kFastRew|k_Repeat:
   360       case kFastRew:
   361       case kLeft|k_Repeat:
   362       case kLeft:    player->SkipSeconds(-10); break;
   363 
   364       case kFastFwd|k_Repeat:
   365       case kFastFwd:
   366       case kRight|k_Repeat:
   367       case kRight:   player->SkipSeconds(10); break;
   368 
   369       case kRed:     Jump(); break;
   370 
   371       case kGreen|k_Repeat:                      // temporary use
   372       case kGreen:   player->SkipSeconds(-60); break;
   373       case kYellow|k_Repeat:
   374       case kYellow:  player->SkipSeconds(60); break;
   375   //    case kGreen|k_Repeat:                      // reserved for future use
   376   //    case kGreen:   player->SkipPrev(); break;
   377   //    case kYellow|k_Repeat:
   378   //    case kYellow:  player->SkipNext(); break;
   379 
   380       case kBack:
   381                      Hide();
   382                      cRemote::CallPlugin(plugin_name);
   383                      return osBack;
   384       case kStop:
   385       case kBlue:    Hide(); Stop(); return osEnd;
   386 
   387       default:
   388         DoShowMode = false;
   389         switch(Key) {
   390           case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; }
   391                     else ShowTimed();
   392                     break;
   393           case kAudio:
   394                     player->KeyCmd("switch_audio");
   395                     break;
   396           case k0:
   397           case k1:
   398           case k2:
   399           case k3:
   400           case k4:
   401           case k5:
   402           case k6:
   403           case k7:
   404           case k8:
   405           case k9:  {
   406                     const char *cmd=MPlayerSetup.KeyCmd[Key-k0];
   407                     if(cmd[0]) player->KeyCmd(cmd);
   408                     }
   409                     break;
   410           default:  break;
   411           }
   412         break;
   413       }
   414 
   415     if(DoShowMode) ShowMode();
   416     }
   417   return osContinue;
   418 }
   419 
   420 // --- cMenuMPlayAid -----------------------------------------------------------
   421 
   422 class cMenuMPlayAid : public cOsdMenu {
   423 public:
   424   cMenuMPlayAid(void);
   425   virtual eOSState ProcessKey(eKeys Key);
   426   };
   427 
   428 cMenuMPlayAid::cMenuMPlayAid(void)
   429 :cOsdMenu(tr("MPlayer Audio ID"),20)
   430 {
   431   Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255));
   432   Display();
   433 }
   434 
   435 eOSState cMenuMPlayAid::ProcessKey(eKeys Key)
   436 {
   437   eOSState state=cOsdMenu::ProcessKey(Key);
   438   if(state==osUnknown) {
   439     switch(Key) {
   440       case kOk: state=osBack; break;
   441       default:  break;
   442       }
   443     }
   444   return state;
   445 }
   446 
   447 // --- cMenuMPlayBrowse ---------------------------------------------------------
   448 
   449 class cMenuMPlayBrowse : public cMenuBrowse {
   450 private:
   451   bool sourcing, aidedit;
   452   eOSState Source(bool second);
   453   eOSState Summary(void);
   454 protected:
   455   virtual void SetButtons(void);
   456 public:
   457   cMenuMPlayBrowse(void);
   458   virtual eOSState ProcessKey(eKeys Key);
   459   };
   460 
   461 static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 };
   462 
   463 cMenuMPlayBrowse::cMenuMPlayBrowse(void)
   464 :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum)
   465 {
   466   sourcing=aidedit=false;
   467   SetButtons();
   468 }
   469 
   470 void cMenuMPlayBrowse::SetButtons(void)
   471 {
   472   static char blue[12];
   473   snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid);
   474   SetHelp(trVDR("Button$Play"), MPlayerSetup.ResumeMode ? trVDR("Button$Rewind"):0, tr("Source"), blue);
   475   Display();
   476 }
   477 
   478 eOSState cMenuMPlayBrowse::Source(bool second)
   479 {
   480   if(HasSubMenu()) return osContinue;
   481 
   482   if(!second) {
   483     sourcing=true;
   484     return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source")));
   485     }
   486   sourcing=false;
   487   cFileSource *src=cMenuSource::GetSelected();
   488   if(src) {
   489     MPlaySources.SetSource(src);
   490     SetSource(src);
   491     NewDir(0);
   492     }
   493   return osContinue;
   494 }
   495 
   496 eOSState cMenuMPlayBrowse::Summary(void)
   497 {
   498   cFileObj *item=CurrentItem();
   499   if(item && item->Type()==otFile) {
   500     static const char *exts[] = { ".summary",".txt",".nfo",0 };
   501     for(int i=0; exts[i]; i++) {
   502       char buff[4096];
   503       strn0cpy(buff,item->FullPath(),sizeof(buff)-20);
   504       char *e=&buff[strlen(buff)];
   505       strn0cpy(e,exts[i],20);
   506       int fd=open(buff,O_RDONLY);
   507       *e=0;
   508       if(fd<0 && (e=rindex(buff,'.'))) {
   509         strn0cpy(e,exts[i],20);
   510         fd=open(buff,O_RDONLY);
   511         }
   512       if(fd>=0) {
   513         int r=read(fd,buff,sizeof(buff)-1);
   514         close(fd);
   515         if(r>0) {
   516           buff[r]=0;
   517           return AddSubMenu(new cMenuText(tr("Summary"),buff));
   518           }
   519         }
   520       }
   521     }
   522   return osContinue;
   523 }
   524 
   525 eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key)
   526 {
   527   eOSState state=cOsdMenu::ProcessKey(Key);
   528   if(state==osContinue && !HasSubMenu()) {
   529     if(sourcing) return Source(true);
   530     if(aidedit) { aidedit=false; SetButtons(); }
   531     }
   532   bool rew=false;
   533   if(state==osUnknown) {
   534     switch(Key) {
   535       case kGreen:
   536         {
   537         cFileObj *item=CurrentItem();
   538         if(item && item->Type()==otFile) {
   539           lastselect=new cFileObj(item);
   540           state=osBack;
   541           rew=true;
   542           } 
   543         else state=osContinue;
   544         break;
   545         }
   546       case kYellow:
   547         state=Source(false);
   548         break;
   549       case kBlue:
   550         aidedit=true;
   551         state=AddSubMenu(new cMenuMPlayAid);
   552         break;
   553       case k0:
   554         state=Summary();
   555         break;
   556       default:
   557         break;
   558       }
   559     }
   560   if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
   561   if(state==osBack && lastselect) {
   562     cMPlayerControl::SetFile(lastselect,rew);
   563     cControl::Launch(new cMPlayerControl);
   564     return osEnd;
   565     }
   566   return state;
   567 }
   568 
   569 // --- cPluginMPlayer ----------------------------------------------------------
   570 
   571 static const char *DESCRIPTION    = trNOOP("Media replay via MPlayer");
   572 static const char *MAINMENUENTRY  = "MPlayer";
   573 
   574 class cPluginMPlayer : public cPlugin {
   575 private:
   576   bool ExternalPlay(const char *path, bool test);
   577 public:
   578   cPluginMPlayer(void);
   579   virtual ~cPluginMPlayer();
   580   virtual const char *Version(void) { return PluginVersion; }
   581   virtual const char *Description(void) { return tr(DESCRIPTION); }
   582   virtual const char *CommandLineHelp(void);
   583   virtual bool ProcessArgs(int argc, char *argv[]);
   584   virtual bool Initialize(void);
   585   virtual const char *MainMenuEntry(void);
   586   virtual cOsdMenu *MainMenuAction(void);
   587   virtual cMenuSetupPage *SetupMenu(void);
   588   virtual bool SetupParse(const char *Name, const char *Value);
   589   virtual bool Service(const char *Id, void *Data);
   590   virtual const char **SVDRPHelpPages(void);
   591   virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
   592   };
   593 
   594 cPluginMPlayer::cPluginMPlayer(void)
   595 {
   596   // Initialize any member variables here.
   597   // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
   598   // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
   599   status=0;
   600 }
   601 
   602 cPluginMPlayer::~cPluginMPlayer()
   603 {
   604   delete status;
   605 }
   606 
   607 const char *cPluginMPlayer::CommandLineHelp(void)
   608 {
   609   static char *help_str=0;
   610   
   611   free(help_str);    //                                     for easier orientation, this is column 80|
   612   asprintf(&help_str,"  -m CMD,   --mount=CMD    use CMD to mount/unmount/eject mp3 sources\n"
   613                      "                           (default: %s)\n"
   614                      "  -M CMD,   --mplayer=CMD  use CMD when calling MPlayer\n"
   615                      "                           (default: %s)\n"
   616                      "  -S SUB,   --sources=SUB  search sources config in SUB subdirectory\n"
   617                      "                           (default: %s)\n"
   618                      "  -R DIR,   --resume=DIR   store global resume file in DIR\n"
   619                      "                           (default: %s)\n",
   620                      mountscript,
   621                      MPlayerCmd,
   622                      sourcesSub ? sourcesSub:"none",
   623                      globalResumeDir ? globalResumeDir:"video dir"
   624                      );
   625   return help_str;
   626 }
   627 
   628 bool cPluginMPlayer::ProcessArgs(int argc, char *argv[])
   629 {
   630   static struct option long_options[] = {
   631       { "mount",    required_argument, NULL, 'm' },
   632       { "mplayer",  required_argument, NULL, 'M' },
   633       { "sources",  required_argument, NULL, 'S' },
   634       { "resume",   required_argument, NULL, 'R' },
   635       { NULL }
   636     };
   637 
   638   int c, option_index = 0;
   639   while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) {
   640     switch (c) {
   641       case 'm': mountscript=optarg; break;
   642       case 'M': MPlayerCmd=optarg; break;
   643       case 'S': sourcesSub=optarg; break;
   644       case 'R': globalResumeDir=optarg; break;
   645       default:  return false;
   646       }
   647     }
   648   return true;
   649 }
   650 
   651 bool cPluginMPlayer::Initialize(void)
   652 {
   653   if(!CheckVDRVersion(1,4,5,"mplayer")) return false;
   654   plugin_name="mplayer";
   655 #if APIVERSNUM < 10507
   656   i18n_name="mplayer";
   657 #else
   658   i18n_name="vdr-mplayer";
   659 #endif
   660   MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf"));
   661   if(MPlaySources.Count()<1) {
   662     esyslog("ERROR: you must have defined at least one source in mplayersources.conf");
   663     fprintf(stderr,"No source(s) defined in mplayersources.conf\n");
   664     return false;
   665     }
   666 #if APIVERSNUM < 10507
   667   RegisterI18n(Phrases);
   668 #endif
   669   if(!(status=new cMPlayerStatus)) return false;
   670   return true;
   671 }
   672 
   673 const char *cPluginMPlayer::MainMenuEntry(void)
   674 {
   675   return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
   676 }
   677 
   678 cOsdMenu *cPluginMPlayer::MainMenuAction(void)
   679 {
   680   return new cMenuMPlayBrowse;
   681 }
   682 
   683 cMenuSetupPage *cPluginMPlayer::SetupMenu(void)
   684 {
   685   return new cMenuSetupMPlayer;
   686 }
   687 
   688 bool cPluginMPlayer::SetupParse(const char *Name, const char *Value)
   689 {
   690   if(      !strcasecmp(Name, "ControlMode"))  MPlayerSetup.SlaveMode    = atoi(Value);
   691   else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value);
   692   else if (!strcasecmp(Name, "ResumeMode"))   MPlayerSetup.ResumeMode   = atoi(Value);
   693   else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
   694     strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
   695   else return false;
   696   return true;
   697 }
   698 
   699 bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
   700 {
   701   char real[PATH_MAX+1];
   702   if(realpath(path,real)) {
   703     cFileSource *src=MPlaySources.FindSource(real);
   704     if(src) {
   705       cFileObj *item=new cFileObj(src,0,0,otFile);
   706       if(item) {
   707         item->SplitAndSet(real);
   708         if(item->GuessType()) {
   709           if(item->Exists()) {
   710             if(!test) {
   711               cMPlayerControl::SetFile(item,true);
   712               cControl::Launch(new cMPlayerControl);
   713               cControl::Attach();
   714               }
   715             delete item;
   716             return true;
   717             }
   718           else dsyslog("MPlayer service: cannot play '%s'",path);
   719           }
   720         else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
   721         delete item;
   722         }
   723       }
   724     else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
   725     }
   726   else if(errno!=ENOENT && errno!=ENOTDIR)
   727     esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
   728   return false;
   729 }
   730 
   731 bool cPluginMPlayer::Service(const char *Id, void *Data)
   732 {
   733   if(!strcasecmp(Id,"MPlayer-Play-v1")) {
   734     if(Data) {
   735       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   736       msd->result=ExternalPlay(msd->data.filename,false);
   737       }
   738     return true;
   739     }
   740   else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
   741     if(Data) {
   742       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   743       msd->result=ExternalPlay(msd->data.filename,true);
   744       }
   745     return true;
   746     }
   747   return false;
   748 }
   749 
   750 const char **cPluginMPlayer::SVDRPHelpPages(void)
   751 {
   752   static const char *HelpPages[] = {
   753     "PLAY <filename>\n"
   754     "    Triggers playback of file 'filename'.",
   755     "TEST <filename>\n"
   756     "    Tests is playback of file 'filename' is possible.",
   757     NULL
   758     };
   759   return HelpPages;
   760 }
   761 
   762 cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
   763 {
   764   if(!strcasecmp(Command,"PLAY")) {
   765     if(*Option) {
   766       if(ExternalPlay(Option,false)) return "Playback triggered";
   767       else { ReplyCode=550; return "Playback failed"; }
   768       }
   769     else { ReplyCode=501; return "Missing filename"; }
   770     }
   771   else if(!strcasecmp(Command,"TEST")) {
   772     if(*Option) {
   773       if(ExternalPlay(Option,true)) return "Playback possible";
   774       else { ReplyCode=550; return "Playback not possible"; }
   775       }
   776     else { ReplyCode=501; return "Missing filename"; }
   777     }
   778   return NULL;
   779 }
   780 
   781 VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!