]> git.vomp.tv Git - vompclient.git/blob - player.cc
Rewrite timers class using std::thread/mutex/cond/chrono
[vompclient.git] / player.cc
1 /*
2     Copyright 2004-2008 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "player.h"
21
22 #include "log.h"
23 #include "audio.h"
24 #include "video.h"
25 #include "demuxervdr.h"
26 #include "demuxerts.h"
27 #include "vdr.h"
28 #include "messagequeue.h"
29 #include "input.h"
30 #include "message.h"
31 #include "dvbsubtitles.h"
32 #include "osdreceiver.h"
33
34 #define USER_RESPONSE_TIME 500 // Milliseconds
35
36 // ----------------------------------- Called from outside, one offs or info funcs
37
38 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
39 : vfeed(this), afeed(this), tfeed(this)
40 {
41   messageQueue = tmessageQueue;
42   messageReceiver = tmessageReceiver;
43   osdReceiver = tosdReceiver;
44   audio = Audio::getInstance();
45   video = Video::getInstance();
46   logger = Log::getInstance();
47   vdr = VDR::getInstance();
48
49   video->turnVideoOn();
50 }
51
52 Player::~Player()
53 {
54   if (initted) shutdown();
55 }
56
57 int Player::init(bool p_isPesRecording, double framespersecond)
58 {
59   if (initted) return 0;
60 #ifndef WIN32
61   pthread_mutex_init(&mutex, NULL);
62 #else
63   mutex=CreateMutex(NULL,FALSE,NULL);
64 #endif
65   is_pesrecording = p_isPesRecording;
66   fps = framespersecond;
67   if (is_pesrecording)
68     demuxer = new DemuxerVDR();
69   else
70     demuxer = new DemuxerTS();
71   if (!demuxer) return 0;
72   subtitles = new DVBSubtitles(osdReceiver);
73   if (!subtitles) return 0;
74
75   teletext = new TeletextDecoderVBIEBU();
76   if (!teletext) return 0;
77   teletext->setRecordigMode(true);
78   unsigned int demux_video_size = 2097152;
79   unsigned int demux_audio_size = 524288;
80   if (video->supportsh264())
81   {
82     demux_video_size *= 5 * 2;
83   }
84   if (audio->maysupportAc3())
85   {
86     //demux_audio_size*=2;
87   }
88  
89   if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,65536, framespersecond, subtitles))
90   {
91     logger->log("Player", Log::ERR, "Demuxer failed to init");
92     shutdown();
93     return 0;
94   }
95
96   vfeed.init();
97   afeed.init();
98   tfeed.init();
99
100   video->stop();
101   video->blank();
102   audio->stop();
103
104   if (Command::getInstance()->getSubDefault())
105     turnSubtitlesOn(true);
106   else
107     turnSubtitlesOn(false);
108
109   initted = true;
110   return 1;
111 }
112
113 int Player::shutdown()
114 {
115   if (!initted) return 0;
116   switchState(S_STOP);
117   initted = false;
118
119   delete demuxer;
120   demuxer = NULL;
121   delete subtitles;
122   subtitles = NULL;
123   delete teletext;
124   teletext = NULL;
125
126 #ifdef WIN32
127   CloseHandle(mutex);
128 #endif
129
130   return 1;
131 }
132
133 void Player::setStartFrame(ULONG startFrame)
134 {
135   ULONG nextiframeNumber;
136   ULONG iframeLength;
137   ULONG iframeNumber;
138   ULLONG filePos;
139
140   // newFrame could be anywhere, go forwards to next I-Frame
141   if (!vdr->getNextIFrame(startFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
142
143   // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
144   vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
145
146   logger->log("Player", Log::DEBUG, "setStartFrame %lu %lu %lu", startFrame, nextiframeNumber,iframeNumber);
147   currentFrameNumber = iframeNumber;
148 }
149
150 void Player::setLengthBytes(ULLONG length)
151 {
152   lengthBytes = length;
153   logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
154 }
155
156 void Player::setLengthFrames(ULONG length)
157 {
158   lengthFrames = length;
159   logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
160 }
161
162 ULONG Player::getLengthFrames()
163 {
164   return lengthFrames;
165 }
166
167 ULONG Player::getCurrentFrameNum()
168 {
169   if (startup) return 0;
170   switch(state)
171   {
172     case S_PLAY:
173     case S_PAUSE_P:
174       return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
175     case S_PAUSE_I:
176     case S_FFWD:
177     case S_FBWD:
178       return currentFrameNumber;
179     default:
180       return 0; // shouldn't happen
181   }
182 }
183
184 bool* Player::getDemuxerMpegAudioChannels()
185 {
186   return demuxer->getmpAudioChannels();
187 }
188
189 bool* Player::getDemuxerAc3AudioChannels()
190 {
191   return demuxer->getac3AudioChannels();
192 }
193
194 bool* Player::getDemuxerSubtitleChannels()
195 {
196   return demuxer->getSubtitleChannels();
197 }
198
199 int Player::getCurrentAudioChannel()
200 {
201   if (is_pesrecording)
202     return demuxer->getselAudioChannel();
203   else
204     return dynamic_cast<DemuxerTS*>(demuxer)->getAID();
205 }
206
207 int Player::getCurrentSubtitleChannel()
208 {
209   if (is_pesrecording)
210     return demuxer->getselSubtitleChannel();
211   else
212     return dynamic_cast<DemuxerTS*>(demuxer)->getSubID();
213 }
214
215 void Player::setSubtitleChannel(int newChannel)
216 {
217   if (is_pesrecording)
218     demuxer->setDVBSubtitleStream(newChannel);
219   else
220     dynamic_cast<DemuxerTS*>(demuxer)->setSubID(newChannel);
221 }
222
223 int *Player::getTeletxtSubtitlePages()
224 {
225   return teletext->getSubtitlePages();
226 }
227
228 void Player::setAudioChannel(int newChannel, int type, int streamtype)
229 {
230   if (is_pesrecording)
231   {
232     demuxer->setAudioStream(newChannel);
233     return;
234   }
235   else
236   {
237     dynamic_cast<DemuxerTS*>(demuxer)->setAID(newChannel,type,streamtype,false);
238     return;
239   }
240 }
241
242 bool Player::toggleSubtitles()
243 {
244   if (!subtitlesShowing)
245   {
246     subtitlesShowing = true;
247     subtitles->show();
248   }
249   else
250   {
251     subtitlesShowing = false;
252     subtitles->hide();
253   }
254   return subtitlesShowing;
255 }
256
257 void  Player::turnSubtitlesOn(bool ison)
258 {
259  if (ison)
260   {
261     subtitlesShowing = true;
262     subtitles->show();
263   }
264   else
265   {
266     subtitlesShowing = false;
267     subtitles->hide();
268   }
269 }
270
271 void Player::tellSubtitlesOSDVisible(bool visible)
272 {
273   subtitles->setOSDMenuVisibility(visible);
274 }
275
276 Channel * Player::getDemuxerChannel()
277 {
278   if (!is_pesrecording)
279   {
280     return dynamic_cast<DemuxerTS*>(demuxer)->getChannelInfo();
281   }
282   return NULL; //Should not happen!
283 }
284
285
286 // ----------------------------------- Externally called events
287
288 void Player::play()
289 {
290   if (!initted) return;
291   if (state == S_PLAY) return;
292   lock();
293
294   bool doUnlock = false;
295   if (state == S_PAUSE_P) doUnlock = true;
296   switchState(S_PLAY);
297   if (doUnlock) unLock();
298 }
299
300 void Player::playpause()
301 {
302   if (!initted) return;
303   lock();
304
305   bool doUnlock = false;
306   if (state==S_PLAY)
307   {
308     doUnlock=true;
309     switchState(S_PAUSE_P);
310   }
311   else
312   {
313     if (state == S_PAUSE_P) doUnlock = true;
314     switchState(S_PLAY);
315   }
316   if (doUnlock) unLock();
317 }
318
319 void Player::stop()
320 {
321   if (!initted) return;
322   if (state == S_STOP) return;
323   lock();
324   logger->log("Player", Log::DEBUG, "Stop called lock");
325   switchState(S_STOP);
326   unLock();
327 }
328
329 void Player::pause()
330 {
331   if (!initted) return;
332   lock();
333
334   if ((state == S_FFWD) || (state == S_FBWD))
335   {
336     switchState(S_PAUSE_I);
337   }
338   else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
339   {
340     switchState(S_PLAY);
341   }
342   else
343   {
344     switchState(S_PAUSE_P);
345   }
346
347   unLock();
348 }
349
350 void Player::fastForward()
351 {
352   if (!initted) return;
353   lock();
354
355   if (state == S_FFWD)
356   {
357     // change the rate
358     switch(ifactor)
359     {
360       case 4: ifactor = 8; break;
361       case 8: ifactor = 16; break;
362       case 16: ifactor = 32; break;
363       case 32: ifactor = 4; break;
364     }
365   }
366   else
367   {
368     ifactor = 4;
369     switchState(S_FFWD);
370   }
371   unLock();
372 }
373
374 void Player::fastBackward()
375 {
376   if (!initted) return;
377   lock();
378
379   if (state == S_FBWD)
380   {
381     // change the rate
382     switch(ifactor)
383     {
384       case 4: ifactor = 8; break;
385       case 8: ifactor = 16; break;
386       case 16: ifactor = 32; break;
387       case 32: ifactor = 4; break;
388     }
389   }
390   else
391   {
392     ifactor = 4;
393     switchState(S_FBWD);
394   }
395   unLock();
396 }
397
398 void Player::jumpToPercent(double percent)
399 {
400   lock();
401   logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
402   ULONG newFrame = static_cast<ULONG>(percent * lengthFrames / 100);
403   switchState(S_JUMP, newFrame);
404 //  unLock(); - let thread unlock this
405 }
406
407 void Player::jumpToMark(int mark)
408 {
409   lock();
410   logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
411   switchState(S_JUMP, mark);
412 //  unLock(); - let thread unlock this
413 }
414
415 void Player::jumpToFrameP(int newFrame)
416 {
417   lock();
418   logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
419   switchState(S_JUMP_PI, newFrame);
420   unLock();
421 }
422
423 void Player::skipForward(int seconds)
424 {
425   lock();
426   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
427   ULONG newFrame = getCurrentFrameNum();
428   if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
429   newFrame += static_cast<ULONG>(static_cast<double>(seconds) * fps);
430   if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
431   else switchState(S_JUMP, newFrame);
432 //  unLock(); - let thread unlock this
433 }
434
435 void Player::skipBackward(int seconds)
436 {
437   lock();
438   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
439   long newFrame = getCurrentFrameNum();
440   if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
441   newFrame -= static_cast<ULONG>(static_cast<double>(seconds) * fps);
442   if (newFrame < 0) newFrame = 0;
443   switchState(S_JUMP, newFrame);
444 //  unLock(); - let thread unlock this
445 }
446
447 // ----------------------------------- Implementations called events
448
449 void Player::switchState(UCHAR toState, ULONG jumpFrame)
450 {
451   if (!initted) return;
452
453   logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
454
455   switch(state) // current state selector
456   {
457     case S_PLAY: // from S_PLAY -----------------------------------
458     {
459       switch(toState)
460       {
461         case S_PLAY: // to S_PLAY
462         {
463           return;
464         }
465         case S_PAUSE_P: // to S_PAUSE_P
466         {
467           #ifdef VOMP_PLATFORM_RASPBERRY
468           vfeed.stop(); // can't vfeed during pause
469           #endif
470
471           video->pause();
472           audio->pause();
473           state = S_PAUSE_P;
474           return;
475         }
476         case S_PAUSE_I: // to S_PAUSE_I
477         {
478           // can't occur
479           return;
480         }
481         case S_FFWD: // to S_FFWD
482         {
483           currentFrameNumber = getCurrentFrameNum();
484           audio->systemMuteOn();
485           threadStop();
486           vfeed.stop();
487           afeed.stop();
488           tfeed.stop();
489           subtitles->stop();
490           demuxer->flush();
491           state = S_FFWD;
492           threadStart();
493           return;
494         }
495         case S_FBWD: // to S_FBWD
496         {
497           currentFrameNumber = getCurrentFrameNum();
498           audio->systemMuteOn();
499           threadStop();
500           vfeed.stop();
501           afeed.stop();
502           tfeed.stop();
503           subtitles->stop();
504           demuxer->flush();
505           state = S_FBWD;
506           threadStart();
507           return;
508         }
509         case S_STOP: // to S_STOP
510         {
511           vfeed.stop();
512           afeed.stop();
513           tfeed.stop();
514           subtitles->stop();
515           threadStop();
516           video->stop();
517           video->blank();
518           audio->stop();
519           audio->unPause();
520           video->reset();
521           demuxer->reset();
522           state = S_STOP;
523           return;
524         }
525         case S_JUMP: // to S_JUMP
526         {
527           restartAtFrame(jumpFrame);
528           return;
529         }
530         case S_JUMP_PI: // to S_JUMP_PI
531         {
532           audio->systemMuteOn();
533           threadStop();
534           vfeed.stop();
535           afeed.stop();
536           tfeed.stop();
537           subtitles->stop();
538           demuxer->flush();
539           state = S_PAUSE_I;
540           video->reset();
541           video->play();
542           restartAtFramePI(jumpFrame);
543           return;
544         }
545       }
546     }
547     FALLTHROUGH // keep compiler happy (all posibilities return)
548     case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
549     {
550       switch(toState)
551       {
552         case S_PLAY: // to S_PLAY
553         {
554           video->unPause();
555           audio->unPause();
556
557           #ifdef VOMP_PLATFORM_RASPBERRY
558           vfeed.start(false);
559           #endif
560
561           state = S_PLAY;
562           return;
563         }
564         case S_PAUSE_P: // to S_PAUSE_P
565         {
566           return;
567         }
568         case S_PAUSE_I: // to S_PAUSE_I
569         {
570           return;
571         }
572         case S_FFWD: // to S_FFWD
573         {
574           currentFrameNumber = getCurrentFrameNum();
575           audio->systemMuteOn();
576           vfeed.stop();
577           afeed.stop();
578           tfeed.stop();
579           subtitles->stop();
580           threadStop();
581           video->unPause();
582           audio->unPause();
583           state = S_FFWD;
584           threadStart();
585           return;
586         }
587         case S_FBWD: // to S_FBWD
588         {
589           currentFrameNumber = getCurrentFrameNum();
590           audio->systemMuteOn();
591           vfeed.stop();
592           afeed.stop();
593           tfeed.stop();
594           subtitles->stop();
595           threadStop();
596           video->unPause();
597           audio->unPause();
598           state = S_FBWD;
599           threadStart();
600           return;
601         }
602         case S_STOP: // to S_STOP
603         {
604           vfeed.stop();
605           afeed.stop();
606           tfeed.stop();
607           subtitles->stop();
608           threadStop();
609           video->stop();
610           video->blank();
611           audio->stop();
612           video->reset();
613           audio->unPause();
614           demuxer->reset();
615           audio->systemMuteOff();
616           state = S_STOP;
617           return;
618         }
619         case S_JUMP: // to S_JUMP
620         {
621           state = S_PLAY;
622           audio->systemMuteOn();
623           audio->unPause();
624           restartAtFrame(jumpFrame);
625           return;
626         }
627         case S_JUMP_PI: // to S_JUMP_PI
628         {
629           audio->systemMuteOn();
630           audio->unPause();
631           threadStop();
632           vfeed.stop();
633           afeed.stop();
634           tfeed.stop();
635           subtitles->stop();
636           demuxer->flush();
637           state = S_PAUSE_I;
638           video->reset();
639           video->play();
640           restartAtFramePI(jumpFrame);
641           return;
642         }
643       }
644     }
645     FALLTHROUGH // keep compiler happy (all posibilities return)
646     case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
647     {
648       switch(toState)
649       {
650         case S_PLAY: // to S_PLAY
651         {
652           state = S_PLAY;
653           restartAtFrame(currentFrameNumber);
654           return;
655         }
656         case S_PAUSE_P: // to S_PAUSE_P
657         {
658           return;
659         }
660         case S_PAUSE_I: // to S_PAUSE_I
661         {
662           return;
663         }
664         case S_FFWD: // to S_FFWD
665         {
666           state = S_FFWD;
667           threadStart();
668           return;
669         }
670         case S_FBWD: // to S_FBWD
671         {
672           state = S_FBWD;
673           threadStart();
674           return;
675         }
676         case S_STOP: // to S_STOP
677         {
678           video->stop();
679           video->blank();
680           audio->stop();
681           video->reset();
682           demuxer->reset();
683           audio->systemMuteOff();
684           state = S_STOP;
685           return;
686         }
687         case S_JUMP: // to S_JUMP
688         {
689           state = S_PLAY;
690           restartAtFrame(jumpFrame);
691           return;
692         }
693         case S_JUMP_PI: // to S_JUMP_PI
694         {
695           restartAtFramePI(jumpFrame);
696           return;
697         }
698       }
699     }
700     FALLTHROUGH // keep compiler happy (all posibilities return)
701     case S_FFWD: // from S_FFWD -----------------------------------
702     {
703       switch(toState)
704       {
705         case S_PLAY: // to S_PLAY
706         {
707           state = S_PLAY;
708           ULONG stepback = static_cast<ULONG>(USER_RESPONSE_TIME * ifactor * fps / 1000);
709           if (stepback < currentFrameNumber)
710             currentFrameNumber -= stepback;
711           else
712             currentFrameNumber = 0;
713           restartAtFrame(currentFrameNumber);
714           return;
715         }
716         case S_PAUSE_P: // to S_PAUSE_P
717         {
718           // can't occur
719           return;
720         }
721         case S_PAUSE_I: // to S_PAUSE_I
722         {
723           threadStop();
724           state = S_PAUSE_I;
725           return;
726         }
727         case S_FFWD: // to S_FFWD
728         {
729           return;
730         }
731         case S_FBWD: // to S_FBWD
732         {
733           threadStop();
734           state = S_FBWD;
735           threadStart();
736           return;
737         }
738         case S_STOP: // to S_STOP
739         {
740           threadStop();
741           video->stop();
742           video->blank();
743           audio->stop();
744           video->reset();
745           demuxer->reset();
746           state = S_STOP;
747           return;
748         }
749         case S_JUMP: // to S_JUMP
750         {
751           state = S_PLAY;
752           restartAtFrame(jumpFrame);
753           return;
754         }
755         case S_JUMP_PI: // to S_JUMP_PI
756         {
757           threadStop();
758           state = S_PAUSE_I;
759           restartAtFramePI(jumpFrame);
760           return;
761         }
762       }
763     }
764     FALLTHROUGH // keep compiler happy (all posibilities return)
765     case S_FBWD: // from S_FBWD -----------------------------------
766     {
767       switch(toState)
768       {
769         case S_PLAY: // to S_PLAY
770         {
771           state = S_PLAY;
772           restartAtFrame(currentFrameNumber);
773           return;
774         }
775         case S_PAUSE_P: // to S_PAUSE_P
776         {
777           // can't occur
778           return;
779         }
780         case S_PAUSE_I: // to S_PAUSE_I
781         {
782           threadStop();
783           state = S_PAUSE_I;
784           return;
785         }
786         case S_FFWD: // to S_FFWD
787         {
788           threadStop();
789           state = S_FFWD;
790           threadStart();
791           return;
792         }
793         case S_FBWD: // to S_FBWD
794         {
795           return;
796         }
797         case S_STOP: // to S_STOP
798         {
799           threadStop();
800           video->stop();
801           video->blank();
802           audio->stop();
803           video->reset();
804           demuxer->reset();
805           state = S_STOP;
806           return;
807         }
808         case S_JUMP: // to S_JUMP
809         {
810           state = S_PLAY;
811           restartAtFrame(jumpFrame);
812           return;
813         }
814         case S_JUMP_PI: // to S_JUMP_PI
815         {
816           threadStop();
817           state = S_PAUSE_I;
818           restartAtFramePI(jumpFrame);
819           return;
820         }
821       }
822     }
823     FALLTHROUGH // keep compiler happy (all posibilities return)
824     case S_STOP: // from S_STOP -----------------------------------
825     {
826       switch(toState)
827       {
828         case S_PLAY: // to S_PLAY
829         {
830           startup = true;
831
832           audio->reset();
833           audio->setStreamType(Audio::MPEG2_PES);
834           audio->systemMuteOff();
835           video->reset();
836           demuxer->reset();
837           // FIXME use restartAtFrame here?
838           if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
839           demuxer->setFrameNum(currentFrameNumber);
840           demuxer->seek();
841           videoStartup = true;
842           state = S_PLAY;
843           threadStart();
844           logger->log("Player", Log::DEBUG, "Immediate play");
845           afeed.start();
846           vfeed.start();
847           tfeed.start();
848           subtitles->start();
849           video->sync();
850           audio->sync();
851           audio->play();
852           video->pause();
853           return;
854         }
855         case S_PAUSE_P: // to S_PAUSE_P
856         {
857           return;
858         }
859         case S_PAUSE_I: // to S_PAUSE_I
860         {
861           return;
862         }
863         case S_FFWD: // to S_FFWD
864         {
865           return;
866         }
867         case S_FBWD: // to S_FBWD
868         {
869           return;
870         }
871         case S_STOP: // to S_STOP
872         {
873           return;
874         }
875         case S_JUMP: // to S_JUMP
876         {
877           return;
878         }
879         case S_JUMP_PI: // to S_JUMP_PI
880         {
881           return;
882         }
883       }
884     }
885     // case S_JUMP cannot be a start state because it auto flips to play
886     // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
887   }
888 }
889
890 // ----------------------------------- Internal functions
891
892 void Player::lock()
893 {
894 #ifndef WIN32
895   pthread_mutex_lock(&mutex);
896   logger->log("Player", Log::DEBUG, "LOCKED");
897
898 #else
899    WaitForSingleObject(mutex, INFINITE);
900 #endif
901 }
902
903 void Player::unLock()
904 {
905 #ifndef WIN32
906   logger->log("Player", Log::DEBUG, "UNLOCKING");
907   pthread_mutex_unlock(&mutex);
908 #else
909    ReleaseMutex(mutex);
910 #endif
911 }
912
913 void Player::restartAtFrame(ULONG newFrame)
914 {
915   vfeed.stop();
916   afeed.stop();
917   tfeed.stop();
918   subtitles->stop();
919   threadStop();
920   video->stop();
921   video->reset();
922   audio->reset();
923   audio->setStreamType(Audio::MPEG2_PES);
924   demuxer->flush();
925   demuxer->seek();
926   currentFrameNumber = newFrame;
927   demuxer->setFrameNum(newFrame);
928   videoStartup = true;
929   afeed.start();
930   tfeed.start();
931   vfeed.start();
932   subtitles->start();
933   threadStart();
934   audio->play();
935   video->sync();
936   audio->sync();
937   audio->systemMuteOff();
938   audio->doMuting();
939 }
940
941
942 void Player::restartAtFramePI(ULONG newFrame)
943 {
944   ULLONG filePos;
945   ULONG nextiframeNumber;
946   ULONG iframeLength;
947   ULONG iframeNumber;
948
949   UCHAR* buffer;
950   UINT amountReceived;
951   UINT videoLength;
952
953   // newFrame could be anywhere, go forwards to next I-Frame
954   if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
955
956   // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
957   vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
958
959   buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
960   if (!vdr->isConnected())
961   {
962     if (buffer) free(buffer);
963     doConnectionLost();
964   }
965   else
966   {
967     videoLength = demuxer->stripAudio(buffer, amountReceived);
968     video->displayIFrame(buffer, videoLength);
969     video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
970     free(buffer);
971     currentFrameNumber = iframeNumber;
972   }
973 }
974
975 void Player::doConnectionLost()
976 {
977   logger->log("Player", Log::DEBUG, "Connection lost, sending message");
978   Message* m = new Message();
979   m->to = messageReceiver;
980   m->from = this;
981   m->message = Message::PLAYER_EVENT;
982   m->parameter = Player::CONNECTION_LOST;
983   messageQueue->postMessage(m);
984 }
985
986 // ----------------------------------- Callback
987
988 void Player::call(void* caller)
989 {
990   if (caller == demuxer)
991   {
992     logger->log("Player", Log::DEBUG, "Callback from demuxer");
993
994     if (video->getTVsize() == Video::ASPECT4X3)
995     {
996       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
997       return;
998     }
999
1000     int parx,pary;
1001     int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary);
1002     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
1003     {
1004       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
1005       video->setAspectRatio(Video::ASPECT4X3,parx,pary);
1006
1007       Message* m = new Message();
1008       m->from = this;
1009       m->to = messageReceiver;
1010       m->message = Message::PLAYER_EVENT;
1011       m->parameter = Player::ASPECT43;
1012       messageQueue->postMessage(m);
1013     }
1014     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
1015     {
1016       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
1017       video->setAspectRatio(Video::ASPECT16X9,parx,pary);
1018
1019       Message* m = new Message();
1020       m->from = this;
1021       m->to = messageReceiver;
1022       m->message = Message::PLAYER_EVENT;
1023       m->parameter = Player::ASPECT169;
1024       messageQueue->postMessage(m);
1025     }
1026     else
1027     {
1028       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... setting it anyway");
1029           video->setAspectRatio(static_cast<UCHAR>(dxCurrentAspect), parx, pary);
1030     }
1031
1032   }
1033   else
1034   {
1035     if (videoStartup)
1036     {
1037       videoStartup = false;
1038       video->reset();
1039       video->play();
1040       video->sync();
1041       vfeed.release();
1042       unLock();
1043     }
1044
1045     threadSignalNoLock();
1046   }
1047 }
1048
1049 // ----------------------------------- Feed thread
1050
1051 void Player::threadMethod()
1052 {
1053   // this method used to be simple, the only thing it does
1054   // is farm out to threadFeed Live/Play/Scan
1055   // All the guff is to support scan hitting one end
1056
1057   if ((state == S_FFWD) || (state == S_FBWD))
1058   {
1059     if (video->PTSIFramePlayback()) threadPTSFeedScan();
1060     else threadFeedScan();
1061     // if this returns then scan hit one end
1062     if (state == S_FFWD) // scan hit the end. stop
1063     {
1064       threadCheckExit();
1065       Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1066       m->to = messageReceiver;
1067       m->from = this;
1068       m->message = Message::PLAYER_EVENT;
1069       m->parameter = STOP_PLAYBACK;
1070       logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1071       messageQueue->postMessage(m);
1072       logger->log("Player", Log::DEBUG, "Message posted...");
1073       return;
1074     }
1075     // if execution gets to here, threadFeedScan hit the start, go to play mode
1076     state = S_PLAY;
1077     audio->reset();
1078     audio->setStreamType(Audio::MPEG2_PES);
1079     demuxer->flush();
1080     demuxer->seek();
1081     demuxer->setFrameNum(currentFrameNumber);
1082     videoStartup = true;
1083     afeed.start();
1084     tfeed.start();
1085     vfeed.start();
1086     subtitles->start();
1087     audio->play();
1088     audio->sync();
1089     audio->systemMuteOff();
1090     audio->doMuting();
1091   }
1092
1093   if (state == S_PLAY) threadFeedPlay();
1094 }
1095
1096 void Player::threadFeedPlay()
1097 {
1098   ULLONG feedPosition;
1099   UINT thisRead, writeLength, thisWrite, askFor;
1100   time_t lastRescan = time(NULL);
1101
1102   feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1103   if (!vdr->isConnected()) { doConnectionLost(); return; }
1104   logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1105
1106
1107   while(1)
1108   {
1109     thisRead = 0;
1110     writeLength = 0;
1111     thisWrite = 0;
1112
1113     threadCheckExit();
1114
1115     // If we havn't rescanned for a while..
1116     if ((lastRescan + 60) < time(NULL))
1117     {
1118       lengthBytes = vdr->rescanRecording(&lengthFrames);
1119       if (!vdr->isConnected()) { doConnectionLost(); return; }
1120       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1121       lastRescan = time(NULL);
1122     }
1123
1124     if (feedPosition >= lengthBytes) break;  // finished playback
1125
1126     if (startup)
1127     {
1128       if (startupBlockSize > lengthBytes)
1129         askFor = static_cast<UINT>(lengthBytes); // is a very small recording!
1130       else
1131         askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1132     }
1133     else
1134     {
1135       if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1136         askFor = static_cast<UINT>(lengthBytes - feedPosition);
1137       else // normal
1138         askFor = blockSize;
1139     }
1140     //logger->log("Player", Log::DEBUG, "Get Block in");
1141
1142     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1143     //logger->log("Player", Log::DEBUG, "Get Block out");
1144
1145     feedPosition += thisRead;
1146
1147     if (!vdr->isConnected())
1148     {
1149       doConnectionLost();
1150       return;
1151     }
1152
1153     if (!threadBuffer) break;
1154
1155     if (startup)
1156     {
1157       int a_stream = demuxer->scan(threadBuffer, thisRead);
1158       demuxer->setAudioStream(a_stream);
1159       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1160       startup = false;
1161     }
1162
1163     threadCheckExit();
1164
1165     while(writeLength < thisRead)
1166     {
1167       //logger->log("Player", Log::DEBUG, "Put in");
1168       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1169       //logger->log("Player", Log::DEBUG, "Put out");
1170       writeLength += thisWrite;
1171
1172       if (!thisWrite)
1173       {
1174         // demuxer is full and can't take anymore
1175         threadLock();
1176         if (!threadActive) { threadUnlock(); threadCheckExit(); }
1177         threadWaitForSignal();
1178         threadUnlock();
1179       }
1180
1181       threadCheckExit();
1182     }
1183
1184     free(threadBuffer);
1185     threadBuffer = NULL;
1186
1187   }
1188
1189   // end of recording
1190   logger->log("Player", Log::DEBUG, "Recording playback ends");
1191
1192   if (videoStartup) // oh woe. there never was a stream, I was conned!
1193   {
1194     videoStartup = false;
1195     unLock();
1196     MILLISLEEP(500); // I think this will solve a race
1197   }
1198
1199   threadCheckExit();
1200
1201
1202   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1203   m->to = messageReceiver;
1204   m->from = this;
1205   m->message = Message::PLAYER_EVENT;
1206   m->parameter = Player::STOP_PLAYBACK;
1207   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1208   messageQueue->postMessage(m);
1209 }
1210
1211
1212 void Player::threadPTSFeedScan()
1213 {
1214   // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?
1215
1216   ULONG direction = 0;
1217   int dir_fac=-1;
1218   ULONG baseFrameNumber = 0;
1219   ULONG iframeNumber = 0;
1220   ULONG iframeLength = 0;
1221   ULONG currentfeedFrameNumber=currentFrameNumber;
1222   ULONG firstFrameNumber=currentFrameNumber;
1223   ULLONG filePos;
1224   UINT amountReceived;
1225   UINT videoLength;
1226
1227   UINT playtime=0;
1228
1229   int frameTimeOffset = 0; // Time in msec between frames
1230
1231   if (state == S_FFWD)
1232   {
1233     direction = 1; // and 0 for backward
1234     dir_fac = 1;
1235   }
1236   video->EnterIframePlayback();
1237
1238   while(1)
1239   {
1240     baseFrameNumber = currentfeedFrameNumber;
1241
1242     threadCheckExit();
1243     if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1244        return;
1245
1246     if (iframeNumber >= lengthFrames) return;
1247         // scan has got to the end of what we knew to be there before we started scanning
1248
1249     baseFrameNumber = iframeNumber;
1250
1251     frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));
1252
1253     logger->log("Player", Log::DEBUG, "XXX Got frame");
1254
1255     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1256
1257     if (!vdr->isConnected())
1258     {
1259       if (threadBuffer) free(threadBuffer);
1260       doConnectionLost();
1261       break;
1262     }
1263
1264
1265     threadCheckExit();
1266
1267
1268     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1269     demuxer->changeTimes(threadBuffer,videoLength,playtime);
1270     int count=0;
1271     while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block
1272     {
1273         MILLISLEEP(20);
1274         threadCheckExit();
1275         count++;
1276         if (count%300==0) {
1277                 ULLONG cur_time=video->getCurrentTimestamp();
1278         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1279                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1280                 if (cur_time!=0) {
1281                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1282                 }
1283         }
1284
1285     }
1286     playtime +=frameTimeOffset;
1287     currentfeedFrameNumber = iframeNumber;
1288     {
1289                 ULLONG cur_time=video->getCurrentTimestamp();
1290         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1291                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1292                 if (cur_time!=0) {
1293                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1294                 }
1295         }
1296
1297     free(threadBuffer);
1298     threadBuffer = NULL;
1299   }
1300 }
1301
1302
1303
1304 void Player::threadFeedScan()
1305 {
1306   // This method is actually really simple - get frame from vdr,
1307   // spit it at the video chip, wait for a time. Most of the code here
1308   // is to get the wait right so that the scan occurs at the correct rate.
1309
1310   ULONG direction = 0;
1311   ULONG baseFrameNumber = 0;
1312   ULONG iframeNumber = 0;
1313   ULONG iframeLength = 0;
1314   ULLONG filePos;
1315   UINT amountReceived;
1316   UINT videoLength;
1317
1318 #ifndef WIN32
1319   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1320   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1321   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1322 #else
1323   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1324 #endif
1325
1326   int frameTimeOffset = 0; // Time in msec between frames
1327   int disp_msec = 0;  // Time taken to display data
1328   int total_msec = 0; // Time taken to fetch data and display it
1329   int sleepTime = 0;
1330
1331   if (state == S_FFWD) direction = 1; // and 0 for backward
1332
1333   while(1)
1334   {
1335     // Fetch I-frames until we get one that can be displayed in good time
1336     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1337
1338     baseFrameNumber = currentFrameNumber;
1339     do
1340     {
1341       threadCheckExit();
1342       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1343         return;
1344
1345       if (iframeNumber >= lengthFrames) return;
1346         // scan has got to the end of what we knew to be there before we started scanning
1347
1348       baseFrameNumber = iframeNumber;
1349       frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
1350 #ifndef WIN32
1351       gettimeofday(&clock0, NULL);
1352 #else
1353       clock0 = timeGetTime();
1354 #endif
1355     }
1356 #ifndef WIN32
1357     while (clock2.tv_sec != 0 &&
1358           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1359           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1360 #else
1361     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1362 #endif
1363     logger->log("Player", Log::DEBUG, "XXX Got frame");
1364
1365     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1366
1367     if (!vdr->isConnected() || !amountReceived)
1368     {
1369       if (threadBuffer) free(threadBuffer);
1370       doConnectionLost();
1371       break;
1372     }
1373     
1374 #ifndef WIN32
1375     gettimeofday(&clock1, NULL);
1376     if (clock2.tv_sec != 0)
1377       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1378                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1379                 + frameTimeOffset - disp_msec;
1380 #else
1381     clock1 = timeGetTime();
1382     if (clock2 != 0)
1383       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1384 #endif
1385     if (sleepTime < 0) sleepTime = 0;
1386     threadCheckExit();
1387     MILLISLEEP(sleepTime);
1388    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1389
1390     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1391     video->displayIFrame(threadBuffer, videoLength);
1392     currentFrameNumber = iframeNumber;
1393     free(threadBuffer);
1394     threadBuffer = NULL;
1395
1396 #ifndef WIN32
1397     gettimeofday(&clock2, NULL);
1398     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1399                + (clock2.tv_usec - clock0.tv_usec) / 1000
1400                - sleepTime;
1401     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1402               + (clock2.tv_usec - clock1.tv_usec) / 1000
1403               - sleepTime;
1404 #else
1405     clock2 = timeGetTime();
1406     total_msec = clock2 - clock0 - sleepTime;
1407     disp_msec = clock2 - clock1 - sleepTime;
1408 #endif
1409     logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1410   }
1411 }
1412
1413 void Player::threadPostStopCleanup()
1414 {
1415   if (threadBuffer)
1416   {
1417     free(threadBuffer);
1418     threadBuffer = NULL;
1419   }
1420 }
1421
1422 // ----------------------------------- Dev
1423
1424 #ifdef DEV
1425 void Player::test1()
1426 {
1427   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1428 }
1429
1430 void Player::test2()
1431 {
1432   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1433 }
1434 #endif