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