]> git.vomp.tv Git - vompclient.git/blob - player.cc
Options view files added, new remote type supported
[vompclient.git] / player.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "player.h"
22
23 Player::Player(MessageQueue* messageQueue)
24 : vfeed(this), afeed(this)
25 {
26   initted = 0;
27   commandMessageQueue = messageQueue;
28
29   paused = 0;
30   playing = 0;
31   ffwd = 0;
32   fbwd = 0;
33   feedPosition = 0;
34   feedMode = MODE_NORMAL;
35
36   streamLength = 0;
37   // FIXME - this might need settings back to zero for new live play depending on what is done with it
38 }
39
40 Player::~Player()
41 {
42   if (initted) shutdown();
43 }
44
45 int Player::init()
46 {
47   if (initted) return 0;
48
49   video = Video::getInstance();
50   audio = Audio::getInstance();
51
52   if (demuxer.init()) // inverted
53   {
54     Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init");
55     shutdown();
56     return 0;
57   }
58
59   vfeed.init(video->getFD());
60   afeed.init(audio->getFD());
61
62   video->stop();
63   video->blank();
64   audio->stop();
65
66   startup = 0;
67   initted = 1;
68   return 1;
69 }
70
71 int Player::shutdown()
72 {
73   if (!initted) return 0;
74   initted = 0;
75
76   Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown...");
77
78   // copy of stop
79   if (playing)
80   {
81     playing = 0;
82     threadStop();
83     video->stop();
84     video->blank();
85     audio->stop();
86     vfeed.stop();
87     afeed.stop();
88     video->reset();
89     demuxer.reset();
90     feedPosition = 0;
91   }
92
93   return 1;
94 }
95
96 int Player::play()
97 {
98   if (!initted) return 0;
99
100   // If we are just paused, unpause!
101   if (paused)
102   {
103     togglePause();
104     return 1;
105   }
106
107   // If we are fast forwarding, set to normal
108   if (ffwd)
109   {
110     toggleFastForward();
111     return 1;
112   }
113
114   // If we are fast backwarding, set to normal
115   if (fbwd)
116   {
117     toggleFastBackward();
118     return 1;
119   }
120
121   // If we are already playing, bail // FIXME - resync?
122   if (playing)
123   {
124     Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC");
125
126 /*
127     vfeed.stop();
128     afeed.stop();
129     video->reset();
130     audio->reset();
131     demuxer.flush();
132     demuxer.seek();
133     vfeed.start();
134     afeed.start();
135
136
137     video->play();
138     audio->play();
139     video->sync();
140     audio->sync();
141     call();
142 */
143
144     // resync method 2..
145
146     video->pause();
147     usleep(500000);
148     video->play();
149     video->sync();
150
151
152     return 1;
153   }
154
155   // Standard play start
156
157   audio->reset();
158   video->reset();
159   demuxer.reset();
160   startup = 1;
161
162 // ------------------------ This one works, but doesn't allow any pre-buffering.
163   threadStart();
164   vfeed.start();
165   afeed.start();
166   audio->play();
167   video->play();
168   video->sync();
169   audio->sync();
170
171   video->pause();
172       usleep(500000); // SYNC
173   video->sync();
174   video->unPause();
175   video->sync();
176
177 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
178
179 /*
180
181   threadStart();
182   sleep(2);
183
184 //  struct timespec delay;
185 //  delay.tv_sec = 1;
186 //  delay.tv_nsec = 500000000;
187 //  nanosleep(&delay, NULL);
188
189   vfeed.start();
190   afeed.start();
191   video->play();
192   audio->play();
193   video->sync();
194   audio->sync();
195 */
196 // ------------------------------------------------------------------------------------------------
197
198   playing = 1;
199   return 1;
200 }
201
202 void Player::stop()
203 {
204   if (!initted) return;
205   if (!playing) return;
206
207   if (ffwd || fbwd)
208   {
209     ffwd = 0;
210     fbwd = 0;
211     afeed.enable();
212     video->unFastForward();
213     audio->systemMuteOff();
214     feedMode = MODE_NORMAL;
215   }
216
217   playing = 0;
218   paused = 0;
219
220   threadStop();
221   video->stop();
222   video->blank();
223   audio->stop();
224   audio->unPause();
225   vfeed.stop();
226   afeed.stop();
227   video->reset();
228   demuxer.reset();
229
230   feedPosition = 0;
231 }
232
233 void Player::togglePause()
234 {
235   if (!initted) return;
236   if (!playing) return;
237
238   if (ffwd) toggleFastForward();
239   if (fbwd) toggleFastBackward();
240
241   if (paused)
242   {
243     video->unPause();
244     audio->unPause();
245     paused = 0;
246   }
247   else
248   {
249     video->pause();
250     audio->pause();
251     paused = 1;
252   }
253 }
254
255 void Player::test()
256 {
257   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
258
259 /*
260
261 //  video->test();
262
263   static int flipflop = 0;
264
265   int a;
266   if (flipflop) a = video->setAspectRatio(Video::ASPECT16X9);
267   else a = video->setAspectRatio(Video::ASPECT4X3);
268
269   flipflop = !flipflop;
270
271   printf("A = %i\n", a);
272 */
273 }
274
275 void Player::test2()
276 {
277   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
278
279   video->test2();
280 }
281
282 void Player::setPosition(ULLONG position)
283 {
284   feedPosition = position;
285 }
286
287 void Player::setLength(ULLONG length)
288 {
289   streamLength = length;
290   Log::getInstance()->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength);
291 }
292
293 void Player::skipForward(int seconds)
294 {
295   // skip forward 1 minute
296   Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
297
298   if (paused) togglePause();
299
300   ULLONG moveBy = seconds * 500000;
301
302   threadStop();
303   vfeed.stop();
304   afeed.stop();
305   video->stop();
306   video->reset();
307   audio->reset();
308   audio->doMuting();  // ???
309   demuxer.flush();
310   feedPosition += moveBy;
311
312   printf("Audio test %i\n", audio->test());
313
314   vfeed.start();
315   afeed.start();
316   threadStart();
317   audio->play();
318   video->play();
319   video->sync();
320   audio->sync();
321
322   video->pause();
323       usleep(500000); // SYNC
324   video->sync();
325   video->unPause();
326   video->sync();
327
328 }
329
330 void Player::skipBackward(int seconds)
331 {
332   // skip forward 1 minute
333   Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
334
335   if (paused) togglePause();
336
337   ULLONG moveBy = seconds * 500000;
338
339   threadStop();
340   vfeed.stop();
341   afeed.stop();
342   video->stop();
343   audio->stop();
344   video->reset();
345   audio->reset();
346   audio->doMuting(); // ???
347   demuxer.flush();
348   if (feedPosition > moveBy) feedPosition -= moveBy;
349   vfeed.start();
350   afeed.start();
351   threadStart();
352   audio->play();
353   video->play();
354   video->sync();
355   audio->sync();
356
357   video->pause();
358       usleep(500000); // SYNC
359   video->sync();
360   video->unPause();
361   video->sync();
362
363 }
364
365 void Player::toggleFastForward()
366 {
367   if (!initted) return;
368   if (!playing) return;
369
370   if (paused) togglePause();
371   if (fbwd) toggleFastBackward();
372
373   if (ffwd)
374   {
375     ffwd = 0;
376 //    video->unFastForward();
377
378
379     threadStop();
380     vfeed.stop();
381     afeed.stop();
382     video->stop();
383     audio->stop();
384     video->reset();
385     audio->reset();
386     demuxer.flush();
387 //    demuxer.seek();
388     vfeed.start();
389     afeed.enable();
390     afeed.start();
391     threadStart();
392     video->play();
393     audio->play();
394     video->sync();
395     audio->sync();
396
397     audio->systemMuteOff();
398
399     video->pause();
400         usleep(500000); // SYNC
401     video->sync();
402     video->unPause();
403     video->sync();
404
405 /*
406     demuxer.flushAudio();
407     audio->reset();
408     afeed.enable();
409     //video->reset();
410     audio->play();
411     video->play();
412     video->sync();
413     audio->sync();
414     audio->systemMuteOff();
415 */
416   }
417   else
418   {
419     ffwd = 1;
420     afeed.disable();
421     audio->systemMuteOn();
422     video->fastForward();
423   }
424 }
425
426 void Player::toggleFastBackward()
427 {
428   if (!initted) return;
429   if (!playing) return;
430
431   if (paused) togglePause();
432   if (ffwd) toggleFastForward();
433
434   if (fbwd)
435   {
436     fbwd = 0;
437     afeed.enable();
438     audio->systemMuteOff();
439
440 //    threadStop();
441     feedMode = MODE_NORMAL;
442 //    threadStart();
443   }
444   else
445   {
446     fbwd = 1;
447     afeed.disable();
448     audio->systemMuteOn();
449
450     threadStop();
451     feedMode = MODE_BACKWARDS;
452     video->reset();
453     video->play();
454     demuxer.flush();
455     threadStart();
456   }
457 }
458
459 void Player::jumpToPercent(int percent)
460 {
461   threadStop();
462   vfeed.stop();
463   afeed.stop();
464   video->stop();
465   audio->stop();
466   video->reset();
467   audio->reset();
468   demuxer.flush();
469   demuxer.seek();
470   feedPosition = streamLength * percent / 100;
471   vfeed.start();
472   afeed.start();
473   threadStart();
474   audio->play();
475   video->play();
476   video->sync();
477   audio->sync();
478
479   video->pause();
480       usleep(500000); // SYNC
481   video->sync();
482   video->unPause();
483   video->sync();
484 }
485
486
487 void Player::call()
488 {
489   threadSignalNoLock();
490 }
491
492 // Feed thread
493
494 void Player::threadMethod()
495 {
496   UCHAR buf[blockSize];
497   int thisRead;
498   int writeLength;
499   int thisWrite;
500
501   VDR* vdr = VDR::getInstance();
502
503   int askFor;
504   while(1)
505   {
506     thisRead = 0;
507     writeLength = 0;
508     thisWrite = 0;
509
510     threadCheckExit();
511
512     // a bit hackey. this needs to be split to live and rec players
513     if (streamLength && (feedPosition >= streamLength)) break;
514     askFor = blockSize;
515     if (streamLength && ((feedPosition + blockSize) > streamLength))
516     {
517       askFor = streamLength - feedPosition;
518     }
519     thisRead = vdr->getBlock(buf, feedPosition, askFor);
520     if (startup)
521     {
522       int a_stream = demuxer.scan(buf, thisRead);
523       demuxer.setAudioStream(a_stream);
524       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
525       startup = 0;
526     }
527
528     if (feedMode == MODE_NORMAL)
529     {
530       feedPosition += thisRead;
531     }
532     else if (feedMode == MODE_BACKWARDS)
533     {
534       if (feedPosition >= 100000)
535       {
536         feedPosition -= 100000;
537         demuxer.seek();
538       }
539       else
540       {
541         // got to the start of the recording.. revert to play mode? how?
542         feedPosition += thisRead;
543       }
544     }
545
546     threadCheckExit();
547
548     while(writeLength < thisRead)
549     {
550       thisWrite = demuxer.put(buf + writeLength, thisRead - writeLength);
551       writeLength += thisWrite;
552
553       if (!thisWrite)
554       {
555         Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
556         // demuxer is full and cant take anymore
557         threadWaitForSignal();
558         Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
559       }
560
561       threadCheckExit();
562     }
563   }
564
565   // end of recording
566   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
567   Message* m = new Message();
568   m->message = Message::STOP_PLAYBACK;
569   Log::getInstance()->log("Player", Log::DEBUG, "Posting message...");
570   commandMessageQueue->postMessage(m);
571   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
572
573
574 }