mplayer.c
author nathan
Sun, 12 Dec 2010 11:31:54 +0100
branchtrunk
changeset 38 79b272a68eb4
parent 29 640ce9201139
child 39 ba6464ebc3f9
permissions -rw-r--r--
fix compile without OGG library
     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;
   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=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 kNext:
   397                     player->KeyCmd("seek_chapter +1");
   398                     break;
   399           case kPrev:
   400                     player->KeyCmd("seek_chapter -1");
   401                     break;
   402           case k0:
   403           case k1:
   404           case k2:
   405           case k3:
   406           case k4:
   407           case k5:
   408           case k6:
   409           case k7:
   410           case k8:
   411           case k9:  {
   412                     const char *cmd=MPlayerSetup.KeyCmd[Key-k0];
   413                     if(cmd[0]) player->KeyCmd(cmd);
   414                     }
   415                     break;
   416           default:  break;
   417           }
   418         break;
   419       }
   420 
   421     if(DoShowMode) ShowMode();
   422     }
   423   return osContinue;
   424 }
   425 
   426 // --- cMenuMPlayAid -----------------------------------------------------------
   427 
   428 class cMenuMPlayAid : public cOsdMenu {
   429 public:
   430   cMenuMPlayAid(void);
   431   virtual eOSState ProcessKey(eKeys Key);
   432   };
   433 
   434 cMenuMPlayAid::cMenuMPlayAid(void)
   435 :cOsdMenu(tr("MPlayer Audio ID"),20)
   436 {
   437   Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255));
   438   Display();
   439 }
   440 
   441 eOSState cMenuMPlayAid::ProcessKey(eKeys Key)
   442 {
   443   eOSState state=cOsdMenu::ProcessKey(Key);
   444   if(state==osUnknown) {
   445     switch(Key) {
   446       case kOk: state=osBack; break;
   447       default:  break;
   448       }
   449     }
   450   return state;
   451 }
   452 
   453 // --- cMenuMPlayBrowse ---------------------------------------------------------
   454 
   455 class cMenuMPlayBrowse : public cMenuBrowse {
   456 private:
   457   bool sourcing, aidedit;
   458   eOSState Source(bool second);
   459   eOSState Summary(void);
   460 protected:
   461   virtual void SetButtons(void);
   462 public:
   463   cMenuMPlayBrowse(void);
   464   virtual eOSState ProcessKey(eKeys Key);
   465   };
   466 
   467 static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 };
   468 
   469 cMenuMPlayBrowse::cMenuMPlayBrowse(void)
   470 :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum)
   471 {
   472   sourcing=aidedit=false;
   473   SetButtons();
   474 }
   475 
   476 void cMenuMPlayBrowse::SetButtons(void)
   477 {
   478   static char blue[12];
   479   snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid);
   480   SetHelp(trVDR("Button$Play"), MPlayerSetup.ResumeMode ? trVDR("Button$Rewind"):0, tr("Source"), blue);
   481   Display();
   482 }
   483 
   484 eOSState cMenuMPlayBrowse::Source(bool second)
   485 {
   486   if(HasSubMenu()) return osContinue;
   487 
   488   if(!second) {
   489     sourcing=true;
   490     return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source")));
   491     }
   492   sourcing=false;
   493   cFileSource *src=cMenuSource::GetSelected();
   494   if(src) {
   495     MPlaySources.SetSource(src);
   496     SetSource(src);
   497     NewDir(0);
   498     }
   499   return osContinue;
   500 }
   501 
   502 eOSState cMenuMPlayBrowse::Summary(void)
   503 {
   504   cFileObj *item=CurrentItem();
   505   if(item && item->Type()==otFile) {
   506     static const char *exts[] = { ".summary",".txt",".nfo",0 };
   507     for(int i=0; exts[i]; i++) {
   508       char buff[4096];
   509       strn0cpy(buff,item->FullPath(),sizeof(buff)-20);
   510       char *e=&buff[strlen(buff)];
   511       strn0cpy(e,exts[i],20);
   512       int fd=open(buff,O_RDONLY);
   513       *e=0;
   514       if(fd<0 && (e=rindex(buff,'.'))) {
   515         strn0cpy(e,exts[i],20);
   516         fd=open(buff,O_RDONLY);
   517         }
   518       if(fd>=0) {
   519         int r=read(fd,buff,sizeof(buff)-1);
   520         close(fd);
   521         if(r>0) {
   522           buff[r]=0;
   523           return AddSubMenu(new cMenuText(tr("Summary"),buff));
   524           }
   525         }
   526       }
   527     }
   528   return osContinue;
   529 }
   530 
   531 eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key)
   532 {
   533   eOSState state=cOsdMenu::ProcessKey(Key);
   534   if(state==osContinue && !HasSubMenu()) {
   535     if(sourcing) return Source(true);
   536     if(aidedit) { aidedit=false; SetButtons(); }
   537     }
   538   bool rew=false;
   539   if(state==osUnknown) {
   540     switch(Key) {
   541       case kGreen:
   542         {
   543         cFileObj *item=CurrentItem();
   544         if(item && item->Type()==otFile) {
   545           lastselect=new cFileObj(item);
   546           state=osBack;
   547           rew=true;
   548           } 
   549         else state=osContinue;
   550         break;
   551         }
   552       case kYellow:
   553         state=Source(false);
   554         break;
   555       case kBlue:
   556         aidedit=true;
   557         state=AddSubMenu(new cMenuMPlayAid);
   558         break;
   559       case k0:
   560         state=Summary();
   561         break;
   562       default:
   563         break;
   564       }
   565     }
   566   if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
   567   if(state==osBack && lastselect) {
   568     cMPlayerControl::SetFile(lastselect,rew);
   569     cControl::Launch(new cMPlayerControl);
   570     return osEnd;
   571     }
   572   return state;
   573 }
   574 
   575 // --- cPluginMPlayer ----------------------------------------------------------
   576 
   577 static const char *DESCRIPTION    = trNOOP("Media replay via MPlayer");
   578 static const char *MAINMENUENTRY  = "MPlayer";
   579 
   580 class cPluginMPlayer : public cPlugin {
   581 private:
   582   bool ExternalPlay(const char *path, bool test);
   583 public:
   584   cPluginMPlayer(void);
   585   virtual ~cPluginMPlayer();
   586   virtual const char *Version(void) { return PluginVersion; }
   587   virtual const char *Description(void) { return tr(DESCRIPTION); }
   588   virtual const char *CommandLineHelp(void);
   589   virtual bool ProcessArgs(int argc, char *argv[]);
   590   virtual bool Initialize(void);
   591   virtual const char *MainMenuEntry(void);
   592   virtual cOsdMenu *MainMenuAction(void);
   593   virtual cMenuSetupPage *SetupMenu(void);
   594   virtual bool SetupParse(const char *Name, const char *Value);
   595   virtual bool Service(const char *Id, void *Data);
   596   virtual const char **SVDRPHelpPages(void);
   597   virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
   598   };
   599 
   600 cPluginMPlayer::cPluginMPlayer(void)
   601 {
   602   // Initialize any member variables here.
   603   // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
   604   // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
   605   status=0;
   606 }
   607 
   608 cPluginMPlayer::~cPluginMPlayer()
   609 {
   610   delete status;
   611 }
   612 
   613 const char *cPluginMPlayer::CommandLineHelp(void)
   614 {
   615   static char *help_str=0;
   616   
   617   free(help_str);    //                                     for easier orientation, this is column 80|
   618   help_str=aprintf(  "  -m CMD,   --mount=CMD    use CMD to mount/unmount/eject mp3 sources\n"
   619                      "                           (default: %s)\n"
   620                      "  -M CMD,   --mplayer=CMD  use CMD when calling MPlayer\n"
   621                      "                           (default: %s)\n"
   622                      "  -S SUB,   --sources=SUB  search sources config in SUB subdirectory\n"
   623                      "                           (default: %s)\n"
   624                      "  -R DIR,   --resume=DIR   store global resume file in DIR\n"
   625                      "                           (default: %s)\n",
   626                      mountscript,
   627                      MPlayerCmd,
   628                      sourcesSub ? sourcesSub:"none",
   629                      globalResumeDir ? globalResumeDir:"video dir"
   630                      );
   631   return help_str;
   632 }
   633 
   634 bool cPluginMPlayer::ProcessArgs(int argc, char *argv[])
   635 {
   636   static struct option long_options[] = {
   637       { "mount",    required_argument, NULL, 'm' },
   638       { "mplayer",  required_argument, NULL, 'M' },
   639       { "sources",  required_argument, NULL, 'S' },
   640       { "resume",   required_argument, NULL, 'R' },
   641       { NULL }
   642     };
   643 
   644   int c, option_index = 0;
   645   while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) {
   646     switch (c) {
   647       case 'm': mountscript=optarg; break;
   648       case 'M': MPlayerCmd=optarg; break;
   649       case 'S': sourcesSub=optarg; break;
   650       case 'R': globalResumeDir=optarg; break;
   651       default:  return false;
   652       }
   653     }
   654   return true;
   655 }
   656 
   657 bool cPluginMPlayer::Initialize(void)
   658 {
   659   if(!CheckVDRVersion(1,4,5,"mplayer")) return false;
   660   plugin_name="mplayer";
   661 #if APIVERSNUM < 10507
   662   i18n_name="mplayer";
   663 #else
   664   i18n_name="vdr-mplayer";
   665 #endif
   666   MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf"));
   667   if(MPlaySources.Count()<1) {
   668     esyslog("ERROR: you must have defined at least one source in mplayersources.conf");
   669     fprintf(stderr,"No source(s) defined in mplayersources.conf\n");
   670     return false;
   671     }
   672 #if APIVERSNUM < 10507
   673   RegisterI18n(Phrases);
   674 #endif
   675   if(!(status=new cMPlayerStatus)) return false;
   676   return true;
   677 }
   678 
   679 const char *cPluginMPlayer::MainMenuEntry(void)
   680 {
   681   return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
   682 }
   683 
   684 cOsdMenu *cPluginMPlayer::MainMenuAction(void)
   685 {
   686   return new cMenuMPlayBrowse;
   687 }
   688 
   689 cMenuSetupPage *cPluginMPlayer::SetupMenu(void)
   690 {
   691   return new cMenuSetupMPlayer;
   692 }
   693 
   694 bool cPluginMPlayer::SetupParse(const char *Name, const char *Value)
   695 {
   696   if(      !strcasecmp(Name, "ControlMode"))  MPlayerSetup.SlaveMode    = atoi(Value);
   697   else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value);
   698   else if (!strcasecmp(Name, "ResumeMode"))   MPlayerSetup.ResumeMode   = atoi(Value);
   699   else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
   700     strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
   701   else return false;
   702   return true;
   703 }
   704 
   705 bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
   706 {
   707   char real[PATH_MAX+1];
   708   if(realpath(path,real)) {
   709     cFileSource *src=MPlaySources.FindSource(real);
   710     if(src) {
   711       cFileObj *item=new cFileObj(src,0,0,otFile);
   712       if(item) {
   713         item->SplitAndSet(real);
   714         if(item->GuessType()) {
   715           if(item->Exists()) {
   716             if(!test) {
   717               cMPlayerControl::SetFile(item,true);
   718               cControl::Launch(new cMPlayerControl);
   719               cControl::Attach();
   720               }
   721             delete item;
   722             return true;
   723             }
   724           else dsyslog("MPlayer service: cannot play '%s'",path);
   725           }
   726         else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
   727         delete item;
   728         }
   729       }
   730     else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
   731     }
   732   else if(errno!=ENOENT && errno!=ENOTDIR)
   733     esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
   734   return false;
   735 }
   736 
   737 bool cPluginMPlayer::Service(const char *Id, void *Data)
   738 {
   739   if(!strcasecmp(Id,"MPlayer-Play-v1")) {
   740     if(Data) {
   741       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   742       msd->result=ExternalPlay(msd->data.filename,false);
   743       }
   744     return true;
   745     }
   746   else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
   747     if(Data) {
   748       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   749       msd->result=ExternalPlay(msd->data.filename,true);
   750       }
   751     return true;
   752     }
   753   return false;
   754 }
   755 
   756 const char **cPluginMPlayer::SVDRPHelpPages(void)
   757 {
   758   static const char *HelpPages[] = {
   759     "PLAY <filename>\n"
   760     "    Triggers playback of file 'filename'.",
   761     "TEST <filename>\n"
   762     "    Tests is playback of file 'filename' is possible.",
   763     NULL
   764     };
   765   return HelpPages;
   766 }
   767 
   768 cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
   769 {
   770   if(!strcasecmp(Command,"PLAY")) {
   771     if(*Option) {
   772       if(ExternalPlay(Option,false)) return "Playback triggered";
   773       else { ReplyCode=550; return "Playback failed"; }
   774       }
   775     else { ReplyCode=501; return "Missing filename"; }
   776     }
   777   else if(!strcasecmp(Command,"TEST")) {
   778     if(*Option) {
   779       if(ExternalPlay(Option,true)) return "Playback possible";
   780       else { ReplyCode=550; return "Playback not possible"; }
   781       }
   782     else { ReplyCode=501; return "Missing filename"; }
   783     }
   784   return NULL;
   785 }
   786 
   787 VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!