nathan@0
|
1 |
/*
|
nathan@0
|
2 |
* MP3/MPlayer plugin to VDR (C++)
|
nathan@0
|
3 |
*
|
nathan@22
|
4 |
* (C) 2001-2009 Stefan Huelswitt <s.huelswitt@gmx.de>
|
nathan@0
|
5 |
*
|
nathan@0
|
6 |
* This code is free software; you can redistribute it and/or
|
nathan@0
|
7 |
* modify it under the terms of the GNU General Public License
|
nathan@0
|
8 |
* as published by the Free Software Foundation; either version 2
|
nathan@0
|
9 |
* of the License, or (at your option) any later version.
|
nathan@0
|
10 |
*
|
nathan@0
|
11 |
* This code is distributed in the hope that it will be useful,
|
nathan@0
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nathan@0
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nathan@0
|
14 |
* GNU General Public License for more details.
|
nathan@0
|
15 |
*
|
nathan@0
|
16 |
* You should have received a copy of the GNU General Public License
|
nathan@0
|
17 |
* along with this program; if not, write to the Free Software
|
nathan@0
|
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
nathan@0
|
19 |
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
nathan@0
|
20 |
*/
|
nathan@0
|
21 |
|
nathan@0
|
22 |
#include <getopt.h>
|
nathan@0
|
23 |
#include <malloc.h>
|
nathan@0
|
24 |
#include <stdlib.h>
|
nathan@0
|
25 |
#include <ctype.h>
|
nathan@0
|
26 |
|
nathan@0
|
27 |
#include "common.h"
|
nathan@0
|
28 |
|
nathan@0
|
29 |
#include <vdr/plugin.h>
|
nathan@0
|
30 |
#include <vdr/player.h>
|
nathan@0
|
31 |
#include <vdr/status.h>
|
nathan@0
|
32 |
#include <vdr/font.h>
|
nathan@0
|
33 |
#include <vdr/osdbase.h>
|
nathan@0
|
34 |
#include <vdr/menuitems.h>
|
nathan@0
|
35 |
#include <vdr/skins.h>
|
nathan@0
|
36 |
#include <vdr/remote.h>
|
nathan@0
|
37 |
#include <vdr/menu.h>
|
nathan@0
|
38 |
|
nathan@0
|
39 |
#include "setup.h"
|
nathan@0
|
40 |
#include "setup-mplayer.h"
|
nathan@0
|
41 |
#include "menu.h"
|
nathan@0
|
42 |
#include "player-mplayer.h"
|
nathan@0
|
43 |
#include "data.h"
|
nathan@0
|
44 |
#include "data-src.h"
|
nathan@0
|
45 |
#include "i18n.h"
|
nathan@0
|
46 |
#include "version.h"
|
nathan@0
|
47 |
#include "service.h"
|
nathan@0
|
48 |
|
nathan@0
|
49 |
const char *sourcesSub=0;
|
nathan@0
|
50 |
cFileSources MPlaySources;
|
nathan@0
|
51 |
|
nathan@2
|
52 |
static const char *plugin_name=0;
|
nathan@12
|
53 |
const char *i18n_name=0;
|
nathan@2
|
54 |
|
nathan@0
|
55 |
// --- cMenuSetupMPlayer --------------------------------------------------------
|
nathan@0
|
56 |
|
nathan@0
|
57 |
class cMenuSetupMPlayer : public cMenuSetupPage {
|
nathan@0
|
58 |
private:
|
nathan@0
|
59 |
cMPlayerSetup data;
|
nathan@0
|
60 |
const char *res[3];
|
nathan@0
|
61 |
protected:
|
nathan@0
|
62 |
virtual void Store(void);
|
nathan@0
|
63 |
public:
|
nathan@0
|
64 |
cMenuSetupMPlayer(void);
|
nathan@0
|
65 |
};
|
nathan@0
|
66 |
|
nathan@0
|
67 |
cMenuSetupMPlayer::cMenuSetupMPlayer(void)
|
nathan@0
|
68 |
{
|
nathan@0
|
69 |
data=MPlayerSetup;
|
nathan@0
|
70 |
SetSection(tr("MPlayer"));
|
nathan@0
|
71 |
Add(new cMenuEditBoolItem(tr("Setup.MPlayer$Control mode"), &data.SlaveMode, tr("Traditional"), tr("Slave")));
|
nathan@0
|
72 |
res[0]=tr("disabled");
|
nathan@0
|
73 |
res[1]=tr("global only");
|
nathan@0
|
74 |
res[2]=tr("local first");
|
nathan@0
|
75 |
Add(new cMenuEditStraItem(tr("Setup.MPlayer$Resume mode"), &data.ResumeMode, 3, res));
|
nathan@0
|
76 |
Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu));
|
nathan@0
|
77 |
for(int i=0; i<10; i++) {
|
nathan@0
|
78 |
char name[32];
|
nathan@0
|
79 |
snprintf(name,sizeof(name),"%s %d",tr("Setup.MPlayer$Slave command key"),i);
|
nathan@0
|
80 |
static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?{}[]\\+*~#',;.:-_<>|@´`^°" };
|
nathan@0
|
81 |
Add(new cMenuEditStrItem(name, data.KeyCmd[i],MAX_KEYCMD,allowed));
|
nathan@0
|
82 |
}
|
nathan@0
|
83 |
}
|
nathan@0
|
84 |
|
nathan@0
|
85 |
void cMenuSetupMPlayer::Store(void)
|
nathan@0
|
86 |
{
|
nathan@0
|
87 |
MPlayerSetup=data;
|
nathan@0
|
88 |
SetupStore("ControlMode", MPlayerSetup.SlaveMode);
|
nathan@0
|
89 |
SetupStore("HideMainMenu",MPlayerSetup.HideMainMenu);
|
nathan@0
|
90 |
SetupStore("ResumeMode", MPlayerSetup.ResumeMode);
|
nathan@0
|
91 |
for(int i=0; i<10; i++) {
|
nathan@0
|
92 |
char name[16];
|
nathan@0
|
93 |
snprintf(name,sizeof(name),"KeyCmd%d",i);
|
nathan@0
|
94 |
SetupStore(name,MPlayerSetup.KeyCmd[i]);
|
nathan@0
|
95 |
}
|
nathan@0
|
96 |
}
|
nathan@0
|
97 |
|
nathan@0
|
98 |
// --- cMPlayerControl ---------------------------------------------------------
|
nathan@0
|
99 |
|
nathan@0
|
100 |
class cMPlayerControl : public cControl {
|
nathan@0
|
101 |
private:
|
nathan@0
|
102 |
static cFileObj *file;
|
nathan@0
|
103 |
static bool rewind;
|
nathan@0
|
104 |
cMPlayerPlayer *player;
|
nathan@0
|
105 |
cSkinDisplayReplay *display;
|
nathan@24
|
106 |
bool visible, modeOnly;
|
nathan@0
|
107 |
time_t timeoutShow;
|
nathan@0
|
108 |
int lastCurrent, lastTotal;
|
nathan@0
|
109 |
char *lastReplayMsg;
|
nathan@0
|
110 |
//
|
nathan@0
|
111 |
bool jumpactive, jumphide, jumpmode;
|
nathan@0
|
112 |
int jumpval;
|
nathan@0
|
113 |
//
|
nathan@0
|
114 |
void Stop(void);
|
nathan@0
|
115 |
void ShowTimed(int Seconds=0);
|
nathan@0
|
116 |
void ShowProgress(void);
|
nathan@0
|
117 |
void ShowMode(void);
|
nathan@0
|
118 |
void ShowTitle(void);
|
nathan@0
|
119 |
void Jump(void);
|
nathan@0
|
120 |
void JumpProcess(eKeys Key);
|
nathan@0
|
121 |
void JumpDisplay(void);
|
nathan@0
|
122 |
public:
|
nathan@0
|
123 |
cMPlayerControl(void);
|
nathan@0
|
124 |
virtual ~cMPlayerControl();
|
nathan@0
|
125 |
virtual eOSState ProcessKey(eKeys Key);
|
nathan@0
|
126 |
virtual void Show(void) { ShowTimed(); }
|
nathan@0
|
127 |
virtual void Hide(void);
|
nathan@0
|
128 |
static void SetFile(const cFileObj *File, bool Rewind);
|
nathan@0
|
129 |
};
|
nathan@0
|
130 |
|
nathan@0
|
131 |
cFileObj *cMPlayerControl::file=0;
|
nathan@0
|
132 |
bool cMPlayerControl::rewind=false;
|
nathan@0
|
133 |
|
nathan@0
|
134 |
cMPlayerControl::cMPlayerControl(void)
|
nathan@0
|
135 |
:cControl(player=new cMPlayerPlayer(file,rewind))
|
nathan@0
|
136 |
{
|
nathan@24
|
137 |
visible=modeOnly=jumpactive=false;
|
nathan@0
|
138 |
lastReplayMsg=0;
|
nathan@0
|
139 |
display=0;
|
nathan@0
|
140 |
ShowTitle();
|
nathan@0
|
141 |
}
|
nathan@0
|
142 |
|
nathan@0
|
143 |
cMPlayerControl::~cMPlayerControl()
|
nathan@0
|
144 |
{
|
nathan@0
|
145 |
Stop();
|
nathan@0
|
146 |
cStatus::MsgReplaying(this,0,0,false);
|
nathan@0
|
147 |
free(lastReplayMsg);
|
nathan@0
|
148 |
}
|
nathan@0
|
149 |
|
nathan@0
|
150 |
void cMPlayerControl::SetFile(const cFileObj *File, bool Rewind)
|
nathan@0
|
151 |
{
|
nathan@0
|
152 |
delete file;
|
nathan@0
|
153 |
file=File ? new cFileObj(File) : 0;
|
nathan@0
|
154 |
rewind=Rewind;
|
nathan@0
|
155 |
}
|
nathan@0
|
156 |
|
nathan@0
|
157 |
void cMPlayerControl::Stop(void)
|
nathan@0
|
158 |
{
|
nathan@0
|
159 |
delete player; player=0;
|
nathan@0
|
160 |
}
|
nathan@0
|
161 |
|
nathan@0
|
162 |
void cMPlayerControl::ShowTimed(int Seconds)
|
nathan@0
|
163 |
{
|
nathan@0
|
164 |
if(modeOnly) Hide();
|
nathan@0
|
165 |
if(!visible) {
|
nathan@0
|
166 |
ShowProgress();
|
nathan@0
|
167 |
timeoutShow = Seconds>0 ? time(0)+Seconds : 0;
|
nathan@0
|
168 |
}
|
nathan@0
|
169 |
}
|
nathan@0
|
170 |
|
nathan@0
|
171 |
void cMPlayerControl::Hide(void)
|
nathan@0
|
172 |
{
|
nathan@0
|
173 |
if(visible) {
|
nathan@0
|
174 |
delete display; display=0;
|
nathan@0
|
175 |
visible=modeOnly=false;
|
nathan@0
|
176 |
#if APIVERSNUM >= 10500
|
nathan@0
|
177 |
SetNeedsFastResponse(false);
|
nathan@0
|
178 |
#else
|
nathan@0
|
179 |
needsFastResponse=false;
|
nathan@0
|
180 |
#endif
|
nathan@0
|
181 |
}
|
nathan@0
|
182 |
}
|
nathan@0
|
183 |
|
nathan@0
|
184 |
void cMPlayerControl::ShowTitle(void)
|
nathan@0
|
185 |
{
|
nathan@0
|
186 |
const char *path=0;
|
nathan@0
|
187 |
bool release=true;
|
nathan@0
|
188 |
if(player) path=player->GetCurrentName();
|
nathan@0
|
189 |
if(!path) {
|
nathan@0
|
190 |
path=file->FullPath();
|
nathan@0
|
191 |
release=false;
|
nathan@0
|
192 |
}
|
nathan@0
|
193 |
if(path) {
|
nathan@0
|
194 |
const char *name=rindex(path,'/');
|
nathan@0
|
195 |
if(name) name++; else name=path;
|
nathan@0
|
196 |
if(!lastReplayMsg || strcmp(lastReplayMsg,path)) {
|
nathan@0
|
197 |
cStatus::MsgReplaying(this,name,path,true);
|
nathan@0
|
198 |
free(lastReplayMsg);
|
nathan@0
|
199 |
lastReplayMsg=strdup(path);
|
nathan@0
|
200 |
}
|
nathan@0
|
201 |
if(visible) {
|
nathan@0
|
202 |
if(display) display->SetTitle(name);
|
nathan@0
|
203 |
}
|
nathan@0
|
204 |
}
|
nathan@0
|
205 |
if(release) free((void *)path);
|
nathan@0
|
206 |
}
|
nathan@0
|
207 |
|
nathan@0
|
208 |
void cMPlayerControl::ShowProgress(void)
|
nathan@0
|
209 |
{
|
nathan@0
|
210 |
int Current, Total;
|
nathan@0
|
211 |
|
nathan@0
|
212 |
if(GetIndex(Current,Total) && Total>0) {
|
nathan@0
|
213 |
bool flush=false;
|
nathan@0
|
214 |
if(!visible) {
|
nathan@0
|
215 |
display=Skins.Current()->DisplayReplay(false);
|
nathan@0
|
216 |
visible=true; modeOnly=false;
|
nathan@0
|
217 |
#if APIVERSNUM >= 10500
|
nathan@0
|
218 |
SetNeedsFastResponse(true);
|
nathan@0
|
219 |
#else
|
nathan@0
|
220 |
needsFastResponse=true;
|
nathan@0
|
221 |
#endif
|
nathan@0
|
222 |
lastCurrent=lastTotal=-1;
|
nathan@0
|
223 |
flush=true;
|
nathan@0
|
224 |
}
|
nathan@0
|
225 |
|
nathan@0
|
226 |
if(abs(Current-lastCurrent)>12) {
|
nathan@0
|
227 |
if(Total>0) display->SetProgress(Current, Total);
|
nathan@0
|
228 |
display->SetCurrent(IndexToHMSF(Current));
|
nathan@0
|
229 |
display->SetTotal(IndexToHMSF(Total));
|
nathan@0
|
230 |
bool Play, Forward;
|
nathan@0
|
231 |
int Speed;
|
nathan@0
|
232 |
if(GetReplayMode(Play,Forward,Speed))
|
nathan@0
|
233 |
display->SetMode(Play, Forward, Speed);
|
nathan@0
|
234 |
ShowTitle();
|
nathan@0
|
235 |
flush=true;
|
nathan@0
|
236 |
lastCurrent=Current; lastTotal=Total;
|
nathan@0
|
237 |
}
|
nathan@0
|
238 |
if(flush)
|
nathan@0
|
239 |
Skins.Flush();
|
nathan@0
|
240 |
ShowMode();
|
nathan@0
|
241 |
}
|
nathan@0
|
242 |
}
|
nathan@0
|
243 |
|
nathan@0
|
244 |
void cMPlayerControl::ShowMode(void)
|
nathan@0
|
245 |
{
|
nathan@0
|
246 |
if(Setup.ShowReplayMode && !jumpactive) {
|
nathan@0
|
247 |
bool Play, Forward;
|
nathan@0
|
248 |
int Speed;
|
nathan@0
|
249 |
if(GetReplayMode(Play, Forward, Speed)) {
|
nathan@0
|
250 |
bool NormalPlay = (Play && Speed == -1);
|
nathan@0
|
251 |
|
nathan@0
|
252 |
if(!visible) {
|
nathan@0
|
253 |
if(NormalPlay) return;
|
nathan@0
|
254 |
display = Skins.Current()->DisplayReplay(true);
|
nathan@0
|
255 |
visible=modeOnly=true;
|
nathan@0
|
256 |
}
|
nathan@0
|
257 |
|
nathan@0
|
258 |
if(modeOnly && !timeoutShow && NormalPlay) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
|
nathan@0
|
259 |
|
nathan@0
|
260 |
display->SetMode(Play, Forward, Speed);
|
nathan@0
|
261 |
}
|
nathan@0
|
262 |
}
|
nathan@0
|
263 |
}
|
nathan@0
|
264 |
|
nathan@0
|
265 |
void cMPlayerControl::JumpDisplay(void)
|
nathan@0
|
266 |
{
|
nathan@0
|
267 |
char buf[64];
|
nathan@2
|
268 |
const char *j=trVDR("Jump: "), u=jumpmode?'%':'m';
|
nathan@0
|
269 |
if(!jumpval) sprintf(buf,"%s- %c", j,u);
|
nathan@0
|
270 |
else sprintf(buf,"%s%d- %c",j,jumpval,u);
|
nathan@0
|
271 |
display->SetJump(buf);
|
nathan@0
|
272 |
}
|
nathan@0
|
273 |
|
nathan@0
|
274 |
void cMPlayerControl::JumpProcess(eKeys Key)
|
nathan@0
|
275 |
{
|
nathan@0
|
276 |
const int n=Key-k0;
|
nathan@0
|
277 |
switch (Key) {
|
nathan@0
|
278 |
case k0 ... k9:
|
nathan@0
|
279 |
{
|
nathan@0
|
280 |
const int max=jumpmode?100:lastTotal;
|
nathan@0
|
281 |
if(jumpval*10+n <= max) jumpval=jumpval*10+n;
|
nathan@0
|
282 |
JumpDisplay();
|
nathan@0
|
283 |
}
|
nathan@0
|
284 |
break;
|
nathan@0
|
285 |
case kBlue:
|
nathan@0
|
286 |
jumpmode=!jumpmode; jumpval=0;
|
nathan@22
|
287 |
JumpDisplay();
|
nathan@0
|
288 |
break;
|
nathan@0
|
289 |
case kPlay:
|
nathan@0
|
290 |
case kUp:
|
nathan@0
|
291 |
player->Goto(jumpval*(jumpmode?1:60),jumpmode,false);
|
nathan@0
|
292 |
jumpactive=false;
|
nathan@0
|
293 |
break;
|
nathan@0
|
294 |
case kFastRew:
|
nathan@0
|
295 |
case kFastFwd:
|
nathan@0
|
296 |
case kLeft:
|
nathan@0
|
297 |
case kRight:
|
nathan@0
|
298 |
if(!jumpmode) {
|
nathan@0
|
299 |
player->SkipSeconds(jumpval*60 * ((Key==kLeft || Key==kFastRew) ? -1:1));
|
nathan@0
|
300 |
jumpactive=false;
|
nathan@0
|
301 |
}
|
nathan@0
|
302 |
break;
|
nathan@0
|
303 |
default:
|
nathan@0
|
304 |
jumpactive=false;
|
nathan@0
|
305 |
break;
|
nathan@0
|
306 |
}
|
nathan@0
|
307 |
|
nathan@0
|
308 |
if(!jumpactive) {
|
nathan@0
|
309 |
if(jumphide) Hide();
|
nathan@0
|
310 |
else
|
nathan@0
|
311 |
display->SetJump(0);
|
nathan@0
|
312 |
}
|
nathan@0
|
313 |
}
|
nathan@0
|
314 |
|
nathan@0
|
315 |
void cMPlayerControl::Jump(void)
|
nathan@0
|
316 |
{
|
nathan@0
|
317 |
jumpval=0; jumphide=jumpmode=false;
|
nathan@0
|
318 |
if(!visible) {
|
nathan@0
|
319 |
ShowTimed(); if(!visible) return;
|
nathan@0
|
320 |
jumphide=true;
|
nathan@0
|
321 |
}
|
nathan@0
|
322 |
JumpDisplay();
|
nathan@0
|
323 |
jumpactive=true;
|
nathan@0
|
324 |
}
|
nathan@0
|
325 |
|
nathan@0
|
326 |
eOSState cMPlayerControl::ProcessKey(eKeys Key)
|
nathan@0
|
327 |
{
|
nathan@0
|
328 |
if(!player->Active()) { Hide(); Stop(); return osEnd; }
|
nathan@0
|
329 |
|
nathan@0
|
330 |
if(!player->SlaveMode()) {
|
nathan@0
|
331 |
if(Key==kBlue) { Hide(); Stop(); return osEnd; }
|
nathan@0
|
332 |
}
|
nathan@0
|
333 |
else {
|
nathan@0
|
334 |
if(visible) {
|
nathan@0
|
335 |
if(timeoutShow && time(0)>timeoutShow) {
|
nathan@0
|
336 |
Hide(); ShowMode();
|
nathan@0
|
337 |
timeoutShow = 0;
|
nathan@0
|
338 |
}
|
nathan@0
|
339 |
else {
|
nathan@0
|
340 |
if(modeOnly) ShowMode();
|
nathan@0
|
341 |
else ShowProgress();
|
nathan@0
|
342 |
}
|
nathan@0
|
343 |
}
|
nathan@0
|
344 |
else ShowTitle();
|
nathan@0
|
345 |
|
nathan@0
|
346 |
if(jumpactive && Key != kNone) {
|
nathan@0
|
347 |
JumpProcess(Key);
|
nathan@0
|
348 |
return osContinue;
|
nathan@0
|
349 |
}
|
nathan@0
|
350 |
|
nathan@0
|
351 |
bool DoShowMode = true;
|
nathan@0
|
352 |
switch (Key) {
|
nathan@0
|
353 |
case kPlay:
|
nathan@0
|
354 |
case kUp: player->Play(); break;
|
nathan@0
|
355 |
|
nathan@0
|
356 |
case kPause:
|
nathan@0
|
357 |
case kDown: player->Pause(); break;
|
nathan@0
|
358 |
|
nathan@0
|
359 |
case kFastRew|k_Repeat:
|
nathan@0
|
360 |
case kFastRew:
|
nathan@0
|
361 |
case kLeft|k_Repeat:
|
nathan@0
|
362 |
case kLeft: player->SkipSeconds(-10); break;
|
nathan@0
|
363 |
|
nathan@0
|
364 |
case kFastFwd|k_Repeat:
|
nathan@0
|
365 |
case kFastFwd:
|
nathan@0
|
366 |
case kRight|k_Repeat:
|
nathan@0
|
367 |
case kRight: player->SkipSeconds(10); break;
|
nathan@0
|
368 |
|
nathan@0
|
369 |
case kRed: Jump(); break;
|
nathan@0
|
370 |
|
nathan@0
|
371 |
case kGreen|k_Repeat: // temporary use
|
nathan@0
|
372 |
case kGreen: player->SkipSeconds(-60); break;
|
nathan@0
|
373 |
case kYellow|k_Repeat:
|
nathan@0
|
374 |
case kYellow: player->SkipSeconds(60); break;
|
nathan@0
|
375 |
// case kGreen|k_Repeat: // reserved for future use
|
nathan@0
|
376 |
// case kGreen: player->SkipPrev(); break;
|
nathan@0
|
377 |
// case kYellow|k_Repeat:
|
nathan@0
|
378 |
// case kYellow: player->SkipNext(); break;
|
nathan@0
|
379 |
|
nathan@0
|
380 |
case kBack:
|
nathan@0
|
381 |
Hide();
|
nathan@2
|
382 |
cRemote::CallPlugin(plugin_name);
|
nathan@0
|
383 |
return osBack;
|
nathan@0
|
384 |
case kStop:
|
nathan@0
|
385 |
case kBlue: Hide(); Stop(); return osEnd;
|
nathan@0
|
386 |
|
nathan@0
|
387 |
default:
|
nathan@0
|
388 |
DoShowMode = false;
|
nathan@0
|
389 |
switch(Key) {
|
nathan@0
|
390 |
case kOk: if(visible && !modeOnly) { Hide(); DoShowMode=true; }
|
nathan@0
|
391 |
else ShowTimed();
|
nathan@0
|
392 |
break;
|
nathan@20
|
393 |
case kAudio:
|
nathan@20
|
394 |
player->KeyCmd("switch_audio");
|
nathan@20
|
395 |
break;
|
nathan@27
|
396 |
case kNext:
|
nathan@27
|
397 |
player->KeyCmd("seek_chapter +1");
|
nathan@27
|
398 |
break;
|
nathan@27
|
399 |
case kPrev:
|
nathan@27
|
400 |
player->KeyCmd("seek_chapter -1");
|
nathan@27
|
401 |
break;
|
nathan@0
|
402 |
case k0:
|
nathan@0
|
403 |
case k1:
|
nathan@0
|
404 |
case k2:
|
nathan@0
|
405 |
case k3:
|
nathan@0
|
406 |
case k4:
|
nathan@0
|
407 |
case k5:
|
nathan@0
|
408 |
case k6:
|
nathan@0
|
409 |
case k7:
|
nathan@0
|
410 |
case k8:
|
nathan@0
|
411 |
case k9: {
|
nathan@0
|
412 |
const char *cmd=MPlayerSetup.KeyCmd[Key-k0];
|
nathan@0
|
413 |
if(cmd[0]) player->KeyCmd(cmd);
|
nathan@0
|
414 |
}
|
nathan@0
|
415 |
break;
|
nathan@0
|
416 |
default: break;
|
nathan@0
|
417 |
}
|
nathan@0
|
418 |
break;
|
nathan@0
|
419 |
}
|
nathan@0
|
420 |
|
nathan@0
|
421 |
if(DoShowMode) ShowMode();
|
nathan@0
|
422 |
}
|
nathan@0
|
423 |
return osContinue;
|
nathan@0
|
424 |
}
|
nathan@0
|
425 |
|
nathan@0
|
426 |
// --- cMenuMPlayAid -----------------------------------------------------------
|
nathan@0
|
427 |
|
nathan@0
|
428 |
class cMenuMPlayAid : public cOsdMenu {
|
nathan@0
|
429 |
public:
|
nathan@0
|
430 |
cMenuMPlayAid(void);
|
nathan@0
|
431 |
virtual eOSState ProcessKey(eKeys Key);
|
nathan@0
|
432 |
};
|
nathan@0
|
433 |
|
nathan@0
|
434 |
cMenuMPlayAid::cMenuMPlayAid(void)
|
nathan@0
|
435 |
:cOsdMenu(tr("MPlayer Audio ID"),20)
|
nathan@0
|
436 |
{
|
nathan@0
|
437 |
Add(new cMenuEditIntItem(tr("Audiostream ID"),&MPlayerAid,-1,255));
|
nathan@0
|
438 |
Display();
|
nathan@0
|
439 |
}
|
nathan@0
|
440 |
|
nathan@0
|
441 |
eOSState cMenuMPlayAid::ProcessKey(eKeys Key)
|
nathan@0
|
442 |
{
|
nathan@0
|
443 |
eOSState state=cOsdMenu::ProcessKey(Key);
|
nathan@0
|
444 |
if(state==osUnknown) {
|
nathan@0
|
445 |
switch(Key) {
|
nathan@0
|
446 |
case kOk: state=osBack; break;
|
nathan@0
|
447 |
default: break;
|
nathan@0
|
448 |
}
|
nathan@0
|
449 |
}
|
nathan@0
|
450 |
return state;
|
nathan@0
|
451 |
}
|
nathan@0
|
452 |
|
nathan@0
|
453 |
// --- cMenuMPlayBrowse ---------------------------------------------------------
|
nathan@0
|
454 |
|
nathan@0
|
455 |
class cMenuMPlayBrowse : public cMenuBrowse {
|
nathan@0
|
456 |
private:
|
nathan@0
|
457 |
bool sourcing, aidedit;
|
nathan@0
|
458 |
eOSState Source(bool second);
|
nathan@0
|
459 |
eOSState Summary(void);
|
nathan@0
|
460 |
protected:
|
nathan@0
|
461 |
virtual void SetButtons(void);
|
nathan@0
|
462 |
public:
|
nathan@0
|
463 |
cMenuMPlayBrowse(void);
|
nathan@0
|
464 |
virtual eOSState ProcessKey(eKeys Key);
|
nathan@0
|
465 |
};
|
nathan@0
|
466 |
|
nathan@0
|
467 |
static const char *excl_sum[] = { ".*","*.summary","*.txt","*.nfo",0 };
|
nathan@0
|
468 |
|
nathan@0
|
469 |
cMenuMPlayBrowse::cMenuMPlayBrowse(void)
|
nathan@0
|
470 |
:cMenuBrowse(MPlaySources.GetSource(),false,false,tr("MPlayer browser"),excl_sum)
|
nathan@0
|
471 |
{
|
nathan@0
|
472 |
sourcing=aidedit=false;
|
nathan@0
|
473 |
SetButtons();
|
nathan@0
|
474 |
}
|
nathan@0
|
475 |
|
nathan@0
|
476 |
void cMenuMPlayBrowse::SetButtons(void)
|
nathan@0
|
477 |
{
|
nathan@0
|
478 |
static char blue[12];
|
nathan@0
|
479 |
snprintf(blue,sizeof(blue),MPlayerAid>=0 ? "AID:%d" : "AID:def",MPlayerAid);
|
nathan@23
|
480 |
SetHelp(trVDR("Button$Play"), MPlayerSetup.ResumeMode ? trVDR("Button$Rewind"):0, tr("Source"), blue);
|
nathan@0
|
481 |
Display();
|
nathan@0
|
482 |
}
|
nathan@0
|
483 |
|
nathan@0
|
484 |
eOSState cMenuMPlayBrowse::Source(bool second)
|
nathan@0
|
485 |
{
|
nathan@0
|
486 |
if(HasSubMenu()) return osContinue;
|
nathan@0
|
487 |
|
nathan@0
|
488 |
if(!second) {
|
nathan@0
|
489 |
sourcing=true;
|
nathan@0
|
490 |
return AddSubMenu(new cMenuSource(&MPlaySources,tr("MPlayer source")));
|
nathan@0
|
491 |
}
|
nathan@0
|
492 |
sourcing=false;
|
nathan@0
|
493 |
cFileSource *src=cMenuSource::GetSelected();
|
nathan@0
|
494 |
if(src) {
|
nathan@0
|
495 |
MPlaySources.SetSource(src);
|
nathan@0
|
496 |
SetSource(src);
|
nathan@0
|
497 |
NewDir(0);
|
nathan@0
|
498 |
}
|
nathan@0
|
499 |
return osContinue;
|
nathan@0
|
500 |
}
|
nathan@0
|
501 |
|
nathan@0
|
502 |
eOSState cMenuMPlayBrowse::Summary(void)
|
nathan@0
|
503 |
{
|
nathan@0
|
504 |
cFileObj *item=CurrentItem();
|
nathan@0
|
505 |
if(item && item->Type()==otFile) {
|
nathan@0
|
506 |
static const char *exts[] = { ".summary",".txt",".nfo",0 };
|
nathan@0
|
507 |
for(int i=0; exts[i]; i++) {
|
nathan@0
|
508 |
char buff[4096];
|
nathan@0
|
509 |
strn0cpy(buff,item->FullPath(),sizeof(buff)-20);
|
nathan@0
|
510 |
char *e=&buff[strlen(buff)];
|
nathan@0
|
511 |
strn0cpy(e,exts[i],20);
|
nathan@0
|
512 |
int fd=open(buff,O_RDONLY);
|
nathan@0
|
513 |
*e=0;
|
nathan@0
|
514 |
if(fd<0 && (e=rindex(buff,'.'))) {
|
nathan@0
|
515 |
strn0cpy(e,exts[i],20);
|
nathan@0
|
516 |
fd=open(buff,O_RDONLY);
|
nathan@0
|
517 |
}
|
nathan@0
|
518 |
if(fd>=0) {
|
nathan@0
|
519 |
int r=read(fd,buff,sizeof(buff)-1);
|
nathan@0
|
520 |
close(fd);
|
nathan@0
|
521 |
if(r>0) {
|
nathan@0
|
522 |
buff[r]=0;
|
nathan@0
|
523 |
return AddSubMenu(new cMenuText(tr("Summary"),buff));
|
nathan@0
|
524 |
}
|
nathan@0
|
525 |
}
|
nathan@0
|
526 |
}
|
nathan@0
|
527 |
}
|
nathan@0
|
528 |
return osContinue;
|
nathan@0
|
529 |
}
|
nathan@0
|
530 |
|
nathan@0
|
531 |
eOSState cMenuMPlayBrowse::ProcessKey(eKeys Key)
|
nathan@0
|
532 |
{
|
nathan@0
|
533 |
eOSState state=cOsdMenu::ProcessKey(Key);
|
nathan@0
|
534 |
if(state==osContinue && !HasSubMenu()) {
|
nathan@0
|
535 |
if(sourcing) return Source(true);
|
nathan@0
|
536 |
if(aidedit) { aidedit=false; SetButtons(); }
|
nathan@0
|
537 |
}
|
nathan@0
|
538 |
bool rew=false;
|
nathan@0
|
539 |
if(state==osUnknown) {
|
nathan@0
|
540 |
switch(Key) {
|
nathan@0
|
541 |
case kGreen:
|
nathan@0
|
542 |
{
|
nathan@0
|
543 |
cFileObj *item=CurrentItem();
|
nathan@0
|
544 |
if(item && item->Type()==otFile) {
|
nathan@0
|
545 |
lastselect=new cFileObj(item);
|
nathan@0
|
546 |
state=osBack;
|
nathan@0
|
547 |
rew=true;
|
nathan@0
|
548 |
}
|
nathan@0
|
549 |
else state=osContinue;
|
nathan@0
|
550 |
break;
|
nathan@0
|
551 |
}
|
nathan@0
|
552 |
case kYellow:
|
nathan@0
|
553 |
state=Source(false);
|
nathan@0
|
554 |
break;
|
nathan@0
|
555 |
case kBlue:
|
nathan@0
|
556 |
aidedit=true;
|
nathan@0
|
557 |
state=AddSubMenu(new cMenuMPlayAid);
|
nathan@0
|
558 |
break;
|
nathan@0
|
559 |
case k0:
|
nathan@0
|
560 |
state=Summary();
|
nathan@0
|
561 |
break;
|
nathan@0
|
562 |
default:
|
nathan@0
|
563 |
break;
|
nathan@0
|
564 |
}
|
nathan@0
|
565 |
}
|
nathan@0
|
566 |
if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
|
nathan@0
|
567 |
if(state==osBack && lastselect) {
|
nathan@0
|
568 |
cMPlayerControl::SetFile(lastselect,rew);
|
nathan@0
|
569 |
cControl::Launch(new cMPlayerControl);
|
nathan@0
|
570 |
return osEnd;
|
nathan@0
|
571 |
}
|
nathan@0
|
572 |
return state;
|
nathan@0
|
573 |
}
|
nathan@0
|
574 |
|
nathan@0
|
575 |
// --- cPluginMPlayer ----------------------------------------------------------
|
nathan@0
|
576 |
|
nathan@2
|
577 |
static const char *DESCRIPTION = trNOOP("Media replay via MPlayer");
|
nathan@0
|
578 |
static const char *MAINMENUENTRY = "MPlayer";
|
nathan@0
|
579 |
|
nathan@0
|
580 |
class cPluginMPlayer : public cPlugin {
|
nathan@0
|
581 |
private:
|
nathan@0
|
582 |
bool ExternalPlay(const char *path, bool test);
|
nathan@0
|
583 |
public:
|
nathan@0
|
584 |
cPluginMPlayer(void);
|
nathan@0
|
585 |
virtual ~cPluginMPlayer();
|
nathan@9
|
586 |
virtual const char *Version(void) { return PluginVersion; }
|
nathan@0
|
587 |
virtual const char *Description(void) { return tr(DESCRIPTION); }
|
nathan@0
|
588 |
virtual const char *CommandLineHelp(void);
|
nathan@0
|
589 |
virtual bool ProcessArgs(int argc, char *argv[]);
|
nathan@0
|
590 |
virtual bool Initialize(void);
|
nathan@0
|
591 |
virtual const char *MainMenuEntry(void);
|
nathan@0
|
592 |
virtual cOsdMenu *MainMenuAction(void);
|
nathan@0
|
593 |
virtual cMenuSetupPage *SetupMenu(void);
|
nathan@0
|
594 |
virtual bool SetupParse(const char *Name, const char *Value);
|
nathan@0
|
595 |
virtual bool Service(const char *Id, void *Data);
|
nathan@0
|
596 |
virtual const char **SVDRPHelpPages(void);
|
nathan@0
|
597 |
virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
|
nathan@0
|
598 |
};
|
nathan@0
|
599 |
|
nathan@0
|
600 |
cPluginMPlayer::cPluginMPlayer(void)
|
nathan@0
|
601 |
{
|
nathan@0
|
602 |
// Initialize any member variables here.
|
nathan@0
|
603 |
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
nathan@0
|
604 |
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
nathan@0
|
605 |
status=0;
|
nathan@0
|
606 |
}
|
nathan@0
|
607 |
|
nathan@0
|
608 |
cPluginMPlayer::~cPluginMPlayer()
|
nathan@0
|
609 |
{
|
nathan@0
|
610 |
delete status;
|
nathan@0
|
611 |
}
|
nathan@0
|
612 |
|
nathan@0
|
613 |
const char *cPluginMPlayer::CommandLineHelp(void)
|
nathan@0
|
614 |
{
|
nathan@0
|
615 |
static char *help_str=0;
|
nathan@0
|
616 |
|
nathan@0
|
617 |
free(help_str); // for easier orientation, this is column 80|
|
nathan@29
|
618 |
help_str=aprintf( " -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n"
|
nathan@0
|
619 |
" (default: %s)\n"
|
nathan@0
|
620 |
" -M CMD, --mplayer=CMD use CMD when calling MPlayer\n"
|
nathan@0
|
621 |
" (default: %s)\n"
|
nathan@0
|
622 |
" -S SUB, --sources=SUB search sources config in SUB subdirectory\n"
|
nathan@0
|
623 |
" (default: %s)\n"
|
nathan@0
|
624 |
" -R DIR, --resume=DIR store global resume file in DIR\n"
|
nathan@0
|
625 |
" (default: %s)\n",
|
nathan@0
|
626 |
mountscript,
|
nathan@0
|
627 |
MPlayerCmd,
|
nathan@0
|
628 |
sourcesSub ? sourcesSub:"none",
|
nathan@0
|
629 |
globalResumeDir ? globalResumeDir:"video dir"
|
nathan@0
|
630 |
);
|
nathan@0
|
631 |
return help_str;
|
nathan@0
|
632 |
}
|
nathan@0
|
633 |
|
nathan@0
|
634 |
bool cPluginMPlayer::ProcessArgs(int argc, char *argv[])
|
nathan@0
|
635 |
{
|
nathan@0
|
636 |
static struct option long_options[] = {
|
nathan@0
|
637 |
{ "mount", required_argument, NULL, 'm' },
|
nathan@0
|
638 |
{ "mplayer", required_argument, NULL, 'M' },
|
nathan@0
|
639 |
{ "sources", required_argument, NULL, 'S' },
|
nathan@0
|
640 |
{ "resume", required_argument, NULL, 'R' },
|
nathan@0
|
641 |
{ NULL }
|
nathan@0
|
642 |
};
|
nathan@0
|
643 |
|
nathan@0
|
644 |
int c, option_index = 0;
|
nathan@0
|
645 |
while((c=getopt_long(argc,argv,"m:M:S:R:",long_options,&option_index))!=-1) {
|
nathan@0
|
646 |
switch (c) {
|
nathan@0
|
647 |
case 'm': mountscript=optarg; break;
|
nathan@0
|
648 |
case 'M': MPlayerCmd=optarg; break;
|
nathan@0
|
649 |
case 'S': sourcesSub=optarg; break;
|
nathan@0
|
650 |
case 'R': globalResumeDir=optarg; break;
|
nathan@0
|
651 |
default: return false;
|
nathan@0
|
652 |
}
|
nathan@0
|
653 |
}
|
nathan@0
|
654 |
return true;
|
nathan@0
|
655 |
}
|
nathan@0
|
656 |
|
nathan@0
|
657 |
bool cPluginMPlayer::Initialize(void)
|
nathan@22
|
658 |
{
|
nathan@22
|
659 |
if(!CheckVDRVersion(1,4,5,"mplayer")) return false;
|
nathan@2
|
660 |
plugin_name="mplayer";
|
nathan@2
|
661 |
#if APIVERSNUM < 10507
|
nathan@2
|
662 |
i18n_name="mplayer";
|
nathan@2
|
663 |
#else
|
nathan@2
|
664 |
i18n_name="vdr-mplayer";
|
nathan@2
|
665 |
#endif
|
nathan@0
|
666 |
MPlaySources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mplayersources.conf"));
|
nathan@0
|
667 |
if(MPlaySources.Count()<1) {
|
nathan@0
|
668 |
esyslog("ERROR: you must have defined at least one source in mplayersources.conf");
|
nathan@0
|
669 |
fprintf(stderr,"No source(s) defined in mplayersources.conf\n");
|
nathan@0
|
670 |
return false;
|
nathan@0
|
671 |
}
|
nathan@2
|
672 |
#if APIVERSNUM < 10507
|
nathan@0
|
673 |
RegisterI18n(Phrases);
|
nathan@2
|
674 |
#endif
|
nathan@0
|
675 |
if(!(status=new cMPlayerStatus)) return false;
|
nathan@0
|
676 |
return true;
|
nathan@0
|
677 |
}
|
nathan@0
|
678 |
|
nathan@0
|
679 |
const char *cPluginMPlayer::MainMenuEntry(void)
|
nathan@0
|
680 |
{
|
nathan@0
|
681 |
return MPlayerSetup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
|
nathan@0
|
682 |
}
|
nathan@0
|
683 |
|
nathan@0
|
684 |
cOsdMenu *cPluginMPlayer::MainMenuAction(void)
|
nathan@0
|
685 |
{
|
nathan@0
|
686 |
return new cMenuMPlayBrowse;
|
nathan@0
|
687 |
}
|
nathan@0
|
688 |
|
nathan@0
|
689 |
cMenuSetupPage *cPluginMPlayer::SetupMenu(void)
|
nathan@0
|
690 |
{
|
nathan@0
|
691 |
return new cMenuSetupMPlayer;
|
nathan@0
|
692 |
}
|
nathan@0
|
693 |
|
nathan@0
|
694 |
bool cPluginMPlayer::SetupParse(const char *Name, const char *Value)
|
nathan@0
|
695 |
{
|
nathan@0
|
696 |
if( !strcasecmp(Name, "ControlMode")) MPlayerSetup.SlaveMode = atoi(Value);
|
nathan@0
|
697 |
else if (!strcasecmp(Name, "HideMainMenu")) MPlayerSetup.HideMainMenu = atoi(Value);
|
nathan@0
|
698 |
else if (!strcasecmp(Name, "ResumeMode")) MPlayerSetup.ResumeMode = atoi(Value);
|
nathan@0
|
699 |
else if (!strncasecmp(Name,"KeyCmd", 6) && strlen(Name)==7 && isdigit(Name[6]))
|
nathan@0
|
700 |
strn0cpy(MPlayerSetup.KeyCmd[Name[6]-'0'],Value,sizeof(MPlayerSetup.KeyCmd[0]));
|
nathan@0
|
701 |
else return false;
|
nathan@0
|
702 |
return true;
|
nathan@0
|
703 |
}
|
nathan@0
|
704 |
|
nathan@0
|
705 |
bool cPluginMPlayer::ExternalPlay(const char *path, bool test)
|
nathan@0
|
706 |
{
|
nathan@0
|
707 |
char real[PATH_MAX+1];
|
nathan@0
|
708 |
if(realpath(path,real)) {
|
nathan@0
|
709 |
cFileSource *src=MPlaySources.FindSource(real);
|
nathan@0
|
710 |
if(src) {
|
nathan@0
|
711 |
cFileObj *item=new cFileObj(src,0,0,otFile);
|
nathan@0
|
712 |
if(item) {
|
nathan@0
|
713 |
item->SplitAndSet(real);
|
nathan@0
|
714 |
if(item->GuessType()) {
|
nathan@0
|
715 |
if(item->Exists()) {
|
nathan@0
|
716 |
if(!test) {
|
nathan@0
|
717 |
cMPlayerControl::SetFile(item,true);
|
nathan@0
|
718 |
cControl::Launch(new cMPlayerControl);
|
nathan@0
|
719 |
cControl::Attach();
|
nathan@0
|
720 |
}
|
nathan@0
|
721 |
delete item;
|
nathan@0
|
722 |
return true;
|
nathan@0
|
723 |
}
|
nathan@0
|
724 |
else dsyslog("MPlayer service: cannot play '%s'",path);
|
nathan@0
|
725 |
}
|
nathan@0
|
726 |
else dsyslog("MPlayer service: GuessType() failed for '%s'",path);
|
nathan@0
|
727 |
delete item;
|
nathan@0
|
728 |
}
|
nathan@0
|
729 |
}
|
nathan@0
|
730 |
else dsyslog("MPlayer service: cannot find source for '%s', real '%s'",path,real);
|
nathan@0
|
731 |
}
|
nathan@0
|
732 |
else if(errno!=ENOENT && errno!=ENOTDIR)
|
nathan@0
|
733 |
esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
|
nathan@0
|
734 |
return false;
|
nathan@0
|
735 |
}
|
nathan@0
|
736 |
|
nathan@0
|
737 |
bool cPluginMPlayer::Service(const char *Id, void *Data)
|
nathan@0
|
738 |
{
|
nathan@0
|
739 |
if(!strcasecmp(Id,"MPlayer-Play-v1")) {
|
nathan@0
|
740 |
if(Data) {
|
nathan@0
|
741 |
struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
|
nathan@0
|
742 |
msd->result=ExternalPlay(msd->data.filename,false);
|
nathan@0
|
743 |
}
|
nathan@0
|
744 |
return true;
|
nathan@0
|
745 |
}
|
nathan@0
|
746 |
else if(!strcasecmp(Id,"MPlayer-Test-v1")) {
|
nathan@0
|
747 |
if(Data) {
|
nathan@0
|
748 |
struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
|
nathan@0
|
749 |
msd->result=ExternalPlay(msd->data.filename,true);
|
nathan@0
|
750 |
}
|
nathan@0
|
751 |
return true;
|
nathan@0
|
752 |
}
|
nathan@0
|
753 |
return false;
|
nathan@0
|
754 |
}
|
nathan@0
|
755 |
|
nathan@0
|
756 |
const char **cPluginMPlayer::SVDRPHelpPages(void)
|
nathan@0
|
757 |
{
|
nathan@0
|
758 |
static const char *HelpPages[] = {
|
nathan@0
|
759 |
"PLAY <filename>\n"
|
nathan@0
|
760 |
" Triggers playback of file 'filename'.",
|
nathan@0
|
761 |
"TEST <filename>\n"
|
nathan@0
|
762 |
" Tests is playback of file 'filename' is possible.",
|
nathan@0
|
763 |
NULL
|
nathan@0
|
764 |
};
|
nathan@0
|
765 |
return HelpPages;
|
nathan@0
|
766 |
}
|
nathan@0
|
767 |
|
nathan@0
|
768 |
cString cPluginMPlayer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
|
nathan@0
|
769 |
{
|
nathan@0
|
770 |
if(!strcasecmp(Command,"PLAY")) {
|
nathan@0
|
771 |
if(*Option) {
|
nathan@0
|
772 |
if(ExternalPlay(Option,false)) return "Playback triggered";
|
nathan@0
|
773 |
else { ReplyCode=550; return "Playback failed"; }
|
nathan@0
|
774 |
}
|
nathan@0
|
775 |
else { ReplyCode=501; return "Missing filename"; }
|
nathan@0
|
776 |
}
|
nathan@0
|
777 |
else if(!strcasecmp(Command,"TEST")) {
|
nathan@0
|
778 |
if(*Option) {
|
nathan@0
|
779 |
if(ExternalPlay(Option,true)) return "Playback possible";
|
nathan@0
|
780 |
else { ReplyCode=550; return "Playback not possible"; }
|
nathan@0
|
781 |
}
|
nathan@0
|
782 |
else { ReplyCode=501; return "Missing filename"; }
|
nathan@0
|
783 |
}
|
nathan@0
|
784 |
return NULL;
|
nathan@0
|
785 |
}
|
nathan@0
|
786 |
|
nathan@0
|
787 |
VDRPLUGINCREATOR(cPluginMPlayer); // Don't touch this!
|