]> git.vomp.tv Git - vompclient.git/blob - player.cc
More compiler warning fixes
[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, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "player.h"
22
23 #include "log.h"
24 #include "audio.h"
25 #include "video.h"
26 #include "demuxervdr.h"
27 #include "demuxerts.h"
28 #include "vdr.h"
29 #include "messagequeue.h"
30 #include "remote.h"
31 #include "message.h"
32 #include "dvbsubtitles.h"
33 #include "osdreceiver.h"
34
35 #define USER_RESPONSE_TIME 500 // Milliseconds
36
37 // ----------------------------------- Called from outside, one offs or info funcs
38
39 Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver)
40 : vfeed(this), afeed(this), tfeed(this)
41 {
42   messageQueue = tmessageQueue;
43   messageReceiver = tmessageReceiver;
44   osdReceiver = tosdReceiver;
45   audio = Audio::getInstance();
46   video = Video::getInstance();
47   logger = Log::getInstance();
48   vdr = VDR::getInstance();
49   initted = false;
50   lengthBytes = 0;
51   lengthFrames = 0;
52   currentFrameNumber = 0;
53   state = S_STOP;
54   ifactor = 4;
55   is_pesrecording=true;
56
57   subtitlesShowing = false;
58
59   videoStartup = false;
60   threadBuffer = NULL;
61  
62   blockSize = 100000;
63   startupBlockSize = 250000;
64   video->turnVideoOn();
65 }
66
67 Player::~Player()
68 {
69   if (initted) shutdown();
70 }
71
72 int Player::init(bool p_isPesRecording,double framespersecond)
73 {
74   if (initted) return 0;
75 #ifndef WIN32
76   pthread_mutex_init(&mutex, NULL);
77 #else
78   mutex=CreateMutex(NULL,FALSE,NULL);
79 #endif
80   is_pesrecording = p_isPesRecording;
81   fps=framespersecond;
82   if (is_pesrecording)
83     demuxer = new DemuxerVDR();
84   else
85     demuxer = new DemuxerTS();
86   if (!demuxer) return 0;
87   subtitles = new DVBSubtitles(osdReceiver);
88   if (!subtitles) return 0;
89
90   teletext = new TeletextDecoderVBIEBU();
91   if (!teletext) return 0;
92   teletext->setRecordigMode(true);
93   unsigned int demux_video_size=2097152;
94   unsigned int demux_audio_size=524288;
95   if (video->supportsh264()) {
96           demux_video_size*=5*2;//5;
97
98   }
99   if (audio->maysupportAc3()) {
100           //demux_audio_size*=2;
101   }
102  
103   if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,65536, framespersecond, subtitles))
104   {
105     logger->log("Player", Log::ERR, "Demuxer failed to init");
106     shutdown();
107     return 0;
108   }
109
110   vfeed.init();
111   afeed.init();
112   tfeed.init();
113
114   video->stop();
115   video->blank();
116   audio->stop();
117
118   if (Command::getInstance()->getSubDefault()) {
119           turnSubtitlesOn(true);
120   } else {
121           turnSubtitlesOn(false);
122   }
123
124   initted = true;
125   return 1;
126 }
127
128 int Player::shutdown()
129 {
130   if (!initted) return 0;
131   switchState(S_STOP);
132   initted = false;
133
134   delete demuxer;
135   demuxer = NULL;
136   delete subtitles;
137   subtitles = NULL;
138   delete teletext;
139   teletext = NULL;
140
141 #ifdef WIN32
142   CloseHandle(mutex);
143 #endif
144
145   return 1;
146 }
147
148 void Player::setStartFrame(ULONG startFrame)
149 {
150         ULONG nextiframeNumber;
151         ULONG iframeLength;
152         ULONG iframeNumber;
153         ULLONG filePos;
154
155         // newFrame could be anywhere, go forwards to next I-Frame
156         if (!vdr->getNextIFrame(startFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
157
158         // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
159         vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
160
161           logger->log("Player", Log::DEBUG, "setStartFrame %lu %lu %lu", startFrame, nextiframeNumber,iframeNumber);
162         currentFrameNumber = iframeNumber;
163
164 }
165
166 void Player::setLengthBytes(ULLONG length)
167 {
168   lengthBytes = length;
169   logger->log("Player", Log::DEBUG, "Player has received length bytes of %llu", lengthBytes);
170 }
171
172 void Player::setLengthFrames(ULONG length)
173 {
174   lengthFrames = length;
175   logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames);
176 }
177
178 ULONG Player::getLengthFrames()
179 {
180   return lengthFrames;
181 }
182
183 ULONG Player::getCurrentFrameNum()
184 {
185   if (startup) return 0;
186   switch(state)
187   {
188     case S_PLAY:
189     case S_PAUSE_P:
190       return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp());
191     case S_PAUSE_I:
192     case S_FFWD:
193     case S_FBWD:
194       return currentFrameNumber;
195     default:
196       return 0; // shouldn't happen
197   }
198 }
199
200 bool* Player::getDemuxerMpegAudioChannels()
201 {
202   return demuxer->getmpAudioChannels();
203 }
204
205 bool* Player::getDemuxerAc3AudioChannels()
206 {
207   return demuxer->getac3AudioChannels();
208 }
209
210 bool* Player::getDemuxerSubtitleChannels()
211 {
212   return demuxer->getSubtitleChannels();
213 }
214
215 int Player::getCurrentAudioChannel()
216 {
217     if (is_pesrecording) {
218         return demuxer->getselAudioChannel();
219     } else {
220         return ((DemuxerTS*)demuxer)->getAID();
221     }
222 }
223
224 int Player::getCurrentSubtitleChannel()
225 {
226     if (is_pesrecording) {
227         return demuxer->getselSubtitleChannel();
228     } else {
229         return ((DemuxerTS*)demuxer)->getSubID();
230     }
231 }
232
233 void Player::setSubtitleChannel(int newChannel)
234 {
235     if (is_pesrecording) {
236          demuxer->setDVBSubtitleStream(newChannel);
237     } else {
238         ((DemuxerTS*)demuxer)->setSubID(newChannel);
239     }
240 }
241
242 int *Player::getTeletxtSubtitlePages()
243 {
244     return teletext->getSubtitlePages();
245 }
246
247 void Player::setAudioChannel(int newChannel, int type, int streamtype)
248 {
249     if (is_pesrecording) {
250         demuxer->setAudioStream(newChannel);
251         return;
252     } else {
253         ((DemuxerTS*)demuxer)->setAID(newChannel,type,streamtype,false);
254         return;
255     }
256 }
257
258 bool Player::toggleSubtitles()
259 {
260   if (!subtitlesShowing)
261   {
262     subtitlesShowing = true;
263     subtitles->show();
264   }
265   else
266   {
267     subtitlesShowing = false;
268     subtitles->hide();
269   }
270   return subtitlesShowing;
271 }
272
273 void  Player::turnSubtitlesOn(bool ison) {
274  if (ison)
275   {
276     subtitlesShowing = true;
277     subtitles->show();
278   }
279   else
280   {
281     subtitlesShowing = false;
282     subtitles->hide();
283   }
284
285 }
286
287 void Player::tellSubtitlesOSDVisible(bool visible){
288 subtitles->setOSDMenuVisibility(visible);
289 }
290
291 Channel * Player::getDemuxerChannel() {
292     if (!is_pesrecording) {
293         return ((DemuxerTS*) demuxer)->getChannelInfo();
294     } 
295     return NULL; //Should not happen!
296 }
297
298
299 // ----------------------------------- Externally called events
300
301 void Player::play()
302 {
303   if (!initted) return;
304   if (state == S_PLAY) return;
305   lock();
306
307   bool doUnlock = false;
308   if (state == S_PAUSE_P) doUnlock = true;
309   switchState(S_PLAY);
310   if (doUnlock) unLock();
311 }
312
313 void Player::playpause()
314 {
315   if (!initted) return;
316   lock();
317
318   bool doUnlock = false;
319   if (state==S_PLAY) {
320           doUnlock=true;
321           switchState(S_PAUSE_P);
322   } else {
323           if (state == S_PAUSE_P) doUnlock = true;
324           switchState(S_PLAY);
325   }
326   if (doUnlock) unLock();
327
328 }
329
330
331
332
333 void Player::stop()
334 {
335   if (!initted) return;
336   if (state == S_STOP) return;
337   lock();
338   logger->log("Player", Log::DEBUG, "Stop called lock");
339   switchState(S_STOP);
340   unLock();
341 }
342
343 void Player::pause()
344 {
345   if (!initted) return;
346   lock();
347
348   if ((state == S_FFWD) || (state == S_FBWD))
349   {
350     switchState(S_PAUSE_I);
351   }
352   else if ((state == S_PAUSE_I) || (state == S_PAUSE_P))
353   {
354     switchState(S_PLAY);
355   }
356   else
357   {
358     switchState(S_PAUSE_P);
359   }
360
361   unLock();
362 }
363
364 void Player::fastForward()
365 {
366   if (!initted) return;
367   lock();
368
369   if (state == S_FFWD)
370   {
371     // change the rate
372     switch(ifactor)
373     {
374       case 4: ifactor = 8; break;
375       case 8: ifactor = 16; break;
376       case 16: ifactor = 32; break;
377       case 32: ifactor = 4; break;
378     }
379   }
380   else
381   {
382     ifactor = 4;
383     switchState(S_FFWD);
384   }
385   unLock();
386 }
387
388 void Player::fastBackward()
389 {
390   if (!initted) return;
391   lock();
392
393   if (state == S_FBWD)
394   {
395     // change the rate
396     switch(ifactor)
397     {
398       case 4: ifactor = 8; break;
399       case 8: ifactor = 16; break;
400       case 16: ifactor = 32; break;
401       case 32: ifactor = 4; break;
402     }
403   }
404   else
405   {
406     ifactor = 4;
407     switchState(S_FBWD);
408   }
409   unLock();
410 }
411
412 void Player::jumpToPercent(double percent)
413 {
414   lock();
415   logger->log("Player", Log::DEBUG, "JUMP TO %f%%", percent);
416   ULONG newFrame = (ULONG)(percent * lengthFrames / 100);
417   switchState(S_JUMP, newFrame);
418 //  unLock(); - let thread unlock this
419 }
420
421 void Player::jumpToMark(int mark)
422 {
423   lock();
424   logger->log("Player", Log::DEBUG, "JUMP TO MARK %i%%", mark);
425   switchState(S_JUMP, mark);
426 //  unLock(); - let thread unlock this
427 }
428
429 void Player::jumpToFrameP(int newFrame)
430 {
431   lock();
432   logger->log("Player", Log::DEBUG, "JUMP TO FRAME AND PAUSE %i", newFrame);
433   switchState(S_JUMP_PI, newFrame);
434   unLock();
435 }
436
437 void Player::skipForward(int seconds)
438 {
439   lock();
440   logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
441   ULONG newFrame = getCurrentFrameNum();
442   if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
443   newFrame +=(ULONG) (((double)seconds) * fps);
444   if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
445   else switchState(S_JUMP, newFrame);
446 //  unLock(); - let thread unlock this
447 }
448
449 void Player::skipBackward(int seconds)
450 {
451   lock();
452   logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
453   long newFrame = getCurrentFrameNum();
454   if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
455   newFrame -= (ULONG) (((double)seconds) * fps);
456   if (newFrame < 0) newFrame = 0;
457   switchState(S_JUMP, newFrame);
458 //  unLock(); - let thread unlock this
459 }
460
461 // ----------------------------------- Implementations called events
462
463 void Player::switchState(UCHAR toState, ULONG jumpFrame)
464 {
465   if (!initted) return;
466
467   logger->log("Player", Log::DEBUG, "Switch state from %u to %u", state, toState);
468
469   switch(state) // current state selector
470   {
471     case S_PLAY: // from S_PLAY -----------------------------------
472     {
473       switch(toState)
474       {
475         case S_PLAY: // to S_PLAY
476         {
477           return;
478         }
479         case S_PAUSE_P: // to S_PAUSE_P
480         {
481           video->pause();
482           audio->pause();
483           state = S_PAUSE_P;
484           return;
485         }
486         case S_PAUSE_I: // to S_PAUSE_I
487         {
488           // can't occur
489           return;
490         }
491         case S_FFWD: // to S_FFWD
492         {
493           currentFrameNumber = getCurrentFrameNum();
494           audio->systemMuteOn();
495           threadStop();
496           vfeed.stop();
497           afeed.stop();
498           tfeed.stop();
499           subtitles->stop();
500           demuxer->flush();
501           state = S_FFWD;
502           threadStart();
503           return;
504         }
505         case S_FBWD: // to S_FBWD
506         {
507           currentFrameNumber = getCurrentFrameNum();
508           audio->systemMuteOn();
509           threadStop();
510           vfeed.stop();
511           afeed.stop();
512           tfeed.stop();
513           subtitles->stop();
514           demuxer->flush();
515           state = S_FBWD;
516           threadStart();
517           return;
518         }
519         case S_STOP: // to S_STOP
520         {
521           vfeed.stop();
522           afeed.stop();
523           tfeed.stop();
524           subtitles->stop();
525           threadStop();
526           video->stop();
527           video->blank();
528           audio->stop();
529           audio->unPause();
530           video->reset();
531           demuxer->reset();
532           state = S_STOP;
533           return;
534         }
535         case S_JUMP: // to S_JUMP
536         {
537           restartAtFrame(jumpFrame);
538           return;
539         }
540         case S_JUMP_PI: // to S_JUMP_PI
541         {
542           audio->systemMuteOn();
543           threadStop();
544           vfeed.stop();
545           afeed.stop();
546           tfeed.stop();
547           subtitles->stop();
548           demuxer->flush();
549           state = S_PAUSE_I;
550           video->reset();
551           video->play();
552           restartAtFramePI(jumpFrame);
553           return;
554         }
555       }
556     }
557     case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
558     {
559       switch(toState)
560       {
561         case S_PLAY: // to S_PLAY
562         {
563           video->unPause();
564           audio->unPause();
565           state = S_PLAY;
566           return;
567         }
568         case S_PAUSE_P: // to S_PAUSE_P
569         {
570           return;
571         }
572         case S_PAUSE_I: // to S_PAUSE_I
573         {
574           return;
575         }
576         case S_FFWD: // to S_FFWD
577         {
578           currentFrameNumber = getCurrentFrameNum();
579           audio->systemMuteOn();
580           vfeed.stop();
581           afeed.stop();
582           tfeed.stop();
583           subtitles->stop();
584           threadStop();
585           video->unPause();
586           audio->unPause();
587           state = S_FFWD;
588           threadStart();
589           return;
590         }
591         case S_FBWD: // to S_FBWD
592         {
593           currentFrameNumber = getCurrentFrameNum();
594           audio->systemMuteOn();
595           vfeed.stop();
596           afeed.stop();
597           tfeed.stop();
598           subtitles->stop();
599           threadStop();
600           video->unPause();
601           audio->unPause();
602           state = S_FBWD;
603           threadStart();
604           return;
605         }
606         case S_STOP: // to S_STOP
607         {
608           vfeed.stop();
609           afeed.stop();
610           tfeed.stop();
611           subtitles->stop();
612           threadStop();
613           video->stop();
614           video->blank();
615           audio->stop();
616           video->reset();
617           audio->unPause();
618           demuxer->reset();
619           audio->systemMuteOff();
620           state = S_STOP;
621           return;
622         }
623         case S_JUMP: // to S_JUMP
624         {
625           state = S_PLAY;
626           audio->systemMuteOn();
627           audio->unPause();
628           restartAtFrame(jumpFrame);
629           return;
630         }
631         case S_JUMP_PI: // to S_JUMP_PI
632         {
633           audio->systemMuteOn();
634           audio->unPause();
635           threadStop();
636           vfeed.stop();
637           afeed.stop();
638           tfeed.stop();
639           subtitles->stop();
640           demuxer->flush();
641           state = S_PAUSE_I;
642           video->reset();
643           video->play();
644           restartAtFramePI(jumpFrame);
645           return;
646         }
647       }
648     }
649     case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
650     {
651       switch(toState)
652       {
653         case S_PLAY: // to S_PLAY
654         {
655           state = S_PLAY;
656           restartAtFrame(currentFrameNumber);
657           return;
658         }
659         case S_PAUSE_P: // to S_PAUSE_P
660         {
661           return;
662         }
663         case S_PAUSE_I: // to S_PAUSE_I
664         {
665           return;
666         }
667         case S_FFWD: // to S_FFWD
668         {
669           state = S_FFWD;
670           threadStart();
671           return;
672         }
673         case S_FBWD: // to S_FBWD
674         {
675           state = S_FBWD;
676           threadStart();
677           return;
678         }
679         case S_STOP: // to S_STOP
680         {
681           video->stop();
682           video->blank();
683           audio->stop();
684           video->reset();
685           demuxer->reset();
686           audio->systemMuteOff();
687           state = S_STOP;
688           return;
689         }
690         case S_JUMP: // to S_JUMP
691         {
692           state = S_PLAY;
693           restartAtFrame(jumpFrame);
694           return;
695         }
696         case S_JUMP_PI: // to S_JUMP_PI
697         {
698           restartAtFramePI(jumpFrame);
699           return;
700         }
701       }
702     }
703     case S_FFWD: // from S_FFWD -----------------------------------
704     {
705       switch(toState)
706       {
707         case S_PLAY: // to S_PLAY
708         {
709           state = S_PLAY;
710           ULONG stepback = (ULONG)(((double)USER_RESPONSE_TIME * ifactor) * fps / 1000.);
711           if (stepback < currentFrameNumber)
712             currentFrameNumber -= stepback;
713           else
714             currentFrameNumber = 0;
715           restartAtFrame(currentFrameNumber);
716           return;
717         }
718         case S_PAUSE_P: // to S_PAUSE_P
719         {
720           // can't occur
721           return;
722         }
723         case S_PAUSE_I: // to S_PAUSE_I
724         {
725           threadStop();
726           state = S_PAUSE_I;
727           return;
728         }
729         case S_FFWD: // to S_FFWD
730         {
731           return;
732         }
733         case S_FBWD: // to S_FBWD
734         {
735           threadStop();
736           state = S_FBWD;
737           threadStart();
738           return;
739         }
740         case S_STOP: // to S_STOP
741         {
742           threadStop();
743           video->stop();
744           video->blank();
745           audio->stop();
746           video->reset();
747           demuxer->reset();
748           state = S_STOP;
749           return;
750         }
751         case S_JUMP: // to S_JUMP
752         {
753           state = S_PLAY;
754           restartAtFrame(jumpFrame);
755           return;
756         }
757         case S_JUMP_PI: // to S_JUMP_PI
758         {
759           threadStop();
760           state = S_PAUSE_I;
761           restartAtFramePI(jumpFrame);
762           return;
763         }
764       }
765     }
766     case S_FBWD: // from S_FBWD -----------------------------------
767     {
768       switch(toState)
769       {
770         case S_PLAY: // to S_PLAY
771         {
772           state = S_PLAY;
773           restartAtFrame(currentFrameNumber);
774           return;
775         }
776         case S_PAUSE_P: // to S_PAUSE_P
777         {
778           // can't occur
779           return;
780         }
781         case S_PAUSE_I: // to S_PAUSE_I
782         {
783           threadStop();
784           state = S_PAUSE_I;
785           return;
786         }
787         case S_FFWD: // to S_FFWD
788         {
789           threadStop();
790           state = S_FFWD;
791           threadStart();
792           return;
793         }
794         case S_FBWD: // to S_FBWD
795         {
796           return;
797         }
798         case S_STOP: // to S_STOP
799         {
800           threadStop();
801           video->stop();
802           video->blank();
803           audio->stop();
804           video->reset();
805           demuxer->reset();
806           state = S_STOP;
807           return;
808         }
809         case S_JUMP: // to S_JUMP
810         {
811           state = S_PLAY;
812           restartAtFrame(jumpFrame);
813           return;
814         }
815         case S_JUMP_PI: // to S_JUMP_PI
816         {
817           threadStop();
818           state = S_PAUSE_I;
819           restartAtFramePI(jumpFrame);
820           return;
821         }
822       }
823     }
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.num = 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.num = Player::ASPECT43;
1012       messageQueue->postMessageFromOuterSpace(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.num = Player::ASPECT169;
1024       messageQueue->postMessageFromOuterSpace(m);
1025     }
1026     else
1027     {
1028       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... setting it anyway");
1029           video->setAspectRatio(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.num = 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 = 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 = 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         threadWaitForSignal();
1177         threadUnlock();
1178       }
1179
1180       threadCheckExit();
1181     }
1182
1183     free(threadBuffer);
1184     threadBuffer = NULL;
1185
1186   }
1187
1188   // end of recording
1189   logger->log("Player", Log::DEBUG, "Recording playback ends");
1190
1191   if (videoStartup) // oh woe. there never was a stream, I was conned!
1192   {
1193     videoStartup = false;
1194     unLock();
1195     MILLISLEEP(500); // I think this will solve a race
1196   }
1197
1198   threadCheckExit();
1199
1200
1201   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1202   m->to = messageReceiver;
1203   m->from = this;
1204   m->message = Message::PLAYER_EVENT;
1205   m->parameter.num = Player::STOP_PLAYBACK;
1206   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1207   messageQueue->postMessage(m);
1208 }
1209
1210
1211 void Player::threadPTSFeedScan()
1212 {
1213   // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?
1214
1215   ULONG direction = 0;
1216   int dir_fac=-1;
1217   ULONG baseFrameNumber = 0;
1218   ULONG iframeNumber = 0;
1219   ULONG iframeLength = 0;
1220   ULONG currentfeedFrameNumber=currentFrameNumber;
1221   ULONG firstFrameNumber=currentFrameNumber;
1222   ULLONG filePos;
1223   UINT amountReceived;
1224   UINT videoLength;
1225
1226   UINT playtime=0;
1227
1228   int frameTimeOffset = 0; // Time in msec between frames
1229
1230   if (state == S_FFWD)
1231   {
1232     direction = 1; // and 0 for backward
1233     dir_fac = 1;
1234   }
1235   video->EnterIframePlayback();
1236
1237   while(1)
1238   {
1239     baseFrameNumber = currentfeedFrameNumber;
1240
1241     threadCheckExit();
1242     if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1243        return;
1244
1245     if (iframeNumber >= lengthFrames) return;
1246         // scan has got to the end of what we knew to be there before we started scanning
1247
1248     baseFrameNumber = iframeNumber;
1249
1250     frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));
1251
1252     logger->log("Player", Log::DEBUG, "XXX Got frame");
1253
1254     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1255
1256     if (!vdr->isConnected())
1257     {
1258       if (threadBuffer) free(threadBuffer);
1259       doConnectionLost();
1260       break;
1261     }
1262
1263
1264     threadCheckExit();
1265
1266
1267     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1268     demuxer->changeTimes(threadBuffer,videoLength,playtime);
1269     int count=0;
1270     while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block
1271     {
1272         MILLISLEEP(20);
1273         threadCheckExit();
1274         count++;
1275         if (count%300==0) {
1276                 ULLONG cur_time=video->getCurrentTimestamp();
1277         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1278                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1279                 if (cur_time!=0) {
1280                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1281                 }
1282         }
1283
1284     }
1285     playtime +=frameTimeOffset;
1286     currentfeedFrameNumber = iframeNumber;
1287     {
1288                 ULLONG cur_time=video->getCurrentTimestamp();
1289         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1290                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1291                 if (cur_time!=0) {
1292                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1293                 }
1294         }
1295
1296     free(threadBuffer);
1297     threadBuffer = NULL;
1298   }
1299 }
1300
1301
1302
1303 void Player::threadFeedScan()
1304 {
1305   // This method is actually really simple - get frame from vdr,
1306   // spit it at the video chip, wait for a time. Most of the code here
1307   // is to get the wait right so that the scan occurs at the correct rate.
1308
1309   ULONG direction = 0;
1310   ULONG baseFrameNumber = 0;
1311   ULONG iframeNumber = 0;
1312   ULONG iframeLength = 0;
1313   ULLONG filePos;
1314   UINT amountReceived;
1315   UINT videoLength;
1316
1317 #ifndef WIN32
1318   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1319   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1320   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1321 #else
1322   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1323 #endif
1324
1325   int frameTimeOffset = 0; // Time in msec between frames
1326   int disp_msec = 0;  // Time taken to display data
1327   int total_msec = 0; // Time taken to fetch data and display it
1328   int sleepTime = 0;
1329
1330   if (state == S_FFWD) direction = 1; // and 0 for backward
1331
1332   while(1)
1333   {
1334     // Fetch I-frames until we get one that can be displayed in good time
1335     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1336
1337     baseFrameNumber = currentFrameNumber;
1338     do
1339     {
1340       threadCheckExit();
1341       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1342         return;
1343
1344       if (iframeNumber >= lengthFrames) return;
1345         // scan has got to the end of what we knew to be there before we started scanning
1346
1347       baseFrameNumber = iframeNumber;
1348       frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
1349 #ifndef WIN32
1350       gettimeofday(&clock0, NULL);
1351 #else
1352       clock0 = timeGetTime();
1353 #endif
1354     }
1355 #ifndef WIN32
1356     while (clock2.tv_sec != 0 &&
1357           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1358           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1359 #else
1360     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1361 #endif
1362     logger->log("Player", Log::DEBUG, "XXX Got frame");
1363
1364     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1365
1366     if (!vdr->isConnected() || !amountReceived)
1367     {
1368       if (threadBuffer) free(threadBuffer);
1369       doConnectionLost();
1370       break;
1371     }
1372     
1373 #ifndef WIN32
1374     gettimeofday(&clock1, NULL);
1375     if (clock2.tv_sec != 0)
1376       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1377                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1378                 + frameTimeOffset - disp_msec;
1379 #else
1380     clock1 = timeGetTime();
1381     if (clock2 != 0)
1382       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1383 #endif
1384     if (sleepTime < 0) sleepTime = 0;
1385     threadCheckExit();
1386     MILLISLEEP(sleepTime);
1387    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1388
1389     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1390     video->displayIFrame(threadBuffer, videoLength);
1391     currentFrameNumber = iframeNumber;
1392     free(threadBuffer);
1393     threadBuffer = NULL;
1394
1395 #ifndef WIN32
1396     gettimeofday(&clock2, NULL);
1397     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1398                + (clock2.tv_usec - clock0.tv_usec) / 1000
1399                - sleepTime;
1400     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1401               + (clock2.tv_usec - clock1.tv_usec) / 1000
1402               - sleepTime;
1403 #else
1404     clock2 = timeGetTime();
1405     total_msec = clock2 - clock0 - sleepTime;
1406     disp_msec = clock2 - clock1 - sleepTime;
1407 #endif
1408     logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1409   }
1410 }
1411
1412 void Player::threadPostStopCleanup()
1413 {
1414   if (threadBuffer)
1415   {
1416     free(threadBuffer);
1417     threadBuffer = NULL;
1418   }
1419 }
1420
1421 // ----------------------------------- Dev
1422
1423 #ifdef DEV
1424 void Player::test1()
1425 {
1426   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1427 }
1428
1429 void Player::test2()
1430 {
1431   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1432 }
1433 #endif