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