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