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