]> git.vomp.tv Git - vompclient.git/blob - playervideo.cc
Fixed a few bugs. Standby off main menu, video off signal, numbers after del
[vompclient.git] / playervideo.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 "playervideo.h"
22
23 PlayerVideo::PlayerVideo(MessageQueue* messageQueue, UCHAR tIsRecording, UCHAR isRadio)
24 : vfeed(this), afeed(this)
25 {
26   commandMessageQueue = messageQueue;
27
28   logger = Log::getInstance();
29   paused = 0;
30   playing = 0;
31   ffwd = 0;
32   fbwd = 0;
33   feedPosition = 0;
34   feedMode = MODE_NORMAL;
35   isRecording = tIsRecording;
36   lastRescan = 0;
37   threadBuffer = NULL;
38
39   if (isRadio)
40   {
41     blockSize = 20000;
42     startupBlockSize = 60000;
43   }
44   else
45   {
46     blockSize = 100000;
47     startupBlockSize = 250000;
48   }
49 }
50
51 PlayerVideo::~PlayerVideo()
52 {
53   if (initted) shutdown();
54 }
55
56 int PlayerVideo::init()
57 {
58   if (initted) return 0;
59
60   video = Video::getInstance();
61
62   if (!demuxer.init(this))
63   {
64     logger->log("Player", Log::ERR, "Demuxer failed to init");
65     shutdown();
66     return 0;
67   }
68
69   vfeed.init(video->getFD());
70   afeed.init(audio->getFD());
71
72   video->stop();
73   video->blank();
74   audio->stop();
75
76   startup = 0;
77   initted = 1;
78   return 1;
79 }
80
81 int PlayerVideo::shutdown()
82 {
83   if (!initted) return 0;
84   initted = 0;
85
86   logger->log("Player", Log::DEBUG, "Player shutdown...");
87
88   // copy of stop
89   if (playing)
90   {
91     playing = 0;
92     threadStop();
93     video->stop();
94     video->blank();
95     audio->stop();
96     vfeed.stop();
97     afeed.stop();
98     video->reset();
99     demuxer.reset();
100     feedPosition = 0;
101   }
102   logger->log("Player", Log::DEBUG, "Player shutdown done");
103
104   return 1;
105 }
106
107 void PlayerVideo::resyncAudio()
108 {
109   // Temp hopefully
110
111   if (!initted) return;
112
113   audio->pause();
114       usleep(500000); // SYNC
115   audio->unPause();
116 }
117
118 int PlayerVideo::play()
119 {
120   if (!initted) return 0;
121
122   // If we are just paused, unpause!
123   if (paused)
124   {
125     togglePause();
126     return 1;
127   }
128
129   // If we are fast forwarding, set to normal
130   if (ffwd)
131   {
132     toggleFastForward();
133     return 1;
134   }
135
136   // If we are fast backwarding, set to normal
137   if (fbwd)
138   {
139     toggleFastBackward();
140     return 1;
141   }
142
143   // If we are already playing, bail // FIXME - resync?
144   if (playing)
145   {
146     logger->log("Player", Log::DEBUG, "DOING RESYNC");
147
148 /*
149     vfeed.stop();
150     afeed.stop();
151     video->reset();
152     audio->reset();
153     demuxer.flush();
154     demuxer.seek();
155     vfeed.start();
156     afeed.start();
157
158
159     video->play();
160     audio->play();
161     video->sync();
162     audio->sync();
163     call();
164 */
165
166     // resync method 2..
167
168     video->pause();
169     usleep(500000);
170     video->play();
171     video->sync();
172
173
174     return 1;
175   }
176
177   // Standard play start
178
179   audio->reset();
180   video->reset();
181   demuxer.reset();
182   startup = 1;
183
184 // ------------------------ This one works, but doesn't allow any pre-buffering.
185   threadStart();
186   vfeed.start();
187   afeed.start();
188   audio->play();
189   video->play();
190   video->sync();
191   audio->sync();
192
193   video->pause();
194       usleep(500000); // SYNC
195   video->sync();
196   video->unPause();
197   video->sync();
198 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
199
200 /*
201   threadStart();
202 //  sleep(1);
203
204 //  struct timespec delay;
205 //  delay.tv_sec = 1;
206 //  delay.tv_nsec = 500000000;
207 //  nanosleep(&delay, NULL);
208
209   vfeed.start();
210   afeed.start();
211   video->play();
212   audio->play();
213   video->sync();
214   audio->sync();
215
216   video->pause();
217       usleep(500000); // SYNC
218   video->sync();
219   video->unPause();
220   video->sync();
221 */
222
223 // ------------------------------------------------------------------------------------------------
224
225   playing = 1;
226   return 1;
227 }
228
229 void PlayerVideo::stop()
230 {
231   if (!initted) return;
232   if (!playing) return;
233
234   if (ffwd || fbwd)
235   {
236     ffwd = 0;
237     fbwd = 0;
238     afeed.enable();
239     video->unFastForward();
240     audio->systemMuteOff();
241     feedMode = MODE_NORMAL;
242   }
243
244   playing = 0;
245   paused = 0;
246
247   logger->log("PlayerVideo", Log::DEBUG, "Temp 1");
248   threadStop();
249   logger->log("PlayerVideo", Log::DEBUG, "Temp 2");
250   video->stop();
251   logger->log("PlayerVideo", Log::DEBUG, "Temp 3");
252   video->blank();
253   logger->log("PlayerVideo", Log::DEBUG, "Temp 4");
254   audio->stop();
255   logger->log("PlayerVideo", Log::DEBUG, "Temp 5");
256   audio->unPause();
257   logger->log("PlayerVideo", Log::DEBUG, "Temp 6");
258   vfeed.stop();
259   logger->log("PlayerVideo", Log::DEBUG, "Temp 7");
260   afeed.stop();
261   logger->log("PlayerVideo", Log::DEBUG, "Temp 8");
262   video->reset();
263   logger->log("PlayerVideo", Log::DEBUG, "Temp 9");
264   demuxer.reset();
265   logger->log("PlayerVideo", Log::DEBUG, "Temp 10");
266
267   feedPosition = 0;
268 }
269
270 void PlayerVideo::togglePause()
271 {
272   if (!initted) return;
273   if (!playing) return;
274
275   if (ffwd) toggleFastForward();
276   if (fbwd) toggleFastBackward();
277
278   if (paused)
279   {
280     video->unPause();
281     audio->unPause();
282     paused = 0;
283   }
284   else
285   {
286     video->pause();
287     audio->pause();
288     paused = 1;
289   }
290 }
291
292 void PlayerVideo::setPosition(ULLONG position)
293 {
294   feedPosition = position;
295 }
296
297 void PlayerVideo::setLength(ULLONG length)
298 {
299   lastRescan = time(NULL);
300   streamLength = length;
301   logger->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
302 }
303
304 void PlayerVideo::skipForward(int seconds)
305 {
306   // skip forward 1 minute
307   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
308
309   if (paused) togglePause();
310
311   ULLONG moveBy = seconds * 500000;
312
313   threadStop();
314   vfeed.stop();
315   afeed.stop();
316   video->stop();
317   video->reset();
318   audio->reset();
319   audio->doMuting();  // ???
320   demuxer.flush();
321   feedPosition += moveBy;
322
323 //  printf("Audio test %i\n", audio->test());
324
325   vfeed.start();
326   afeed.start();
327   threadStart();
328   audio->play();
329   video->play();
330   video->sync();
331   audio->sync();
332
333   video->pause();
334       usleep(500000); // SYNC
335   video->sync();
336   video->unPause();
337   video->sync();
338
339 }
340
341 void PlayerVideo::skipBackward(int seconds)
342 {
343   // skip forward 1 minute
344   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
345
346   if (paused) togglePause();
347
348   ULLONG moveBy = seconds * 500000;
349
350   threadStop();
351   vfeed.stop();
352   afeed.stop();
353   video->stop();
354   audio->stop();
355   video->reset();
356   audio->reset();
357   audio->doMuting(); // ???
358   demuxer.flush();
359   if (feedPosition > moveBy) feedPosition -= moveBy;
360   vfeed.start();
361   afeed.start();
362   threadStart();
363   audio->play();
364   video->play();
365   video->sync();
366   audio->sync();
367
368   video->pause();
369       usleep(500000); // SYNC
370   video->sync();
371   video->unPause();
372   video->sync();
373
374 }
375
376 void PlayerVideo::toggleFastForward()
377 {
378   if (!initted) return;
379   if (!playing) return;
380
381   if (paused) togglePause();
382   if (fbwd) toggleFastBackward();
383
384   if (ffwd)
385   {
386     ffwd = 0;
387 //    video->unFastForward();
388
389
390     threadStop();
391     vfeed.stop();
392     afeed.stop();
393     video->stop();
394     audio->stop();
395     video->reset();
396     audio->reset();
397     demuxer.flush();
398 //    demuxer.seek();
399     vfeed.start();
400     afeed.enable();
401     afeed.start();
402     threadStart();
403     video->play();
404     audio->play();
405     video->sync();
406     audio->sync();
407
408     audio->systemMuteOff();
409
410     video->pause();
411         usleep(500000); // SYNC
412     video->sync();
413     video->unPause();
414     video->sync();
415
416 /*
417     demuxer.flushAudio();
418     audio->reset();
419     afeed.enable();
420     //video->reset();
421     audio->play();
422     video->play();
423     video->sync();
424     audio->sync();
425     audio->systemMuteOff();
426 */
427   }
428   else
429   {
430     ffwd = 1;
431     afeed.disable();
432     audio->systemMuteOn();
433     video->fastForward();
434   }
435 }
436
437 void PlayerVideo::toggleFastBackward()
438 {
439   if (!initted) return;
440   if (!playing) return;
441
442   if (paused) togglePause();
443   if (ffwd) toggleFastForward();
444
445   if (fbwd)
446   {
447     fbwd = 0;
448     afeed.enable();
449     audio->systemMuteOff();
450
451 //    threadStop();
452     feedMode = MODE_NORMAL;
453 //    threadStart();
454   }
455   else
456   {
457     fbwd = 1;
458     afeed.disable();
459     audio->systemMuteOn();
460
461     threadStop();
462     feedMode = MODE_BACKWARDS;
463     video->reset();
464     video->play();
465     demuxer.flush();
466     threadStart();
467   }
468 }
469
470 void PlayerVideo::jumpToPercent(int percent)
471 {
472   threadStop();
473   vfeed.stop();
474   afeed.stop();
475   video->stop();
476   audio->stop();
477   video->reset();
478   audio->reset();
479   demuxer.flush();
480   demuxer.seek();
481   feedPosition = streamLength * percent / 100;
482   vfeed.start();
483   afeed.start();
484   threadStart();
485   audio->play();
486   video->play();
487   video->sync();
488   audio->sync();
489
490   video->pause();
491       usleep(500000); // SYNC
492   video->sync();
493   video->unPause();
494   video->sync();
495 }
496
497
498 void PlayerVideo::call(void* caller)
499 {
500   if (caller == &demuxer)
501   {
502     logger->log("Player", Log::DEBUG, "Callback from demuxer");
503
504     if (video->getTVsize() == Video::ASPECT4X3)
505     {
506       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
507       return;
508     }
509
510     int dxCurrentAspect = demuxer.getAspectRatio();
511     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
512     {
513       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
514       video->setAspectRatio(Video::ASPECT4X3);
515     }
516     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
517     {
518       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
519       video->setAspectRatio(Video::ASPECT16X9);
520     }
521     else
522     {
523       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
524     }
525
526   }
527   else
528   {
529     threadSignalNoLock();
530   }
531 }
532
533 // Feed thread
534
535 void PlayerVideo::threadMethod()
536 {
537   UINT thisRead;
538   UINT writeLength;
539   UINT thisWrite;
540
541   VDR* vdr = VDR::getInstance();
542
543   UINT askFor;
544   while(1)
545   {
546     thisRead = 0;
547     writeLength = 0;
548     thisWrite = 0;
549
550     threadCheckExit();
551
552     // If we havn't rescanned for a while..
553     if (isRecording && ((lastRescan + 60) < time(NULL)))
554     {
555       streamLength = vdr->rescanRecording();
556       Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
557       lastRescan = time(NULL);
558     }
559
560     if (streamLength) // is playing a recording
561     {
562       if (feedPosition >= streamLength) break;  // finished playback
563
564       if (startup)
565       {
566         if (startupBlockSize > streamLength)
567           askFor = streamLength; // is a very small recording!
568         else
569           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
570       }
571       else
572       {
573         if ((feedPosition + blockSize) > streamLength) // last block of recording
574           askFor = streamLength - feedPosition;
575         else // normal
576           askFor = blockSize;
577       }
578     }
579     else // is playing live
580     {
581       if (startup)
582         askFor = startupBlockSize; // find audio streams sized block
583       else
584         askFor = blockSize; // normal
585     }
586
587     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
588     if (!threadBuffer) break;
589
590     if (startup)
591     {
592       int a_stream = demuxer.scan(threadBuffer, thisRead);
593       demuxer.setAudioStream(a_stream);
594       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
595       startup = 0;
596     }
597
598     if (feedMode == MODE_NORMAL)
599     {
600       feedPosition += thisRead;
601     }
602     else if (feedMode == MODE_BACKWARDS)
603     {
604       if (feedPosition >= blockSize)
605       {
606         feedPosition -= blockSize;
607         demuxer.seek();
608       }
609       else
610       {
611         // got to the start of the recording.. revert to play mode? how?
612         feedPosition += thisRead;
613       }
614     }
615
616     threadCheckExit();
617
618     while(writeLength < thisRead)
619     {
620       thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
621       writeLength += thisWrite;
622
623       if (!thisWrite)
624       {
625 //        Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
626         // demuxer is full and cant take anymore
627         threadLock();
628         threadWaitForSignal();
629         threadUnlock();
630 //        Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
631       }
632
633       threadCheckExit();
634     }
635
636     free(threadBuffer);
637     threadBuffer = NULL;
638
639   }
640
641   // end of recording
642   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
643   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
644   if (streamLength) m->message = Message::STOP_PLAYBACK;  // recording
645   else m->message = Message::STREAM_END;                  // live
646   Log::getInstance()->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
647   commandMessageQueue->postMessage(m);
648   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
649 }
650
651 void PlayerVideo::threadPostStopCleanup()
652 {
653   Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
654   if (threadBuffer)
655   {
656     Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");
657     free(threadBuffer);
658     threadBuffer = NULL;
659   }
660 }
661
662 #ifdef DEV
663 void PlayerVideo::test1()
664 {
665   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 1");
666 }
667
668 void PlayerVideo::test2()
669 {
670   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 2");
671 }
672 #endif