]> git.vomp.tv Git - vompclient.git/blob - playervideo.cc
Big code cleanup
[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
199 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
200
201 /*
202
203   threadStart();
204   sleep(2);
205
206 //  struct timespec delay;
207 //  delay.tv_sec = 1;
208 //  delay.tv_nsec = 500000000;
209 //  nanosleep(&delay, NULL);
210
211   vfeed.start();
212   afeed.start();
213   video->play();
214   audio->play();
215   video->sync();
216   audio->sync();
217 */
218 // ------------------------------------------------------------------------------------------------
219
220   playing = 1;
221   return 1;
222 }
223
224 void PlayerVideo::stop()
225 {
226   if (!initted) return;
227   if (!playing) return;
228
229   if (ffwd || fbwd)
230   {
231     ffwd = 0;
232     fbwd = 0;
233     afeed.enable();
234     video->unFastForward();
235     audio->systemMuteOff();
236     feedMode = MODE_NORMAL;
237   }
238
239   playing = 0;
240   paused = 0;
241
242   logger->log("PlayerVideo", Log::DEBUG, "Temp 1");
243   threadStop();
244   logger->log("PlayerVideo", Log::DEBUG, "Temp 2");
245   video->stop();
246   logger->log("PlayerVideo", Log::DEBUG, "Temp 3");
247   video->blank();
248   logger->log("PlayerVideo", Log::DEBUG, "Temp 4");
249   audio->stop();
250   logger->log("PlayerVideo", Log::DEBUG, "Temp 5");
251   audio->unPause();
252   logger->log("PlayerVideo", Log::DEBUG, "Temp 6");
253   vfeed.stop();
254   logger->log("PlayerVideo", Log::DEBUG, "Temp 7");
255   afeed.stop();
256   logger->log("PlayerVideo", Log::DEBUG, "Temp 8");
257   video->reset();
258   logger->log("PlayerVideo", Log::DEBUG, "Temp 9");
259   demuxer.reset();
260   logger->log("PlayerVideo", Log::DEBUG, "Temp 10");
261
262   feedPosition = 0;
263 }
264
265 void PlayerVideo::togglePause()
266 {
267   if (!initted) return;
268   if (!playing) return;
269
270   if (ffwd) toggleFastForward();
271   if (fbwd) toggleFastBackward();
272
273   if (paused)
274   {
275     video->unPause();
276     audio->unPause();
277     paused = 0;
278   }
279   else
280   {
281     video->pause();
282     audio->pause();
283     paused = 1;
284   }
285 }
286
287 void PlayerVideo::setPosition(ULLONG position)
288 {
289   feedPosition = position;
290 }
291
292 void PlayerVideo::setLength(ULLONG length)
293 {
294   lastRescan = time(NULL);
295   streamLength = length;
296   logger->log("PlayerVideo", Log::DEBUG, "Player has received length of %llu", streamLength);
297 }
298
299 void PlayerVideo::skipForward(int seconds)
300 {
301   // skip forward 1 minute
302   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
303
304   if (paused) togglePause();
305
306   ULLONG moveBy = seconds * 500000;
307
308   threadStop();
309   vfeed.stop();
310   afeed.stop();
311   video->stop();
312   video->reset();
313   audio->reset();
314   audio->doMuting();  // ???
315   demuxer.flush();
316   feedPosition += moveBy;
317
318 //  printf("Audio test %i\n", audio->test());
319
320   vfeed.start();
321   afeed.start();
322   threadStart();
323   audio->play();
324   video->play();
325   video->sync();
326   audio->sync();
327
328   video->pause();
329       usleep(500000); // SYNC
330   video->sync();
331   video->unPause();
332   video->sync();
333
334 }
335
336 void PlayerVideo::skipBackward(int seconds)
337 {
338   // skip forward 1 minute
339   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
340
341   if (paused) togglePause();
342
343   ULLONG moveBy = seconds * 500000;
344
345   threadStop();
346   vfeed.stop();
347   afeed.stop();
348   video->stop();
349   audio->stop();
350   video->reset();
351   audio->reset();
352   audio->doMuting(); // ???
353   demuxer.flush();
354   if (feedPosition > moveBy) feedPosition -= moveBy;
355   vfeed.start();
356   afeed.start();
357   threadStart();
358   audio->play();
359   video->play();
360   video->sync();
361   audio->sync();
362
363   video->pause();
364       usleep(500000); // SYNC
365   video->sync();
366   video->unPause();
367   video->sync();
368
369 }
370
371 void PlayerVideo::toggleFastForward()
372 {
373   if (!initted) return;
374   if (!playing) return;
375
376   if (paused) togglePause();
377   if (fbwd) toggleFastBackward();
378
379   if (ffwd)
380   {
381     ffwd = 0;
382 //    video->unFastForward();
383
384
385     threadStop();
386     vfeed.stop();
387     afeed.stop();
388     video->stop();
389     audio->stop();
390     video->reset();
391     audio->reset();
392     demuxer.flush();
393 //    demuxer.seek();
394     vfeed.start();
395     afeed.enable();
396     afeed.start();
397     threadStart();
398     video->play();
399     audio->play();
400     video->sync();
401     audio->sync();
402
403     audio->systemMuteOff();
404
405     video->pause();
406         usleep(500000); // SYNC
407     video->sync();
408     video->unPause();
409     video->sync();
410
411 /*
412     demuxer.flushAudio();
413     audio->reset();
414     afeed.enable();
415     //video->reset();
416     audio->play();
417     video->play();
418     video->sync();
419     audio->sync();
420     audio->systemMuteOff();
421 */
422   }
423   else
424   {
425     ffwd = 1;
426     afeed.disable();
427     audio->systemMuteOn();
428     video->fastForward();
429   }
430 }
431
432 void PlayerVideo::toggleFastBackward()
433 {
434   if (!initted) return;
435   if (!playing) return;
436
437   if (paused) togglePause();
438   if (ffwd) toggleFastForward();
439
440   if (fbwd)
441   {
442     fbwd = 0;
443     afeed.enable();
444     audio->systemMuteOff();
445
446 //    threadStop();
447     feedMode = MODE_NORMAL;
448 //    threadStart();
449   }
450   else
451   {
452     fbwd = 1;
453     afeed.disable();
454     audio->systemMuteOn();
455
456     threadStop();
457     feedMode = MODE_BACKWARDS;
458     video->reset();
459     video->play();
460     demuxer.flush();
461     threadStart();
462   }
463 }
464
465 void PlayerVideo::jumpToPercent(int percent)
466 {
467   threadStop();
468   vfeed.stop();
469   afeed.stop();
470   video->stop();
471   audio->stop();
472   video->reset();
473   audio->reset();
474   demuxer.flush();
475   demuxer.seek();
476   feedPosition = streamLength * percent / 100;
477   vfeed.start();
478   afeed.start();
479   threadStart();
480   audio->play();
481   video->play();
482   video->sync();
483   audio->sync();
484
485   video->pause();
486       usleep(500000); // SYNC
487   video->sync();
488   video->unPause();
489   video->sync();
490 }
491
492
493 void PlayerVideo::call(void* caller)
494 {
495   if (caller == &demuxer)
496   {
497     logger->log("Player", Log::DEBUG, "Callback from demuxer");
498
499     if (video->getTVsize() == Video::ASPECT4X3)
500     {
501       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
502       return;
503     }
504
505     int dxCurrentAspect = demuxer.getAspectRatio();
506     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
507     {
508       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
509       video->setAspectRatio(Video::ASPECT4X3);
510     }
511     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
512     {
513       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
514       video->setAspectRatio(Video::ASPECT16X9);
515     }
516     else
517     {
518       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
519     }
520
521   }
522   else
523   {
524     threadSignalNoLock();
525   }
526 }
527
528 // Feed thread
529
530 void PlayerVideo::threadMethod()
531 {
532   UINT thisRead;
533   UINT writeLength;
534   UINT thisWrite;
535
536   VDR* vdr = VDR::getInstance();
537
538   UINT askFor;
539   while(1)
540   {
541     thisRead = 0;
542     writeLength = 0;
543     thisWrite = 0;
544
545     threadCheckExit();
546
547     // If we havn't rescanned for a while..
548     if (isRecording && ((lastRescan + 60) < time(NULL)))
549     {
550       streamLength = vdr->rescanRecording();
551       Log::getInstance()->log("PlayerVideo", Log::DEBUG, "Rescanned and reset length: %llu", streamLength);
552       lastRescan = time(NULL);
553     }
554
555     if (streamLength) // is playing a recording
556     {
557       if (feedPosition >= streamLength) break;  // finished playback
558
559       if (startup)
560       {
561         if (startupBlockSize > streamLength)
562           askFor = streamLength; // is a very small recording!
563         else
564           askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
565       }
566       else
567       {
568         if ((feedPosition + blockSize) > streamLength) // last block of recording
569           askFor = streamLength - feedPosition;
570         else // normal
571           askFor = blockSize;
572       }
573     }
574     else // is playing live
575     {
576       if (startup)
577         askFor = startupBlockSize; // find audio streams sized block
578       else
579         askFor = blockSize; // normal
580     }
581
582     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
583     if (!threadBuffer) break;
584
585     if (startup)
586     {
587       int a_stream = demuxer.scan(threadBuffer, thisRead);
588       demuxer.setAudioStream(a_stream);
589       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
590       startup = 0;
591     }
592
593     if (feedMode == MODE_NORMAL)
594     {
595       feedPosition += thisRead;
596     }
597     else if (feedMode == MODE_BACKWARDS)
598     {
599       if (feedPosition >= blockSize)
600       {
601         feedPosition -= blockSize;
602         demuxer.seek();
603       }
604       else
605       {
606         // got to the start of the recording.. revert to play mode? how?
607         feedPosition += thisRead;
608       }
609     }
610
611     threadCheckExit();
612
613     while(writeLength < thisRead)
614     {
615       thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
616       writeLength += thisWrite;
617
618       if (!thisWrite)
619       {
620 //        Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
621         // demuxer is full and cant take anymore
622         threadLock();
623         threadWaitForSignal();
624         threadUnlock();
625 //        Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
626       }
627
628       threadCheckExit();
629     }
630
631     free(threadBuffer);
632     threadBuffer = NULL;
633
634   }
635
636   // end of recording
637   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
638   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
639   if (streamLength) m->message = Message::STOP_PLAYBACK;  // recording
640   else m->message = Message::STREAM_END;                  // live
641   Log::getInstance()->log("Player", Log::DEBUG, "Posting message to %p...", commandMessageQueue);
642   commandMessageQueue->postMessage(m);
643   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
644 }
645
646 void PlayerVideo::threadPostStopCleanup()
647 {
648   Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 1");
649   if (threadBuffer)
650   {
651     Log::getInstance()->log("Player", Log::DEBUG, "Post stop cleanup 2");
652     free(threadBuffer);
653     threadBuffer = NULL;
654   }
655 }
656
657 #ifdef DEV
658 void PlayerVideo::test1()
659 {
660   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 1");
661 }
662
663 void PlayerVideo::test2()
664 {
665   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST 2");
666 }
667 #endif