mplayer.c
branchtrunk
changeset 0 474a1293c3c0
child 2 4c1f7b705009
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mplayer.c	Sat Dec 29 14:47:40 2007 +0100
     1.3 @@ -0,0 +1,955 @@
     1.4 +/*
     1.5 + * MP3/MPlayer plugin to VDR (C++)
     1.6 + *
     1.7 + * (C) 2001-2007 Stefan Huelswitt <s.huelswitt@gmx.de>
     1.8 + *
     1.9 + * This code is free software; you can redistribute it and/or
    1.10 + * modify it under the terms of the GNU General Public License
    1.11 + * as published by the Free Software Foundation; either version 2
    1.12 + * of the License, or (at your option) any later version.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful,
    1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with this program; if not, write to the Free Software
    1.21 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    1.22 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    1.23 + */
    1.24 +
    1.25 +#include <getopt.h>
    1.26 +#include <malloc.h>
    1.27 +#include <stdlib.h>
    1.28 +#include <ctype.h>
    1.29 +
    1.30 +#include "common.h"
    1.31 +
    1.32 +#include <vdr/plugin.h>
    1.33 +#include <vdr/player.h>
    1.34 +#include <vdr/status.h>
    1.35 +#include <vdr/font.h>
    1.36 +#include <vdr/osdbase.h>
    1.37 +#include <vdr/menuitems.h>
    1.38 +#ifdef HAVE_BEAUTYPATCH
    1.39 +#include <vdr/fontsym.h>
    1.40 +#endif
    1.41 +#if APIVERSNUM >= 10307
    1.42 +#include <vdr/skins.h>
    1.43 +#endif
    1.44 +#if APIVERSNUM >= 10332
    1.45 +#include <vdr/remote.h>
    1.46 +#endif
    1.47 +
    1.48 +#if APIVERSNUM > 10307
    1.49 +#include <vdr/menu.h>
    1.50 +#elif APIVERSNUM == 10307
    1.51 +class cMenuText : public cOsdMenu {
    1.52 +private:
    1.53 +  char *text;
    1.54 +public:
    1.55 +  cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
    1.56 +  virtual ~cMenuText();
    1.57 +  void SetText(const char *Text);
    1.58 +  virtual void Display(void);
    1.59 +  virtual eOSState ProcessKey(eKeys Key);
    1.60 +  };
    1.61 +#else
    1.62 +class cMenuText : public cOsdMenu {
    1.63 +public:
    1.64 +  cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
    1.65 +  virtual eOSState ProcessKey(eKeys Key);
    1.66 +  };
    1.67 +#endif
    1.68 +
    1.69 +#include "setup.h"
    1.70 +#include "setup-mplayer.h"
    1.71 +#include "menu.h"
    1.72 +#include "player-mplayer.h"
    1.73 +#include "data.h"
    1.74 +#include "data-src.h"
    1.75 +#include "i18n.h"
    1.76 +#include "version.h"
    1.77 +#include "service.h"
    1.78 +
    1.79 +const char *sourcesSub=0;
    1.80 +cFileSources MPlaySources;
    1.81 +
    1.82 +// --- cMenuSetupMPlayer --------------------------------------------------------
    1.83 +
    1.84 +class cMenuSetupMPlayer : public cMenuSetupPage {
    1.85 +private:
    1.86 +  cMPlayerSetup data;
    1.87 +  const char *res[3];
    1.88 +protected:
    1.89 +  virtual void Store(void);
    1.90 +public:
    1.91 +  cMenuSetupMPlayer(void);
    1.92 +  };
    1.93 +
    1.94 +cMenuSetupMPlayer::cMenuSetupMPlayer(void)
    1.95 +{
    1.96 +  data=MPlayerSetup;
    1.97 +  SetSection(tr("MPlayer"));
    1.98 +  Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"),  &data.SlaveMode, tr("Traditional"), tr("Slave")));
    1.99 +#if APIVERSNUM < 10307
   1.100 +  Add(new cMenuEditIntItem( tr("Setup.MPlayer$OSD position"),  &data.OsdPos, 0, 6));
   1.101 +#endif
   1.102 +  res[0]=tr("disabled");
   1.103 +  res[1]=tr("global only");
   1.104 +  res[2]=tr("local first");
   1.105 +  Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"),   &data.ResumeMode, 3, res));
   1.106 +  Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"),         &data.HideMainMenu));
   1.107 +  for(int i=0; i<10; i++) {
   1.108 +    char name[32];
   1.109 +    snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i);
   1.110 +    static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" };
   1.111 +    Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed));
   1.112 +    }
   1.113 +}
   1.114 +
   1.115 +void cMenuSetupMPlayer::Store(void)
   1.116 +{
   1.117 +  MPlayerSetup=data;
   1.118 +  SetupStore("ControlMode", MPlayerSetup.SlaveMode);
   1.119 +  SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu);
   1.120 +  SetupStore("ResumeMode",  MPlayerSetup.ResumeMode);
   1.121 +#if APIVERSNUM < 10307
   1.122 +  SetupStore("OsdPos",      MPlayerSetup.OsdPos);
   1.123 +#endif
   1.124 +  for(int i=0; i<10; i++) {
   1.125 +    char name[16];
   1.126 +    snprintf(name,sizeof(name),"KeyCmd%d",i);
   1.127 +    SetupStore(name,MPlayerSetup.KeyCmd[i]);
   1.128 +    }
   1.129 +}
   1.130 +
   1.131 +// --- cMPlayerControl ---------------------------------------------------------
   1.132 +
   1.133 +class cMPlayerControl : public cControl {
   1.134 +private:
   1.135 +  static cFileObj *file;
   1.136 +  static bool rewind;
   1.137 +  cMPlayerPlayer *player;
   1.138 +#if APIVERSNUM >= 10307
   1.139 +  cSkinDisplayReplay *display;
   1.140 +#endif
   1.141 +  bool visible, modeOnly, haveBeauty;
   1.142 +  time_t timeoutShow;
   1.143 +  int lastCurrent, lastTotal;
   1.144 +  char *lastReplayMsg;
   1.145 +  //
   1.146 +  bool jumpactive, jumphide, jumpmode;
   1.147 +  int jumpval;
   1.148 +  //
   1.149 +  void Stop(void);
   1.150 +  void ShowTimed(int Seconds=0);
   1.151 +  void DisplayAtBottom(const char *s);
   1.152 +  void ShowProgress(void);
   1.153 +  void ShowMode(void);
   1.154 +  void ShowTitle(void);
   1.155 +  void Jump(void);
   1.156 +  void JumpProcess(eKeys Key);
   1.157 +  void JumpDisplay(void);
   1.158 +public:
   1.159 +  cMPlayerControl(void);
   1.160 +  virtual ~cMPlayerControl();
   1.161 +  virtual eOSState ProcessKey(eKeys Key);
   1.162 +  virtual void Show(void) { ShowTimed(); }
   1.163 +  virtual void Hide(void);
   1.164 +  static void SetFile(const cFileObj *File, bool Rewind);
   1.165 +  };
   1.166 +
   1.167 +cFileObj *cMPlayerControl::file=0;
   1.168 +bool cMPlayerControl::rewind=false;
   1.169 +
   1.170 +cMPlayerControl::cMPlayerControl(void)
   1.171 +:cControl(player=new cMPlayerPlayer(file,rewind))
   1.172 +{
   1.173 +  visible=modeOnly=jumpactive=haveBeauty=false;
   1.174 +  lastReplayMsg=0;
   1.175 +#if APIVERSNUM >= 10307
   1.176 +  display=0;
   1.177 +#else
   1.178 +#ifdef HAVE_BEAUTYPATCH
   1.179 +#if APIVERSNUM >= 10300
   1.180 +  const cFont *sym=cFont::GetFont(fontSym);
   1.181 +  const cFont *osd=cFont::GetFont(fontOsd);
   1.182 +  const cFont::tCharData *symD=sym->CharData(32);
   1.183 +  const cFont::tCharData *osdD=osd->CharData(32);
   1.184 +#else //APIVERSNUM >= 10300
   1.185 +  cFont *sym=new cFont(fontSym);
   1.186 +  cFont *osd=new cFont(fontOsd);
   1.187 +  const cFont::tCharData *symD=sym->CharData(32);
   1.188 +  const cFont::tCharData *osdD=osd->CharData(32);
   1.189 +  delete sym;
   1.190 +  delete osd;
   1.191 +#endif //APIVERSNUM >= 10300
   1.192 +  if(symD != osdD) haveBeauty=true;
   1.193 +  d(printf("mplayer: beauty patch %sdetected\n",haveBeauty?"":"NOT "))
   1.194 +#endif //HAVE_BEAUTYPATCH
   1.195 +#endif //APIVERSNUM >= 10307
   1.196 +  ShowTitle();
   1.197 +}
   1.198 +
   1.199 +cMPlayerControl::~cMPlayerControl()
   1.200 +{
   1.201 +  Stop();
   1.202 +#if APIVERSNUM >= 10338
   1.203 +  cStatus::MsgReplaying(this,0,0,false);
   1.204 +#else
   1.205 +  cStatus::MsgReplaying(this, NULL);
   1.206 +#endif
   1.207 +  free(lastReplayMsg);
   1.208 +}
   1.209 +
   1.210 +void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind)
   1.211 +{
   1.212 +  delete file;
   1.213 +  file=File ? new cFileObj(File) : 0;
   1.214 +  rewind=Rewind;
   1.215 +}
   1.216 +
   1.217 +void cMPlayerControl::Stop(void)
   1.218 +{
   1.219 +  delete player; player=0;
   1.220 +}
   1.221 +
   1.222 +void cMPlayerControl::ShowTimed(int Seconds)
   1.223 +{
   1.224 +  if(modeOnly) Hide();
   1.225 +  if(!visible) {
   1.226 +    ShowProgress();
   1.227 +    timeoutShow = Seconds>0 ? time(0)+Seconds : 0;
   1.228 +    }
   1.229 +}
   1.230 +
   1.231 +void cMPlayerControl::Hide(void)
   1.232 +{
   1.233 +  if(visible) {
   1.234 +#if APIVERSNUM >= 10307
   1.235 +    delete display; display=0;
   1.236 +#else
   1.237 +    Interface->Close();
   1.238 +#endif
   1.239 +    visible=modeOnly=false;
   1.240 +#if APIVERSNUM >= 10500
   1.241 +    SetNeedsFastResponse(false);
   1.242 +#else
   1.243 +    needsFastResponse=false;
   1.244 +#endif
   1.245 +    }
   1.246 +}
   1.247 +
   1.248 +void cMPlayerControl::DisplayAtBottom(const char *s)
   1.249 +{
   1.250 +#if APIVERSNUM < 10307
   1.251 +  const int p=modeOnly ? 0 : 2;
   1.252 +  if(s) {
   1.253 +    const int d=max(Width()-cOsd::WidthInCells(s),0) / 2;
   1.254 +    if(modeOnly) Interface->Fill(0, p, Interface->Width(), 1, clrTransparent);
   1.255 +    Interface->Write(d, p, s);
   1.256 +    }
   1.257 +  else
   1.258 +    Interface->Fill(12, p, Width() - 22, 1, clrBackground);
   1.259 +#endif
   1.260 +}
   1.261 +
   1.262 +void cMPlayerControl::ShowTitle(void)
   1.263 +{
   1.264 +  const char *path=0;
   1.265 +  bool release=true;
   1.266 +  if(player) path=player->GetCurrentName();
   1.267 +  if(!path) {
   1.268 +    path=file->FullPath();
   1.269 +    release=false;
   1.270 +    }
   1.271 +  if(path) {
   1.272 +    const char *name=rindex(path,'/');
   1.273 +    if(name) name++; else name=path;
   1.274 +    if(!lastReplayMsg || strcmp(lastReplayMsg,path)) {
   1.275 +#if APIVERSNUM >= 10338
   1.276 +      cStatus::MsgReplaying(this,name,path,true);
   1.277 +#else
   1.278 +      cStatus::MsgReplaying(this,path);
   1.279 +#endif
   1.280 +      free(lastReplayMsg);
   1.281 +      lastReplayMsg=strdup(path);
   1.282 +      }
   1.283 +    if(visible) {
   1.284 +#if APIVERSNUM >= 10307
   1.285 +      if(display) display->SetTitle(name);
   1.286 +#else
   1.287 +      int n=strlen(name);
   1.288 +      if(n>Width()) {
   1.289 +        n=n-Width()+4; if(n<0) n=0;
   1.290 +        char str[72];
   1.291 +        snprintf(str,sizeof(str),"... %s",name+n);
   1.292 +        Interface->Write(0,0,str);
   1.293 +        }
   1.294 +      else Interface->Write(0,0,name);
   1.295 +#endif
   1.296 +      }
   1.297 +    }
   1.298 +  if(release) free((void *)path);
   1.299 +}
   1.300 +
   1.301 +void cMPlayerControl::ShowProgress(void)
   1.302 +{
   1.303 +  int Current, Total;
   1.304 +
   1.305 +  if(GetIndex(Current,Total) && Total>0) {
   1.306 +    bool flush=false;
   1.307 +    if(!visible) {
   1.308 +#if APIVERSNUM >= 10307
   1.309 +      display=Skins.Current()->DisplayReplay(false);
   1.310 +#else
   1.311 +      Interface->Open(Setup.OSDwidth,-MPlayerSetup.OsdPos-3);
   1.312 +      Interface->Clear();
   1.313 +      if(MPlayerSetup.OsdPos>0) Interface->Fill(0,3,Interface->Width(),MPlayerSetup.OsdPos,clrTransparent);
   1.314 +#endif
   1.315 +      visible=true; modeOnly=false;
   1.316 +#if APIVERSNUM >= 10500
   1.317 +      SetNeedsFastResponse(true);
   1.318 +#else
   1.319 +      needsFastResponse=true;
   1.320 +#endif
   1.321 +      lastCurrent=lastTotal=-1;
   1.322 +      flush=true;
   1.323 +      }
   1.324 +
   1.325 +    if(abs(Current-lastCurrent)>12) {
   1.326 +#if APIVERSNUM >= 10307
   1.327 +      if(Total>0) display->SetProgress(Current, Total);
   1.328 +      display->SetCurrent(IndexToHMSF(Current));
   1.329 +      display->SetTotal(IndexToHMSF(Total));
   1.330 +      bool Play, Forward;
   1.331 +      int Speed;
   1.332 +      if(GetReplayMode(Play,Forward,Speed)) 
   1.333 +        display->SetMode(Play, Forward, Speed);
   1.334 +#else
   1.335 +      cProgressBar ProgressBar(Width() * cOsd::CellWidth(), cOsd::LineHeight(), Current, Total);
   1.336 +      Interface->SetBitmap(0, cOsd::LineHeight(), ProgressBar);
   1.337 +      Interface->Write(0,2,IndexToHMSF(Current));
   1.338 +      Interface->Write(-7,2,IndexToHMSF(Total));
   1.339 +#endif
   1.340 +      ShowTitle();
   1.341 +      flush=true;
   1.342 +      lastCurrent=Current; lastTotal=Total;
   1.343 +      }
   1.344 +    if(flush) 
   1.345 +#if APIVERSNUM >= 10307
   1.346 +      Skins.Flush();
   1.347 +#else
   1.348 +      Interface->Flush();
   1.349 +#endif
   1.350 +    ShowMode();
   1.351 +    }
   1.352 +}
   1.353 +
   1.354 +#if APIVERSNUM < 10307
   1.355 +#ifdef HAVE_BEAUTYPATCH
   1.356 +int forwSym[] = { FSYM_FORW,FSYM_FORW1,FSYM_FORW2,FSYM_FORW3 };
   1.357 +int backSym[] = { FSYM_BACK,FSYM_BACK1,FSYM_BACK2,FSYM_BACK3 };
   1.358 +#endif
   1.359 +#endif
   1.360 +
   1.361 +void cMPlayerControl::ShowMode(void)
   1.362 +{
   1.363 +  if(Setup.ShowReplayMode && !jumpactive) {
   1.364 +    bool Play, Forward;
   1.365 +    int Speed;
   1.366 +    if(GetReplayMode(Play, Forward, Speed)) {
   1.367 +       bool NormalPlay = (Play && Speed == -1);
   1.368 +
   1.369 +       if(!visible) {
   1.370 +         if(NormalPlay) return;
   1.371 +#if APIVERSNUM >= 10307
   1.372 +         display = Skins.Current()->DisplayReplay(true);
   1.373 +#else
   1.374 +         Interface->Open(0,-MPlayerSetup.OsdPos-1);
   1.375 +#endif
   1.376 +         visible=modeOnly=true;
   1.377 +         }
   1.378 +
   1.379 +       if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
   1.380 +
   1.381 +#if APIVERSNUM >= 10307
   1.382 +       display->SetMode(Play, Forward, Speed);
   1.383 +#else
   1.384 +       char buf[16];
   1.385 +       eDvbFont OldFont;
   1.386 +#ifdef HAVE_BEAUTYPATCH
   1.387 +       if(haveBeauty) {
   1.388 +         int i=0;
   1.389 +         if(!(Width()&1)) buf[i++]=' ';
   1.390 +         buf[i]=FSYM_EMPTY; if(Speed>=0 && !Forward) buf[i]=backSym[Speed];
   1.391 +         i++;
   1.392 +         buf[i++]=Play?(Speed==-1?FSYM_PLAY:FSYM_EMPTY):FSYM_PAUSE;
   1.393 +         buf[i]=FSYM_EMPTY; if(Speed>=0 && Forward) buf[i]=forwSym[Speed];
   1.394 +         i++;
   1.395 +         if(!(Width()&1)) buf[i++]=' ';
   1.396 +         buf[i]=0;
   1.397 +         OldFont = Interface->SetFont(fontSym);
   1.398 +         }
   1.399 +       else {
   1.400 +#endif //HAVE_BEAUTYPATCH
   1.401 +         const char *Mode;
   1.402 +         if (Speed == -1) Mode = Play    ? "  >  " : " ||  ";
   1.403 +         else if (Play)   Mode = Forward ? " X>> " : " <<X ";
   1.404 +         else             Mode = Forward ? " X|> " : " <|X ";
   1.405 +         strn0cpy(buf, Mode, sizeof(buf));
   1.406 +         char *p = strchr(buf, 'X');
   1.407 +         if(p) *p = Speed > 0 ? '1' + Speed - 1 : ' ';
   1.408 +         OldFont = Interface->SetFont(fontFix);
   1.409 +#ifdef HAVE_BEAUTYPATCH
   1.410 +         }
   1.411 +#endif //HAVE_BEAUTYPATCH
   1.412 +       DisplayAtBottom(buf);
   1.413 +       Interface->SetFont(OldFont);
   1.414 +#endif //APIVERSNUM >= 10307
   1.415 +       }
   1.416 +    }
   1.417 +}
   1.418 +
   1.419 +void cMPlayerControl::JumpDisplay(void)
   1.420 +{
   1.421 +  char buf[64];
   1.422 +  const char *j=tr("Jump: "), u=jumpmode?'%':'m';
   1.423 +  if(!jumpval) sprintf(buf,"%s- %c",  j,u);
   1.424 +  else         sprintf(buf,"%s%d- %c",j,jumpval,u);
   1.425 +#if APIVERSNUM >= 10307
   1.426 +  display->SetJump(buf);
   1.427 +#else
   1.428 +  DisplayAtBottom(buf);
   1.429 +#endif
   1.430 +}
   1.431 +
   1.432 +void cMPlayerControl::JumpProcess(eKeys Key)
   1.433 +{
   1.434 +  const int n=Key-k0;
   1.435 +  switch (Key) {
   1.436 +    case k0 ... k9:
   1.437 +      {
   1.438 +      const int max=jumpmode?100:lastTotal;
   1.439 +      if(jumpval*10+n <= max) jumpval=jumpval*10+n;
   1.440 +      JumpDisplay();
   1.441 +      }
   1.442 +      break;
   1.443 +    case kBlue:
   1.444 +      jumpmode=!jumpmode; jumpval=0;
   1.445 +      DisplayAtBottom(0); JumpDisplay();
   1.446 +      break;
   1.447 +    case kPlay:
   1.448 +    case kUp:
   1.449 +      player->Goto(jumpval*(jumpmode?1:60),jumpmode,false);
   1.450 +      jumpactive=false;
   1.451 +      break;
   1.452 +    case kFastRew:
   1.453 +    case kFastFwd:
   1.454 +    case kLeft:
   1.455 +    case kRight:
   1.456 +      if(!jumpmode) {
   1.457 +        player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1));
   1.458 +        jumpactive=false;
   1.459 +        }
   1.460 +      break;
   1.461 +    default:
   1.462 +      jumpactive=false;
   1.463 +      break;
   1.464 +    }
   1.465 +
   1.466 +  if(!jumpactive) {
   1.467 +    if(jumphide) Hide();
   1.468 +    else 
   1.469 +#if APIVERSNUM >= 10307
   1.470 +      display->SetJump(0);
   1.471 +#else
   1.472 +      DisplayAtBottom(0);
   1.473 +#endif
   1.474 +    }
   1.475 +}
   1.476 +
   1.477 +void cMPlayerControl::Jump(void)
   1.478 +{
   1.479 +  jumpval=0; jumphide=jumpmode=false;
   1.480 +  if(!visible) {
   1.481 +    ShowTimed(); if(!visible) return;
   1.482 +    jumphide=true;
   1.483 +    }
   1.484 +  JumpDisplay();
   1.485 +  jumpactive=true;
   1.486 +}
   1.487 +
   1.488 +eOSState cMPlayerControl::ProcessKey(eKeys Key)
   1.489 +{
   1.490 +  if(!player->Active()) { Hide(); Stop(); return osEnd; }
   1.491 +
   1.492 +  if(!player->SlaveMode()) {
   1.493 +    if(Key==kBlue) { Hide(); Stop(); return osEnd; }
   1.494 +    }
   1.495 +  else {
   1.496 +    if(visible) {
   1.497 +      if(timeoutShow && time(0)>timeoutShow) {
   1.498 +        Hide(); ShowMode();
   1.499 +        timeoutShow = 0;
   1.500 +        }
   1.501 +      else {
   1.502 +        if(modeOnly) ShowMode();
   1.503 +        else ShowProgress();
   1.504 +        }
   1.505 +      }
   1.506 +    else ShowTitle();
   1.507 +
   1.508 +    if(jumpactive && Key != kNone) {
   1.509 +      JumpProcess(Key);
   1.510 +      return osContinue;
   1.511 +      }
   1.512 +
   1.513 +    bool DoShowMode = true;
   1.514 +    switch (Key) {
   1.515 +      case kPlay:
   1.516 +      case kUp:      player->Play(); break;
   1.517 +
   1.518 +      case kPause:
   1.519 +      case kDown:    player->Pause(); break;
   1.520 +
   1.521 +      case kFastRew|k_Repeat:
   1.522 +      case kFastRew:
   1.523 +      case kLeft|k_Repeat:
   1.524 +      case kLeft:    player->SkipSeconds(-10); break;
   1.525 +
   1.526 +      case kFastFwd|k_Repeat:
   1.527 +      case kFastFwd:
   1.528 +      case kRight|k_Repeat:
   1.529 +      case kRight:   player->SkipSeconds(10); break;
   1.530 +
   1.531 +      case kRed:     Jump(); break;
   1.532 +
   1.533 +      case kGreen|k_Repeat:                      // temporary use
   1.534 +      case kGreen:   player->SkipSeconds(-60); break;
   1.535 +      case kYellow|k_Repeat:
   1.536 +      case kYellow:  player->SkipSeconds(60); break;
   1.537 +  //    case kGreen|k_Repeat:                      // reserved for future use
   1.538 +  //    case kGreen:   player->SkipPrev(); break;
   1.539 +  //    case kYellow|k_Repeat:
   1.540 +  //    case kYellow:  player->SkipNext(); break;
   1.541 +
   1.542 +      case kBack:
   1.543 +#if APIVERSNUM >= 10332
   1.544 +                     Hide();
   1.545 +                     cRemote::CallPlugin(i18n_name);
   1.546 +                     return osBack;
   1.547 +#endif
   1.548 +      case kStop:
   1.549 +      case kBlue:    Hide(); Stop(); return osEnd;
   1.550 +
   1.551 +      default:
   1.552 +        DoShowMode = false;
   1.553 +        switch(Key) {
   1.554 +          case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; }
   1.555 +                    else ShowTimed();
   1.556 +                    break;
   1.557 +          case k0:
   1.558 +          case k1:
   1.559 +          case k2:
   1.560 +          case k3:
   1.561 +          case k4:
   1.562 +          case k5:
   1.563 +          case k6:
   1.564 +          case k7:
   1.565 +          case k8:
   1.566 +          case k9:  {
   1.567 +                    const char *cmd=MPlayerSetup.KeyCmd[Key-k0];
   1.568 +                    if(cmd[0]) player->KeyCmd(cmd);
   1.569 +                    }
   1.570 +                    break;
   1.571 +          default:  break;
   1.572 +          }
   1.573 +        break;
   1.574 +      }
   1.575 +
   1.576 +    if(DoShowMode) ShowMode();
   1.577 +    }
   1.578 +  return osContinue;
   1.579 +}
   1.580 +
   1.581 +// --- cMenuMPlayAid -----------------------------------------------------------
   1.582 +
   1.583 +class cMenuMPlayAid : public cOsdMenu {
   1.584 +public:
   1.585 +  cMenuMPlayAid(void);
   1.586 +  virtual eOSState ProcessKey(eKeys Key);
   1.587 +  };
   1.588 +
   1.589 +cMenuMPlayAid::cMenuMPlayAid(void)
   1.590 +:cOsdMenu(tr("MPlayer Audio ID"),20)
   1.591 +{
   1.592 +  Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255));
   1.593 +  Display();
   1.594 +}
   1.595 +
   1.596 +eOSState cMenuMPlayAid::ProcessKey(eKeys Key)
   1.597 +{
   1.598 +  eOSState state=cOsdMenu::ProcessKey(Key);
   1.599 +  if(state==osUnknown) {
   1.600 +    switch(Key) {
   1.601 +      case kOk: state=osBack; break;
   1.602 +      default:  break;
   1.603 +      }
   1.604 +    }
   1.605 +  return state;
   1.606 +}
   1.607 +
   1.608 +// --- cMenuMPlayBrowse ---------------------------------------------------------
   1.609 +
   1.610 +class cMenuMPlayBrowse : public cMenuBrowse {
   1.611 +private:
   1.612 +  bool sourcing, aidedit;
   1.613 +  eOSState Source(bool second);
   1.614 +  eOSState Summary(void);
   1.615 +protected:
   1.616 +  virtual void SetButtons(void);
   1.617 +public:
   1.618 +  cMenuMPlayBrowse(void);
   1.619 +  virtual eOSState ProcessKey(eKeys Key);
   1.620 +  };
   1.621 +
   1.622 +static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 };
   1.623 +
   1.624 +cMenuMPlayBrowse::cMenuMPlayBrowse(void)
   1.625 +:cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum)
   1.626 +{
   1.627 +  sourcing=aidedit=false;
   1.628 +  SetButtons();
   1.629 +}
   1.630 +
   1.631 +void cMenuMPlayBrowse::SetButtons(void)
   1.632 +{
   1.633 +  static char blue[12];
   1.634 +  snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid);
   1.635 +  SetHelp(tr(BUTTON"Play"), MPlayerSetup.ResumeMode ? tr(BUTTON"Rewind"):0, tr("Source"), blue);
   1.636 +  Display();
   1.637 +}
   1.638 +
   1.639 +eOSState cMenuMPlayBrowse::Source(bool second)
   1.640 +{
   1.641 +  if(HasSubMenu()) return osContinue;
   1.642 +
   1.643 +  if(!second) {
   1.644 +    sourcing=true;
   1.645 +    return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source")));
   1.646 +    }
   1.647 +  sourcing=false;
   1.648 +  cFileSource *src=cMenuSource::GetSelected();
   1.649 +  if(src) {
   1.650 +    MPlaySources.SetSource(src);
   1.651 +    SetSource(src);
   1.652 +    NewDir(0);
   1.653 +    }
   1.654 +  return osContinue;
   1.655 +}
   1.656 +
   1.657 +eOSState cMenuMPlayBrowse::Summary(void)
   1.658 +{
   1.659 +  cFileObj *item=CurrentItem();
   1.660 +  if(item && item->Type()==otFile) {
   1.661 +    static const char *exts[] = { ".summary",".txt",".nfo",0 };
   1.662 +    for(int i=0; exts[i]; i++) {
   1.663 +      char buff[4096];
   1.664 +      strn0cpy(buff,item->FullPath(),sizeof(buff)-20);
   1.665 +      char *e=&buff[strlen(buff)];
   1.666 +      strn0cpy(e,exts[i],20);
   1.667 +      int fd=open(buff,O_RDONLY);
   1.668 +      *e=0;
   1.669 +      if(fd<0 && (e=rindex(buff,'.'))) {
   1.670 +        strn0cpy(e,exts[i],20);
   1.671 +        fd=open(buff,O_RDONLY);
   1.672 +        }
   1.673 +      if(fd>=0) {
   1.674 +        int r=read(fd,buff,sizeof(buff)-1);
   1.675 +        close(fd);
   1.676 +        if(r>0) {
   1.677 +          buff[r]=0;
   1.678 +          return AddSubMenu(new cMenuText(tr("Summary"),buff));
   1.679 +          }
   1.680 +        }
   1.681 +      }
   1.682 +    }
   1.683 +  return osContinue;
   1.684 +}
   1.685 +
   1.686 +eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key)
   1.687 +{
   1.688 +  eOSState state=cOsdMenu::ProcessKey(Key);
   1.689 +  if(state==osContinue && !HasSubMenu()) {
   1.690 +    if(sourcing) return Source(true);
   1.691 +    if(aidedit) { aidedit=false; SetButtons(); }
   1.692 +    }
   1.693 +  bool rew=false;
   1.694 +  if(state==osUnknown) {
   1.695 +    switch(Key) {
   1.696 +      case kGreen:
   1.697 +        {
   1.698 +        cFileObj *item=CurrentItem();
   1.699 +        if(item && item->Type()==otFile) {
   1.700 +          lastselect=new cFileObj(item);
   1.701 +          state=osBack;
   1.702 +          rew=true;
   1.703 +          } 
   1.704 +        else state=osContinue;
   1.705 +        break;
   1.706 +        }
   1.707 +      case kYellow:
   1.708 +        state=Source(false);
   1.709 +        break;
   1.710 +      case kBlue:
   1.711 +        aidedit=true;
   1.712 +        state=AddSubMenu(new cMenuMPlayAid);
   1.713 +        break;
   1.714 +      case k0:
   1.715 +        state=Summary();
   1.716 +        break;
   1.717 +      default:
   1.718 +        break;
   1.719 +      }
   1.720 +    }
   1.721 +  if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
   1.722 +  if(state==osBack && lastselect) {
   1.723 +    cMPlayerControl::SetFile(lastselect,rew);
   1.724 +    cControl::Launch(new cMPlayerControl);
   1.725 +    return osEnd;
   1.726 +    }
   1.727 +  return state;
   1.728 +}
   1.729 +
   1.730 +// --- cPluginMPlayer ----------------------------------------------------------
   1.731 +
   1.732 +static const char *VERSION        = PLUGIN_VERSION;
   1.733 +static const char *DESCRIPTION    = "Media replay via MPlayer";
   1.734 +static const char *MAINMENUENTRY  = "MPlayer";
   1.735 +
   1.736 +class cPluginMPlayer : public cPlugin {
   1.737 +private:
   1.738 +#if APIVERSNUM >= 10330
   1.739 +  bool ExternalPlay(const char *path, bool test);
   1.740 +#endif
   1.741 +public:
   1.742 +  cPluginMPlayer(void);
   1.743 +  virtual ~cPluginMPlayer();
   1.744 +  virtual const char *Version(void) { return VERSION; }
   1.745 +  virtual const char *Description(void) { return tr(DESCRIPTION); }
   1.746 +  virtual const char *CommandLineHelp(void);
   1.747 +  virtual bool ProcessArgs(int argc, char *argv[]);
   1.748 +#if APIVERSNUM >= 10131
   1.749 +  virtual bool Initialize(void);
   1.750 +#else
   1.751 +  virtual bool Start(void);
   1.752 +#endif
   1.753 +  virtual const char *MainMenuEntry(void);
   1.754 +  virtual cOsdMenu *MainMenuAction(void);
   1.755 +  virtual cMenuSetupPage *SetupMenu(void);
   1.756 +  virtual bool SetupParse(const char *Name, const char *Value);
   1.757 +#if APIVERSNUM >= 10330
   1.758 +  virtual bool Service(const char *Id, void *Data);
   1.759 +#if APIVERSNUM >= 10331
   1.760 +  virtual const char **SVDRPHelpPages(void);
   1.761 +  virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
   1.762 +#endif
   1.763 +#endif
   1.764 +  };
   1.765 +
   1.766 +cPluginMPlayer::cPluginMPlayer(void)
   1.767 +{
   1.768 +  // Initialize any member variables here.
   1.769 +  // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
   1.770 +  // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
   1.771 +  status=0;
   1.772 +}
   1.773 +
   1.774 +cPluginMPlayer::~cPluginMPlayer()
   1.775 +{
   1.776 +  delete status;
   1.777 +}
   1.778 +
   1.779 +const char *cPluginMPlayer::CommandLineHelp(void)
   1.780 +{
   1.781 +  static char *help_str=0;
   1.782 +  
   1.783 +  free(help_str);    //                                     for easier orientation, this is column 80|
   1.784 +  asprintf(&help_str,"  -m CMD,   --mount=CMD    use CMD to mount/unmount/eject mp3 sources\n"
   1.785 +                     "                           (default: %s)\n"
   1.786 +                     "  -M CMD,   --mplayer=CMD  use CMD when calling MPlayer\n"
   1.787 +                     "                           (default: %s)\n"
   1.788 +                     "  -S SUB,   --sources=SUB  search sources config in SUB subdirectory\n"
   1.789 +                     "                           (default: %s)\n"
   1.790 +                     "  -R DIR,   --resume=DIR   store global resume file in DIR\n"
   1.791 +                     "                           (default: %s)\n",
   1.792 +                     mountscript,
   1.793 +                     MPlayerCmd,
   1.794 +                     sourcesSub ? sourcesSub:"none",
   1.795 +                     globalResumeDir ? globalResumeDir:"video dir"
   1.796 +                     );
   1.797 +  return help_str;
   1.798 +}
   1.799 +
   1.800 +bool cPluginMPlayer::ProcessArgs(int argc, char *argv[])
   1.801 +{
   1.802 +  static struct option long_options[] = {
   1.803 +      { "mount",    required_argument, NULL, 'm' },
   1.804 +      { "mplayer",  required_argument, NULL, 'M' },
   1.805 +      { "sources",  required_argument, NULL, 'S' },
   1.806 +      { "resume",   required_argument, NULL, 'R' },
   1.807 +      { NULL }
   1.808 +    };
   1.809 +
   1.810 +  int c, option_index = 0;
   1.811 +  while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) {
   1.812 +    switch (c) {
   1.813 +      case 'm': mountscript=optarg; break;
   1.814 +      case 'M': MPlayerCmd=optarg; break;
   1.815 +      case 'S': sourcesSub=optarg; break;
   1.816 +      case 'R': globalResumeDir=optarg; break;
   1.817 +      default:  return false;
   1.818 +      }
   1.819 +    }
   1.820 +  return true;
   1.821 +}
   1.822 +
   1.823 +#if APIVERSNUM >= 10131
   1.824 +bool cPluginMPlayer::Initialize(void)
   1.825 +#else
   1.826 +bool cPluginMPlayer::Start(void)
   1.827 +#endif
   1.828 +{
   1.829 +  if(!CheckVDRVersion(1,1,16,"mplayer")) return false;
   1.830 +  i18n_name=Name();
   1.831 +  MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf"));
   1.832 +  if(MPlaySources.Count()<1) {
   1.833 +    esyslog("ERROR: you must have defined at least one source in mplayersources.conf");
   1.834 +    fprintf(stderr,"No source(s) defined in mplayersources.conf\n");
   1.835 +    return false;
   1.836 +    }
   1.837 +  RegisterI18n(Phrases);
   1.838 +  if(!(status=new cMPlayerStatus)) return false;
   1.839 +  return true;
   1.840 +}
   1.841 +
   1.842 +const char *cPluginMPlayer::MainMenuEntry(void)
   1.843 +{
   1.844 +  return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
   1.845 +}
   1.846 +
   1.847 +cOsdMenu *cPluginMPlayer::MainMenuAction(void)
   1.848 +{
   1.849 +  return new cMenuMPlayBrowse;
   1.850 +}
   1.851 +
   1.852 +cMenuSetupPage *cPluginMPlayer::SetupMenu(void)
   1.853 +{
   1.854 +  return new cMenuSetupMPlayer;
   1.855 +}
   1.856 +
   1.857 +bool cPluginMPlayer::SetupParse(const char *Name, const char *Value)
   1.858 +{
   1.859 +  if(      !strcasecmp(Name, "ControlMode"))  MPlayerSetup.SlaveMode    = atoi(Value);
   1.860 +  else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value);
   1.861 +  else if (!strcasecmp(Name, "ResumeMode"))   MPlayerSetup.ResumeMode   = atoi(Value);
   1.862 +  else if (!strcasecmp(Name, "OsdPos"))       MPlayerSetup.OsdPos       = atoi(Value);
   1.863 +  else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
   1.864 +    strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
   1.865 +  else return false;
   1.866 +  return true;
   1.867 +}
   1.868 +
   1.869 +#if APIVERSNUM >= 10330
   1.870 +
   1.871 +bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
   1.872 +{
   1.873 +  char real[PATH_MAX+1];
   1.874 +  if(realpath(path,real)) {
   1.875 +    cFileSource *src=MPlaySources.FindSource(real);
   1.876 +    if(src) {
   1.877 +      cFileObj *item=new cFileObj(src,0,0,otFile);
   1.878 +      if(item) {
   1.879 +        item->SplitAndSet(real);
   1.880 +        if(item->GuessType()) {
   1.881 +          if(item->Exists()) {
   1.882 +            if(!test) {
   1.883 +              cMPlayerControl::SetFile(item,true);
   1.884 +              cControl::Launch(new cMPlayerControl);
   1.885 +              cControl::Attach();
   1.886 +              }
   1.887 +            delete item;
   1.888 +            return true;
   1.889 +            }
   1.890 +          else dsyslog("MPlayer service: cannot play '%s'",path);
   1.891 +          }
   1.892 +        else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
   1.893 +        delete item;
   1.894 +        }
   1.895 +      }
   1.896 +    else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
   1.897 +    }
   1.898 +  else if(errno!=ENOENT && errno!=ENOTDIR)
   1.899 +    esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
   1.900 +  return false;
   1.901 +}
   1.902 +
   1.903 +bool cPluginMPlayer::Service(const char *Id, void *Data)
   1.904 +{
   1.905 +  if(!strcasecmp(Id,"MPlayer-Play-v1")) {
   1.906 +    if(Data) {
   1.907 +      struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   1.908 +      msd->result=ExternalPlay(msd->data.filename,false);
   1.909 +      }
   1.910 +    return true;
   1.911 +    }
   1.912 +  else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
   1.913 +    if(Data) {
   1.914 +      struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
   1.915 +      msd->result=ExternalPlay(msd->data.filename,true);
   1.916 +      }
   1.917 +    return true;
   1.918 +    }
   1.919 +  return false;
   1.920 +}
   1.921 +
   1.922 +#if APIVERSNUM >= 10331
   1.923 +
   1.924 +const char **cPluginMPlayer::SVDRPHelpPages(void)
   1.925 +{
   1.926 +  static const char *HelpPages[] = {
   1.927 +    "PLAY <filename>\n"
   1.928 +    "    Triggers playback of file 'filename'.",
   1.929 +    "TEST <filename>\n"
   1.930 +    "    Tests is playback of file 'filename' is possible.",
   1.931 +    NULL
   1.932 +    };
   1.933 +  return HelpPages;
   1.934 +}
   1.935 +
   1.936 +cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
   1.937 +{
   1.938 +  if(!strcasecmp(Command,"PLAY")) {
   1.939 +    if(*Option) {
   1.940 +      if(ExternalPlay(Option,false)) return "Playback triggered";
   1.941 +      else { ReplyCode=550; return "Playback failed"; }
   1.942 +      }
   1.943 +    else { ReplyCode=501; return "Missing filename"; }
   1.944 +    }
   1.945 +  else if(!strcasecmp(Command,"TEST")) {
   1.946 +    if(*Option) {
   1.947 +      if(ExternalPlay(Option,true)) return "Playback possible";
   1.948 +      else { ReplyCode=550; return "Playback not possible"; }
   1.949 +      }
   1.950 +    else { ReplyCode=501; return "Missing filename"; }
   1.951 +    }
   1.952 +  return NULL;
   1.953 +}
   1.954 +
   1.955 +#endif // 1.3.31
   1.956 +#endif // 1.3.30
   1.957 +
   1.958 +VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!