nathan@0: /* nathan@0: * MP3/MPlayer plugin to VDR (C++) nathan@0: * nathan@0: * (C) 2001-2007 Stefan Huelswitt nathan@0: * nathan@0: * This code is free software; you can redistribute it and/or nathan@0: * modify it under the terms of the GNU General Public License nathan@0: * as published by the Free Software Foundation; either version 2 nathan@0: * of the License, or (at your option) any later version. nathan@0: * nathan@0: * This code is distributed in the hope that it will be useful, nathan@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of nathan@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nathan@0: * GNU General Public License for more details. nathan@0: * nathan@0: * You should have received a copy of the GNU General Public License nathan@0: * along with this program; if not, write to the Free Software nathan@0: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. nathan@0: * Or, point your browser to http://www.gnu.org/copyleft/gpl.html nathan@0: */ nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: nathan@0: #include "common.h" nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #ifdef HAVE_BEAUTYPATCH nathan@0: #include nathan@0: #endif nathan@0: #if APIVERSNUM >= 10307 nathan@0: #include nathan@0: #endif nathan@0: #if APIVERSNUM >= 10332 nathan@0: #include nathan@0: #endif nathan@0: nathan@0: #if APIVERSNUM > 10307 nathan@0: #include nathan@0: #elif APIVERSNUM == 10307 nathan@0: class cMenuText : public cOsdMenu { nathan@0: private: nathan@0: char *text; nathan@0: public: nathan@0: cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd); nathan@0: virtual ~cMenuText(); nathan@0: void SetText(const char *Text); nathan@0: virtual void Display(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: #else nathan@0: class cMenuText : public cOsdMenu { nathan@0: public: nathan@0: cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: #endif nathan@0: nathan@0: #include "setup.h" nathan@0: #include "setup-mplayer.h" nathan@0: #include "menu.h" nathan@0: #include "player-mplayer.h" nathan@0: #include "data.h" nathan@0: #include "data-src.h" nathan@0: #include "i18n.h" nathan@0: #include "version.h" nathan@0: #include "service.h" nathan@0: nathan@0: const char *sourcesSub=0; nathan@0: cFileSources MPlaySources; nathan@0: nathan@2: static const char *plugin_name=0; nathan@2: nathan@0: // --- cMenuSetupMPlayer -------------------------------------------------------- nathan@0: nathan@0: class cMenuSetupMPlayer : public cMenuSetupPage { nathan@0: private: nathan@0: cMPlayerSetup data; nathan@0: const char *res[3]; nathan@0: protected: nathan@0: virtual void Store(void); nathan@0: public: nathan@0: cMenuSetupMPlayer(void); nathan@0: }; nathan@0: nathan@0: cMenuSetupMPlayer::cMenuSetupMPlayer(void) nathan@0: { nathan@0: data=MPlayerSetup; nathan@0: SetSection(tr("MPlayer")); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"), &data.SlaveMode, tr("Traditional"), tr("Slave"))); nathan@0: #if APIVERSNUM < 10307 nathan@0: Add(new cMenuEditIntItem( tr("Setup.MPlayer$OSD position"), &data.OsdPos, 0, 6)); nathan@0: #endif nathan@0: res[0]=tr("disabled"); nathan@0: res[1]=tr("global only"); nathan@0: res[2]=tr("local first"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"), &data.ResumeMode, 3, res)); nathan@0: Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu)); nathan@0: for(int i=0; i<10; i++) { nathan@0: char name[32]; nathan@0: snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i); nathan@0: static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" }; nathan@0: Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed)); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMenuSetupMPlayer::Store(void) nathan@0: { nathan@0: MPlayerSetup=data; nathan@0: SetupStore("ControlMode", MPlayerSetup.SlaveMode); nathan@0: SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu); nathan@0: SetupStore("ResumeMode", MPlayerSetup.ResumeMode); nathan@0: #if APIVERSNUM < 10307 nathan@0: SetupStore("OsdPos", MPlayerSetup.OsdPos); nathan@0: #endif nathan@0: for(int i=0; i<10; i++) { nathan@0: char name[16]; nathan@0: snprintf(name,sizeof(name),"KeyCmd%d",i); nathan@0: SetupStore(name,MPlayerSetup.KeyCmd[i]); nathan@0: } nathan@0: } nathan@0: nathan@0: // --- cMPlayerControl --------------------------------------------------------- nathan@0: nathan@0: class cMPlayerControl : public cControl { nathan@0: private: nathan@0: static cFileObj *file; nathan@0: static bool rewind; nathan@0: cMPlayerPlayer *player; nathan@0: #if APIVERSNUM >= 10307 nathan@0: cSkinDisplayReplay *display; nathan@0: #endif nathan@0: bool visible, modeOnly, haveBeauty; nathan@0: time_t timeoutShow; nathan@0: int lastCurrent, lastTotal; nathan@0: char *lastReplayMsg; nathan@0: // nathan@0: bool jumpactive, jumphide, jumpmode; nathan@0: int jumpval; nathan@0: // nathan@0: void Stop(void); nathan@0: void ShowTimed(int Seconds=0); nathan@0: void DisplayAtBottom(const char *s); nathan@0: void ShowProgress(void); nathan@0: void ShowMode(void); nathan@0: void ShowTitle(void); nathan@0: void Jump(void); nathan@0: void JumpProcess(eKeys Key); nathan@0: void JumpDisplay(void); nathan@0: public: nathan@0: cMPlayerControl(void); nathan@0: virtual ~cMPlayerControl(); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: virtual void Show(void) { ShowTimed(); } nathan@0: virtual void Hide(void); nathan@0: static void SetFile(const cFileObj *File, bool Rewind); nathan@0: }; nathan@0: nathan@0: cFileObj *cMPlayerControl::file=0; nathan@0: bool cMPlayerControl::rewind=false; nathan@0: nathan@0: cMPlayerControl::cMPlayerControl(void) nathan@0: :cControl(player=new cMPlayerPlayer(file,rewind)) nathan@0: { nathan@0: visible=modeOnly=jumpactive=haveBeauty=false; nathan@0: lastReplayMsg=0; nathan@0: #if APIVERSNUM >= 10307 nathan@0: display=0; nathan@0: #else nathan@0: #ifdef HAVE_BEAUTYPATCH nathan@0: #if APIVERSNUM >= 10300 nathan@0: const cFont *sym=cFont::GetFont(fontSym); nathan@0: const cFont *osd=cFont::GetFont(fontOsd); nathan@0: const cFont::tCharData *symD=sym->CharData(32); nathan@0: const cFont::tCharData *osdD=osd->CharData(32); nathan@0: #else //APIVERSNUM >= 10300 nathan@0: cFont *sym=new cFont(fontSym); nathan@0: cFont *osd=new cFont(fontOsd); nathan@0: const cFont::tCharData *symD=sym->CharData(32); nathan@0: const cFont::tCharData *osdD=osd->CharData(32); nathan@0: delete sym; nathan@0: delete osd; nathan@0: #endif //APIVERSNUM >= 10300 nathan@0: if(symD != osdD) haveBeauty=true; nathan@0: d(printf("mplayer: beauty patch %sdetected\n",haveBeauty?"":"NOT ")) nathan@0: #endif //HAVE_BEAUTYPATCH nathan@0: #endif //APIVERSNUM >= 10307 nathan@0: ShowTitle(); nathan@0: } nathan@0: nathan@0: cMPlayerControl::~cMPlayerControl() nathan@0: { nathan@0: Stop(); nathan@0: #if APIVERSNUM >= 10338 nathan@0: cStatus::MsgReplaying(this,0,0,false); nathan@0: #else nathan@0: cStatus::MsgReplaying(this, NULL); nathan@0: #endif nathan@0: free(lastReplayMsg); nathan@0: } nathan@0: nathan@0: void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind) nathan@0: { nathan@0: delete file; nathan@0: file=File ? new cFileObj(File) : 0; nathan@0: rewind=Rewind; nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Stop(void) nathan@0: { nathan@0: delete player; player=0; nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowTimed(int Seconds) nathan@0: { nathan@0: if(modeOnly) Hide(); nathan@0: if(!visible) { nathan@0: ShowProgress(); nathan@0: timeoutShow = Seconds>0 ? time(0)+Seconds : 0; nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Hide(void) nathan@0: { nathan@0: if(visible) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: delete display; display=0; nathan@0: #else nathan@0: Interface->Close(); nathan@0: #endif nathan@0: visible=modeOnly=false; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(false); nathan@0: #else nathan@0: needsFastResponse=false; nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::DisplayAtBottom(const char *s) nathan@0: { nathan@0: #if APIVERSNUM < 10307 nathan@0: const int p=modeOnly ? 0 : 2; nathan@0: if(s) { nathan@0: const int d=max(Width()-cOsd::WidthInCells(s),0) / 2; nathan@0: if(modeOnly) Interface->Fill(0, p, Interface->Width(), 1, clrTransparent); nathan@0: Interface->Write(d, p, s); nathan@0: } nathan@0: else nathan@0: Interface->Fill(12, p, Width() - 22, 1, clrBackground); nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowTitle(void) nathan@0: { nathan@0: const char *path=0; nathan@0: bool release=true; nathan@0: if(player) path=player->GetCurrentName(); nathan@0: if(!path) { nathan@0: path=file->FullPath(); nathan@0: release=false; nathan@0: } nathan@0: if(path) { nathan@0: const char *name=rindex(path,'/'); nathan@0: if(name) name++; else name=path; nathan@0: if(!lastReplayMsg || strcmp(lastReplayMsg,path)) { nathan@0: #if APIVERSNUM >= 10338 nathan@0: cStatus::MsgReplaying(this,name,path,true); nathan@0: #else nathan@0: cStatus::MsgReplaying(this,path); nathan@0: #endif nathan@0: free(lastReplayMsg); nathan@0: lastReplayMsg=strdup(path); nathan@0: } nathan@0: if(visible) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(display) display->SetTitle(name); nathan@0: #else nathan@0: int n=strlen(name); nathan@0: if(n>Width()) { nathan@0: n=n-Width()+4; if(n<0) n=0; nathan@0: char str[72]; nathan@0: snprintf(str,sizeof(str),"... %s",name+n); nathan@0: Interface->Write(0,0,str); nathan@0: } nathan@0: else Interface->Write(0,0,name); nathan@0: #endif nathan@0: } nathan@0: } nathan@0: if(release) free((void *)path); nathan@0: } nathan@0: nathan@0: void cMPlayerControl::ShowProgress(void) nathan@0: { nathan@0: int Current, Total; nathan@0: nathan@0: if(GetIndex(Current,Total) && Total>0) { nathan@0: bool flush=false; nathan@0: if(!visible) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: display=Skins.Current()->DisplayReplay(false); nathan@0: #else nathan@0: Interface->Open(Setup.OSDwidth,-MPlayerSetup.OsdPos-3); nathan@0: Interface->Clear(); nathan@0: if(MPlayerSetup.OsdPos>0) Interface->Fill(0,3,Interface->Width(),MPlayerSetup.OsdPos,clrTransparent); nathan@0: #endif nathan@0: visible=true; modeOnly=false; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(true); nathan@0: #else nathan@0: needsFastResponse=true; nathan@0: #endif nathan@0: lastCurrent=lastTotal=-1; nathan@0: flush=true; nathan@0: } nathan@0: nathan@0: if(abs(Current-lastCurrent)>12) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(Total>0) display->SetProgress(Current, Total); nathan@0: display->SetCurrent(IndexToHMSF(Current)); nathan@0: display->SetTotal(IndexToHMSF(Total)); nathan@0: bool Play, Forward; nathan@0: int Speed; nathan@0: if(GetReplayMode(Play,Forward,Speed)) nathan@0: display->SetMode(Play, Forward, Speed); nathan@0: #else nathan@0: cProgressBar ProgressBar(Width() * cOsd::CellWidth(), cOsd::LineHeight(), Current, Total); nathan@0: Interface->SetBitmap(0, cOsd::LineHeight(), ProgressBar); nathan@0: Interface->Write(0,2,IndexToHMSF(Current)); nathan@0: Interface->Write(-7,2,IndexToHMSF(Total)); nathan@0: #endif nathan@0: ShowTitle(); nathan@0: flush=true; nathan@0: lastCurrent=Current; lastTotal=Total; nathan@0: } nathan@0: if(flush) nathan@0: #if APIVERSNUM >= 10307 nathan@0: Skins.Flush(); nathan@0: #else nathan@0: Interface->Flush(); nathan@0: #endif nathan@0: ShowMode(); nathan@0: } nathan@0: } nathan@0: nathan@0: #if APIVERSNUM < 10307 nathan@0: #ifdef HAVE_BEAUTYPATCH nathan@0: int forwSym[] = { FSYM_FORW,FSYM_FORW1,FSYM_FORW2,FSYM_FORW3 }; nathan@0: int backSym[] = { FSYM_BACK,FSYM_BACK1,FSYM_BACK2,FSYM_BACK3 }; nathan@0: #endif nathan@0: #endif nathan@0: nathan@0: void cMPlayerControl::ShowMode(void) nathan@0: { nathan@0: if(Setup.ShowReplayMode && !jumpactive) { nathan@0: bool Play, Forward; nathan@0: int Speed; nathan@0: if(GetReplayMode(Play, Forward, Speed)) { nathan@0: bool NormalPlay = (Play && Speed == -1); nathan@0: nathan@0: if(!visible) { nathan@0: if(NormalPlay) return; nathan@0: #if APIVERSNUM >= 10307 nathan@0: display = Skins.Current()->DisplayReplay(true); nathan@0: #else nathan@0: Interface->Open(0,-MPlayerSetup.OsdPos-1); nathan@0: #endif nathan@0: visible=modeOnly=true; nathan@0: } nathan@0: nathan@0: if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; nathan@0: nathan@0: #if APIVERSNUM >= 10307 nathan@0: display->SetMode(Play, Forward, Speed); nathan@0: #else nathan@0: char buf[16]; nathan@0: eDvbFont OldFont; nathan@0: #ifdef HAVE_BEAUTYPATCH nathan@0: if(haveBeauty) { nathan@0: int i=0; nathan@0: if(!(Width()&1)) buf[i++]=' '; nathan@0: buf[i]=FSYM_EMPTY; if(Speed>=0 && !Forward) buf[i]=backSym[Speed]; nathan@0: i++; nathan@0: buf[i++]=Play?(Speed==-1?FSYM_PLAY:FSYM_EMPTY):FSYM_PAUSE; nathan@0: buf[i]=FSYM_EMPTY; if(Speed>=0 && Forward) buf[i]=forwSym[Speed]; nathan@0: i++; nathan@0: if(!(Width()&1)) buf[i++]=' '; nathan@0: buf[i]=0; nathan@0: OldFont = Interface->SetFont(fontSym); nathan@0: } nathan@0: else { nathan@0: #endif //HAVE_BEAUTYPATCH nathan@0: const char *Mode; nathan@0: if (Speed == -1) Mode = Play ? " > " : " || "; nathan@0: else if (Play) Mode = Forward ? " X>> " : " < " : " <|X "; nathan@0: strn0cpy(buf, Mode, sizeof(buf)); nathan@0: char *p = strchr(buf, 'X'); nathan@0: if(p) *p = Speed > 0 ? '1' + Speed - 1 : ' '; nathan@0: OldFont = Interface->SetFont(fontFix); nathan@0: #ifdef HAVE_BEAUTYPATCH nathan@0: } nathan@0: #endif //HAVE_BEAUTYPATCH nathan@0: DisplayAtBottom(buf); nathan@0: Interface->SetFont(OldFont); nathan@0: #endif //APIVERSNUM >= 10307 nathan@0: } nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::JumpDisplay(void) nathan@0: { nathan@0: char buf[64]; nathan@2: const char *j=trVDR("Jump: "), u=jumpmode?'%':'m'; nathan@0: if(!jumpval) sprintf(buf,"%s- %c", j,u); nathan@0: else sprintf(buf,"%s%d- %c",j,jumpval,u); nathan@0: #if APIVERSNUM >= 10307 nathan@0: display->SetJump(buf); nathan@0: #else nathan@0: DisplayAtBottom(buf); nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMPlayerControl::JumpProcess(eKeys Key) nathan@0: { nathan@0: const int n=Key-k0; nathan@0: switch (Key) { nathan@0: case k0 ... k9: nathan@0: { nathan@0: const int max=jumpmode?100:lastTotal; nathan@0: if(jumpval*10+n <= max) jumpval=jumpval*10+n; nathan@0: JumpDisplay(); nathan@0: } nathan@0: break; nathan@0: case kBlue: nathan@0: jumpmode=!jumpmode; jumpval=0; nathan@0: DisplayAtBottom(0); JumpDisplay(); nathan@0: break; nathan@0: case kPlay: nathan@0: case kUp: nathan@0: player->Goto(jumpval*(jumpmode?1:60),jumpmode,false); nathan@0: jumpactive=false; nathan@0: break; nathan@0: case kFastRew: nathan@0: case kFastFwd: nathan@0: case kLeft: nathan@0: case kRight: nathan@0: if(!jumpmode) { nathan@0: player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1)); nathan@0: jumpactive=false; nathan@0: } nathan@0: break; nathan@0: default: nathan@0: jumpactive=false; nathan@0: break; nathan@0: } nathan@0: nathan@0: if(!jumpactive) { nathan@0: if(jumphide) Hide(); nathan@0: else nathan@0: #if APIVERSNUM >= 10307 nathan@0: display->SetJump(0); nathan@0: #else nathan@0: DisplayAtBottom(0); nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: void cMPlayerControl::Jump(void) nathan@0: { nathan@0: jumpval=0; jumphide=jumpmode=false; nathan@0: if(!visible) { nathan@0: ShowTimed(); if(!visible) return; nathan@0: jumphide=true; nathan@0: } nathan@0: JumpDisplay(); nathan@0: jumpactive=true; nathan@0: } nathan@0: nathan@0: eOSState cMPlayerControl::ProcessKey(eKeys Key) nathan@0: { nathan@0: if(!player->Active()) { Hide(); Stop(); return osEnd; } nathan@0: nathan@0: if(!player->SlaveMode()) { nathan@0: if(Key==kBlue) { Hide(); Stop(); return osEnd; } nathan@0: } nathan@0: else { nathan@0: if(visible) { nathan@0: if(timeoutShow && time(0)>timeoutShow) { nathan@0: Hide(); ShowMode(); nathan@0: timeoutShow = 0; nathan@0: } nathan@0: else { nathan@0: if(modeOnly) ShowMode(); nathan@0: else ShowProgress(); nathan@0: } nathan@0: } nathan@0: else ShowTitle(); nathan@0: nathan@0: if(jumpactive && Key != kNone) { nathan@0: JumpProcess(Key); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: bool DoShowMode = true; nathan@0: switch (Key) { nathan@0: case kPlay: nathan@0: case kUp: player->Play(); break; nathan@0: nathan@0: case kPause: nathan@0: case kDown: player->Pause(); break; nathan@0: nathan@0: case kFastRew|k_Repeat: nathan@0: case kFastRew: nathan@0: case kLeft|k_Repeat: nathan@0: case kLeft: player->SkipSeconds(-10); break; nathan@0: nathan@0: case kFastFwd|k_Repeat: nathan@0: case kFastFwd: nathan@0: case kRight|k_Repeat: nathan@0: case kRight: player->SkipSeconds(10); break; nathan@0: nathan@0: case kRed: Jump(); break; nathan@0: nathan@0: case kGreen|k_Repeat: // temporary use nathan@0: case kGreen: player->SkipSeconds(-60); break; nathan@0: case kYellow|k_Repeat: nathan@0: case kYellow: player->SkipSeconds(60); break; nathan@0: // case kGreen|k_Repeat: // reserved for future use nathan@0: // case kGreen: player->SkipPrev(); break; nathan@0: // case kYellow|k_Repeat: nathan@0: // case kYellow: player->SkipNext(); break; nathan@0: nathan@0: case kBack: nathan@0: #if APIVERSNUM >= 10332 nathan@0: Hide(); nathan@2: cRemote::CallPlugin(plugin_name); nathan@0: return osBack; nathan@0: #endif nathan@0: case kStop: nathan@0: case kBlue: Hide(); Stop(); return osEnd; nathan@0: nathan@0: default: nathan@0: DoShowMode = false; nathan@0: switch(Key) { nathan@0: case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; } nathan@0: else ShowTimed(); nathan@0: break; nathan@0: case k0: nathan@0: case k1: nathan@0: case k2: nathan@0: case k3: nathan@0: case k4: nathan@0: case k5: nathan@0: case k6: nathan@0: case k7: nathan@0: case k8: nathan@0: case k9: { nathan@0: const char *cmd=MPlayerSetup.KeyCmd[Key-k0]; nathan@0: if(cmd[0]) player->KeyCmd(cmd); nathan@0: } nathan@0: break; nathan@0: default: break; nathan@0: } nathan@0: break; nathan@0: } nathan@0: nathan@0: if(DoShowMode) ShowMode(); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: // --- cMenuMPlayAid ----------------------------------------------------------- nathan@0: nathan@0: class cMenuMPlayAid : public cOsdMenu { nathan@0: public: nathan@0: cMenuMPlayAid(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuMPlayAid::cMenuMPlayAid(void) nathan@0: :cOsdMenu(tr("MPlayer Audio ID"),20) nathan@0: { nathan@0: Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255)); nathan@0: Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayAid::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state=cOsdMenu::ProcessKey(Key); nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kOk: state=osBack; break; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cMenuMPlayBrowse --------------------------------------------------------- nathan@0: nathan@0: class cMenuMPlayBrowse : public cMenuBrowse { nathan@0: private: nathan@0: bool sourcing, aidedit; nathan@0: eOSState Source(bool second); nathan@0: eOSState Summary(void); nathan@0: protected: nathan@0: virtual void SetButtons(void); nathan@0: public: nathan@0: cMenuMPlayBrowse(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 }; nathan@0: nathan@0: cMenuMPlayBrowse::cMenuMPlayBrowse(void) nathan@0: :cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum) nathan@0: { nathan@0: sourcing=aidedit=false; nathan@0: SetButtons(); nathan@0: } nathan@0: nathan@0: void cMenuMPlayBrowse::SetButtons(void) nathan@0: { nathan@0: static char blue[12]; nathan@0: snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid); nathan@2: SetHelp(trVDR(BUTTON"Play"), MPlayerSetup.ResumeMode ? trVDR(BUTTON"Rewind"):0, tr("Source"), blue); nathan@0: Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::Source(bool second) nathan@0: { nathan@0: if(HasSubMenu()) return osContinue; nathan@0: nathan@0: if(!second) { nathan@0: sourcing=true; nathan@0: return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source"))); nathan@0: } nathan@0: sourcing=false; nathan@0: cFileSource *src=cMenuSource::GetSelected(); nathan@0: if(src) { nathan@0: MPlaySources.SetSource(src); nathan@0: SetSource(src); nathan@0: NewDir(0); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::Summary(void) nathan@0: { nathan@0: cFileObj *item=CurrentItem(); nathan@0: if(item && item->Type()==otFile) { nathan@0: static const char *exts[] = { ".summary",".txt",".nfo",0 }; nathan@0: for(int i=0; exts[i]; i++) { nathan@0: char buff[4096]; nathan@0: strn0cpy(buff,item->FullPath(),sizeof(buff)-20); nathan@0: char *e=&buff[strlen(buff)]; nathan@0: strn0cpy(e,exts[i],20); nathan@0: int fd=open(buff,O_RDONLY); nathan@0: *e=0; nathan@0: if(fd<0 && (e=rindex(buff,'.'))) { nathan@0: strn0cpy(e,exts[i],20); nathan@0: fd=open(buff,O_RDONLY); nathan@0: } nathan@0: if(fd>=0) { nathan@0: int r=read(fd,buff,sizeof(buff)-1); nathan@0: close(fd); nathan@0: if(r>0) { nathan@0: buff[r]=0; nathan@0: return AddSubMenu(new cMenuText(tr("Summary"),buff)); nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state=cOsdMenu::ProcessKey(Key); nathan@0: if(state==osContinue && !HasSubMenu()) { nathan@0: if(sourcing) return Source(true); nathan@0: if(aidedit) { aidedit=false; SetButtons(); } nathan@0: } nathan@0: bool rew=false; nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kGreen: nathan@0: { nathan@0: cFileObj *item=CurrentItem(); nathan@0: if(item && item->Type()==otFile) { nathan@0: lastselect=new cFileObj(item); nathan@0: state=osBack; nathan@0: rew=true; nathan@0: } nathan@0: else state=osContinue; nathan@0: break; nathan@0: } nathan@0: case kYellow: nathan@0: state=Source(false); nathan@0: break; nathan@0: case kBlue: nathan@0: aidedit=true; nathan@0: state=AddSubMenu(new cMenuMPlayAid); nathan@0: break; nathan@0: case k0: nathan@0: state=Summary(); nathan@0: break; nathan@0: default: nathan@0: break; nathan@0: } nathan@0: } nathan@0: if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); nathan@0: if(state==osBack && lastselect) { nathan@0: cMPlayerControl::SetFile(lastselect,rew); nathan@0: cControl::Launch(new cMPlayerControl); nathan@0: return osEnd; nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cPluginMPlayer ---------------------------------------------------------- nathan@0: nathan@0: static const char *VERSION = PLUGIN_VERSION; nathan@2: static const char *DESCRIPTION = trNOOP("Media replay via MPlayer"); nathan@0: static const char *MAINMENUENTRY = "MPlayer"; nathan@0: nathan@0: class cPluginMPlayer : public cPlugin { nathan@0: private: nathan@0: #if APIVERSNUM >= 10330 nathan@0: bool ExternalPlay(const char *path, bool test); nathan@0: #endif nathan@0: public: nathan@0: cPluginMPlayer(void); nathan@0: virtual ~cPluginMPlayer(); nathan@0: virtual const char *Version(void) { return VERSION; } nathan@0: virtual const char *Description(void) { return tr(DESCRIPTION); } nathan@0: virtual const char *CommandLineHelp(void); nathan@0: virtual bool ProcessArgs(int argc, char *argv[]); nathan@0: #if APIVERSNUM >= 10131 nathan@0: virtual bool Initialize(void); nathan@0: #else nathan@0: virtual bool Start(void); nathan@0: #endif nathan@0: virtual const char *MainMenuEntry(void); nathan@0: virtual cOsdMenu *MainMenuAction(void); nathan@0: virtual cMenuSetupPage *SetupMenu(void); nathan@0: virtual bool SetupParse(const char *Name, const char *Value); nathan@0: #if APIVERSNUM >= 10330 nathan@0: virtual bool Service(const char *Id, void *Data); nathan@0: #if APIVERSNUM >= 10331 nathan@0: virtual const char **SVDRPHelpPages(void); nathan@0: virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); nathan@0: #endif nathan@0: #endif nathan@0: }; nathan@0: nathan@0: cPluginMPlayer::cPluginMPlayer(void) nathan@0: { nathan@0: // Initialize any member variables here. nathan@0: // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL nathan@0: // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! nathan@0: status=0; nathan@0: } nathan@0: nathan@0: cPluginMPlayer::~cPluginMPlayer() nathan@0: { nathan@0: delete status; nathan@0: } nathan@0: nathan@0: const char *cPluginMPlayer::CommandLineHelp(void) nathan@0: { nathan@0: static char *help_str=0; nathan@0: nathan@0: free(help_str); // for easier orientation, this is column 80| nathan@0: asprintf(&help_str," -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" nathan@0: " (default: %s)\n" nathan@0: " -M CMD, --mplayer=CMD use CMD when calling MPlayer\n" nathan@0: " (default: %s)\n" nathan@0: " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" nathan@0: " (default: %s)\n" nathan@0: " -R DIR, --resume=DIR store global resume file in DIR\n" nathan@0: " (default: %s)\n", nathan@0: mountscript, nathan@0: MPlayerCmd, nathan@0: sourcesSub ? sourcesSub:"none", nathan@0: globalResumeDir ? globalResumeDir:"video dir" nathan@0: ); nathan@0: return help_str; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::ProcessArgs(int argc, char *argv[]) nathan@0: { nathan@0: static struct option long_options[] = { nathan@0: { "mount", required_argument, NULL, 'm' }, nathan@0: { "mplayer", required_argument, NULL, 'M' }, nathan@0: { "sources", required_argument, NULL, 'S' }, nathan@0: { "resume", required_argument, NULL, 'R' }, nathan@0: { NULL } nathan@0: }; nathan@0: nathan@0: int c, option_index = 0; nathan@0: while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) { nathan@0: switch (c) { nathan@0: case 'm': mountscript=optarg; break; nathan@0: case 'M': MPlayerCmd=optarg; break; nathan@0: case 'S': sourcesSub=optarg; break; nathan@0: case 'R': globalResumeDir=optarg; break; nathan@0: default: return false; nathan@0: } nathan@0: } nathan@0: return true; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10131 nathan@0: bool cPluginMPlayer::Initialize(void) nathan@0: #else nathan@0: bool cPluginMPlayer::Start(void) nathan@0: #endif nathan@0: { nathan@0: if(!CheckVDRVersion(1,1,16,"mplayer")) return false; nathan@2: plugin_name="mplayer"; nathan@2: #if APIVERSNUM < 10507 nathan@2: i18n_name="mplayer"; nathan@2: #else nathan@2: i18n_name="vdr-mplayer"; nathan@2: #endif nathan@0: MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf")); nathan@0: if(MPlaySources.Count()<1) { nathan@0: esyslog("ERROR: you must have defined at least one source in mplayersources.conf"); nathan@0: fprintf(stderr,"No source(s) defined in mplayersources.conf\n"); nathan@0: return false; nathan@0: } nathan@2: #if APIVERSNUM < 10507 nathan@0: RegisterI18n(Phrases); nathan@2: #endif nathan@0: if(!(status=new cMPlayerStatus)) return false; nathan@0: return true; nathan@0: } nathan@0: nathan@0: const char *cPluginMPlayer::MainMenuEntry(void) nathan@0: { nathan@0: return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY); nathan@0: } nathan@0: nathan@0: cOsdMenu *cPluginMPlayer::MainMenuAction(void) nathan@0: { nathan@0: return new cMenuMPlayBrowse; nathan@0: } nathan@0: nathan@0: cMenuSetupPage *cPluginMPlayer::SetupMenu(void) nathan@0: { nathan@0: return new cMenuSetupMPlayer; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::SetupParse(const char *Name, const char *Value) nathan@0: { nathan@0: if( !strcasecmp(Name, "ControlMode")) MPlayerSetup.SlaveMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value); nathan@0: else if (!strcasecmp(Name, "ResumeMode")) MPlayerSetup.ResumeMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "OsdPos")) MPlayerSetup.OsdPos = atoi(Value); nathan@0: else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6])) nathan@0: strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0])); nathan@0: else return false; nathan@0: return true; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10330 nathan@0: nathan@0: bool cPluginMPlayer::ExternalPlay(const char *path, bool test) nathan@0: { nathan@0: char real[PATH_MAX+1]; nathan@0: if(realpath(path,real)) { nathan@0: cFileSource *src=MPlaySources.FindSource(real); nathan@0: if(src) { nathan@0: cFileObj *item=new cFileObj(src,0,0,otFile); nathan@0: if(item) { nathan@0: item->SplitAndSet(real); nathan@0: if(item->GuessType()) { nathan@0: if(item->Exists()) { nathan@0: if(!test) { nathan@0: cMPlayerControl::SetFile(item,true); nathan@0: cControl::Launch(new cMPlayerControl); nathan@0: cControl::Attach(); nathan@0: } nathan@0: delete item; nathan@0: return true; nathan@0: } nathan@0: else dsyslog("MPlayer service: cannot play '%s'",path); nathan@0: } nathan@0: else dsyslog("MPlayer service: GuessType() failed for '%s'",path); nathan@0: delete item; nathan@0: } nathan@0: } nathan@0: else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real); nathan@0: } nathan@0: else if(errno!=ENOENT && errno!=ENOTDIR) nathan@0: esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); nathan@0: return false; nathan@0: } nathan@0: nathan@0: bool cPluginMPlayer::Service(const char *Id, void *Data) nathan@0: { nathan@0: if(!strcasecmp(Id,"MPlayer-Play-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,false); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: else if(!strcasecmp(Id,"MPlayer-Test-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,true); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: return false; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10331 nathan@0: nathan@0: const char **cPluginMPlayer::SVDRPHelpPages(void) nathan@0: { nathan@0: static const char *HelpPages[] = { nathan@0: "PLAY \n" nathan@0: " Triggers playback of file 'filename'.", nathan@0: "TEST \n" nathan@0: " Tests is playback of file 'filename' is possible.", nathan@0: NULL nathan@0: }; nathan@0: return HelpPages; nathan@0: } nathan@0: nathan@0: cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) nathan@0: { nathan@0: if(!strcasecmp(Command,"PLAY")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,false)) return "Playback triggered"; nathan@0: else { ReplyCode=550; return "Playback failed"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: else if(!strcasecmp(Command,"TEST")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,true)) return "Playback possible"; nathan@0: else { ReplyCode=550; return "Playback not possible"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: return NULL; nathan@0: } nathan@0: nathan@0: #endif // 1.3.31 nathan@0: #endif // 1.3.30 nathan@0: nathan@0: VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!