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!