mplayer.c
author nathan
Sun, 12 Dec 2010 12:15:17 +0100
branchtrunk
changeset 40 31537cd8ec5e
parent 39 ba6464ebc3f9
permissions -rw-r--r--
fixed image_convert.sh for newer mjpegtools
     1 /*
     2  * MP3/MPlayer plugin to VDR (C++)
     3  *
     4  * (C) 2001-2010 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   Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Prev/Next keys"),&data.PrevNextKeyMode, tr("Chapter"), tr("Playlist")));
    73   res[0]=tr("disabled");
    74   res[1]=tr("global only");
    75   res[2]=tr("local first");
    76   Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"),   &data.ResumeMode, 3, res));
    77   Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"),         &data.HideMainMenu));
    78   for(int i=0; i<10; i++) {
    79     char name[32];
    80     snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i);
    81     static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" };
    82     Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed));
    83     }
    84 }
    85 
    86 void cMenuSetupMPlayer::Store(void)
    87 {
    88   MPlayerSetup=data;
    89   SetupStore("ControlMode", MPlayerSetup.SlaveMode);
    90   SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu);
    91   SetupStore("ResumeMode",  MPlayerSetup.ResumeMode);
    92   SetupStore("PrevNextMode",MPlayerSetup.PrevNextKeyMode);
    93   for(int i=0; i<10; i++) {
    94     char name[16];
    95     snprintf(name,sizeof(name),"KeyCmd%d",i);
    96     SetupStore(name,MPlayerSetup.KeyCmd[i]);
    97     }
    98 }
    99 
   100 // --- cMPlayerControl ---------------------------------------------------------
   101 
   102 class cMPlayerControl : public cControl {
   103 private:
   104   static cFileObj *file;
   105   static bool rewind;
   106   cMPlayerPlayer *player;
   107   cSkinDisplayReplay *display;
   108   bool visible, modeOnly;
   109   time_t timeoutShow;
   110   int lastCurrent, lastTotal;
   111   char *lastReplayMsg;
   112   //
   113   bool jumpactive, jumphide, jumpmode;
   114   int jumpval;
   115   //
   116   void Stop(void);
   117   void ShowTimed(int Seconds=0);
   118   void ShowProgress(void);
   119   void ShowMode(void);
   120   void ShowTitle(void);
   121   void Jump(void);
   122   void JumpProcess(eKeys Key);
   123   void JumpDisplay(void);
   124 public:
   125   cMPlayerControl(void);
   126   virtual ~cMPlayerControl();
   127   virtual eOSState ProcessKey(eKeys Key);
   128   virtual void Show(void) { ShowTimed(); }
   129   virtual void Hide(void);
   130   static void SetFile(const cFileObj *File, bool Rewind);
   131   };
   132 
   133 cFileObj *cMPlayerControl::file=0;
   134 bool cMPlayerControl::rewind=false;
   135 
   136 cMPlayerControl::cMPlayerControl(void)
   137 :cControl(player=new cMPlayerPlayer(file,rewind))
   138 {
   139   visible=modeOnly=jumpactive=false;
   140   lastReplayMsg=0;
   141   display=0;
   142   ShowTitle();
   143 }
   144 
   145 cMPlayerControl::~cMPlayerControl()
   146 {
   147   Stop();
   148   cStatus::MsgReplaying(this,0,0,false);
   149   free(lastReplayMsg);
   150 }
   151 
   152 void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind)
   153 {
   154   delete file;
   155   file=File ? new cFileObj(File) : 0;
   156   rewind=Rewind;
   157 }
   158 
   159 void cMPlayerControl::Stop(void)
   160 {
   161   delete player; player=0;
   162 }
   163 
   164 void cMPlayerControl::ShowTimed(int Seconds)
   165 {
   166   if(modeOnly) Hide();
   167   if(!visible) {
   168     ShowProgress();
   169     timeoutShow = Seconds>0 ? time(0)+Seconds : 0;
   170     }
   171 }
   172 
   173 void cMPlayerControl::Hide(void)
   174 {
   175   if(visible) {
   176     delete display; display=0;
   177     visible=modeOnly=false;
   178 #if APIVERSNUM >= 10500
   179     SetNeedsFastResponse(false);
   180 #else
   181     needsFastResponse=false;
   182 #endif
   183     }
   184 }
   185 
   186 void cMPlayerControl::ShowTitle(void)
   187 {
   188   const char *path=0;
   189   bool release=true;
   190   if(player) path=player->GetCurrentName();
   191   if(!path) {
   192     path=file->FullPath();
   193     release=false;
   194     }
   195   if(path) {
   196     const char *name=rindex(path,'/');
   197     if(name) name++; else name=path;
   198     if(!lastReplayMsg || strcmp(lastReplayMsg,path)) {
   199       cStatus::MsgReplaying(this,name,path,true);
   200       free(lastReplayMsg);
   201       lastReplayMsg=strdup(path);
   202       }
   203     if(visible) {
   204       if(display) display->SetTitle(name);
   205       }
   206     }
   207   if(release) free((void *)path);
   208 }
   209 
   210 void cMPlayerControl::ShowProgress(void)
   211 {
   212   int Current, Total;
   213 
   214   if(GetIndex(Current,Total) && Total>0) {
   215     bool flush=false;
   216     if(!visible) {
   217       display=Skins.Current()->DisplayReplay(false);
   218       visible=true; modeOnly=false;
   219 #if APIVERSNUM >= 10500
   220       SetNeedsFastResponse(true);
   221 #else
   222       needsFastResponse=true;
   223 #endif
   224       lastCurrent=lastTotal=-1;
   225       flush=true;
   226       }
   227 
   228     if(abs(Current-lastCurrent)>12) {
   229       if(Total>0) display->SetProgress(Current, Total);
   230       display->SetCurrent(IndexToHMSF(Current));
   231       display->SetTotal(IndexToHMSF(Total));
   232       bool Play, Forward;
   233       int Speed;
   234       if(GetReplayMode(Play,Forward,Speed)) 
   235         display->SetMode(Play, Forward, Speed);
   236       ShowTitle();
   237       flush=true;
   238       lastCurrent=Current; lastTotal=Total;
   239       }
   240     if(flush) 
   241       Skins.Flush();
   242     ShowMode();
   243     }
   244 }
   245 
   246 void cMPlayerControl::ShowMode(void)
   247 {
   248   if(Setup.ShowReplayMode && !jumpactive) {
   249     bool Play, Forward;
   250     int Speed;
   251     if(GetReplayMode(Play, Forward, Speed)) {
   252        bool NormalPlay = (Play && Speed == -1);
   253 
   254        if(!visible) {
   255          if(NormalPlay) return;
   256          display = Skins.Current()->DisplayReplay(true);
   257          visible=modeOnly=true;
   258          }
   259 
   260        if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
   261 
   262        display->SetMode(Play, Forward, Speed);
   263        }
   264     }
   265 }
   266 
   267 void cMPlayerControl::JumpDisplay(void)
   268 {
   269   char buf[64];
   270   const char *j=trVDR("Jump: "), u=jumpmode?'%':'m';
   271   if(!jumpval) sprintf(buf,"%s- %c",  j,u);
   272   else         sprintf(buf,"%s%d- %c",j,jumpval,u);
   273   display->SetJump(buf);
   274 }
   275 
   276 void cMPlayerControl::JumpProcess(eKeys Key)
   277 {
   278   const int n=Key-k0;
   279   switch (Key) {
   280     case k0 ... k9:
   281       {
   282       const int max=jumpmode?100:lastTotal;
   283       if(jumpval*10+n <= max) jumpval=jumpval*10+n;
   284       JumpDisplay();
   285       }
   286       break;
   287     case kBlue:
   288       jumpmode=!jumpmode; jumpval=0;
   289       JumpDisplay();
   290       break;
   291     case kPlay:
   292     case kUp:
   293       player->Goto(jumpval*(jumpmode?1:60),jumpmode,false);
   294       jumpactive=false;
   295       break;
   296     case kFastRew:
   297     case kFastFwd:
   298     case kLeft:
   299     case kRight:
   300       if(!jumpmode) {
   301         player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1));
   302         jumpactive=false;
   303         }
   304       break;
   305     default:
   306       jumpactive=false;
   307       break;
   308     }
   309 
   310   if(!jumpactive) {
   311     if(jumphide) Hide();
   312     else 
   313       display->SetJump(0);
   314     }
   315 }
   316 
   317 void cMPlayerControl::Jump(void)
   318 {
   319   jumpval=0; jumphide=jumpmode=false;
   320   if(!visible) {
   321     ShowTimed(); if(!visible) return;
   322     jumphide=true;
   323     }
   324   JumpDisplay();
   325   jumpactive=true;
   326 }
   327 
   328 eOSState cMPlayerControl::ProcessKey(eKeys Key)
   329 {
   330   if(!player->Active()) { Hide(); Stop(); return osEnd; }
   331 
   332   if(!player->SlaveMode()) {
   333     if(Key==kBlue) { Hide(); Stop(); return osEnd; }
   334     }
   335   else {
   336     if(visible) {
   337       if(timeoutShow && time(0)>timeoutShow) {
   338         Hide(); ShowMode();
   339         timeoutShow = 0;
   340         }
   341       else {
   342         if(modeOnly) ShowMode();
   343         else ShowProgress();
   344         }
   345       }
   346     else ShowTitle();
   347 
   348     if(jumpactive && Key != kNone) {
   349       JumpProcess(Key);
   350       return osContinue;
   351       }
   352 
   353     bool DoShowMode = true;
   354     switch (Key) {
   355       case kPlay:
   356       case kUp:      player->Play(); break;
   357 
   358       case kPause:
   359       case kDown:    player->Pause(); break;
   360 
   361       case kFastRew|k_Repeat:
   362       case kFastRew:
   363       case kLeft|k_Repeat:
   364       case kLeft:    player->SkipSeconds(-10); break;
   365 
   366       case kFastFwd|k_Repeat:
   367       case kFastFwd:
   368       case kRight|k_Repeat:
   369       case kRight:   player->SkipSeconds(10); break;
   370 
   371       case kRed:     Jump(); break;
   372 
   373       case kGreen|k_Repeat:
   374       case kGreen:   player->SkipSeconds(-60); break;
   375       case kYellow|k_Repeat:
   376       case kYellow:  player->SkipSeconds(60); break;
   377 
   378       case kNext:    player->SkipTrack(1,MPlayerSetup.PrevNextKeyMode!=0); break;
   379       case kPrev:    player->SkipTrack(-1,MPlayerSetup.PrevNextKeyMode!=0); break;
   380 
   381       case kBack:    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   help_str=aprintf(  "  -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 (!strcasecmp(Name, "PrevNextMode")) MPlayerSetup.PrevNextKeyMode = atoi(Value);
   694   else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
   695     strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
   696   else return false;
   697   return true;
   698 }
   699 
   700 bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
   701 {
   702   char real[PATH_MAX+1];
   703   if(realpath(path,real)) {
   704     cFileSource *src=MPlaySources.FindSource(real);
   705     if(src) {
   706       cFileObj *item=new cFileObj(src,0,0,otFile);
   707       if(item) {
   708         item->SplitAndSet(real);
   709         if(item->GuessType()) {
   710           if(item->Exists()) {
   711             if(!test) {
   712               cMPlayerControl::SetFile(item,true);
   713               cControl::Launch(new cMPlayerControl);
   714               cControl::Attach();
   715               }
   716             delete item;
   717             return true;
   718             }
   719           else dsyslog("MPlayer service: cannot play '%s'",path);
   720           }
   721         else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
   722         delete item;
   723         }
   724       }
   725     else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
   726     }
   727   else if(errno!=ENOENT && errno!=ENOTDIR)
   728     esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
   729   return false;
   730 }
   731 
   732 bool cPluginMPlayer::Service(const char *Id, void *Data)
   733 {
   734   if(!strcasecmp(Id,"MPlayer-Play-v1")) {
   735     if(Data) {
   736       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   737       msd->result=ExternalPlay(msd->data.filename,false);
   738       }
   739     return true;
   740     }
   741   else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
   742     if(Data) {
   743       struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   744       msd->result=ExternalPlay(msd->data.filename,true);
   745       }
   746     return true;
   747     }
   748   return false;
   749 }
   750 
   751 const char **cPluginMPlayer::SVDRPHelpPages(void)
   752 {
   753   static const char *HelpPages[] = {
   754     "PLAY <filename>\n"
   755     "    Triggers playback of file 'filename'.",
   756     "TEST <filename>\n"
   757     "    Tests is playback of file 'filename' is possible.",
   758     NULL
   759     };
   760   return HelpPages;
   761 }
   762 
   763 cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
   764 {
   765   if(!strcasecmp(Command,"PLAY")) {
   766     if(*Option) {
   767       if(ExternalPlay(Option,false)) return "Playback triggered";
   768       else { ReplyCode=550; return "Playback failed"; }
   769       }
   770     else { ReplyCode=501; return "Missing filename"; }
   771     }
   772   else if(!strcasecmp(Command,"TEST")) {
   773     if(*Option) {
   774       if(ExternalPlay(Option,true)) return "Playback possible";
   775       else { ReplyCode=550; return "Playback not possible"; }
   776       }
   777     else { ReplyCode=501; return "Missing filename"; }
   778     }
   779   return NULL;
   780 }
   781 
   782 VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!