]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
Let vomp handle aspect ratio change, better aspect ratio control for HD and SD
[vompclient-marten.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 parx,pary;
978     int dxCurrentAspect = demuxer->getAspectRatio(&parx,&pary);
979     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
980     {
981       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
982       video->setAspectRatio(Video::ASPECT4X3,parx,pary);
983
984       Message* m = new Message();
985       m->from = this;
986       m->to = messageReceiver;
987       m->message = Message::PLAYER_EVENT;
988       m->parameter = Player::ASPECT43;
989       messageQueue->postMessageFromOuterSpace(m);
990     }
991     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
992     {
993       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
994       video->setAspectRatio(Video::ASPECT16X9,parx,pary);
995
996       Message* m = new Message();
997       m->from = this;
998       m->to = messageReceiver;
999       m->message = Message::PLAYER_EVENT;
1000       m->parameter = Player::ASPECT169;
1001       messageQueue->postMessageFromOuterSpace(m);
1002     }
1003     else
1004     {
1005       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... setting it anyway");
1006           video->setAspectRatio(dxCurrentAspect,parx,pary);
1007     }
1008
1009   }
1010   else
1011   {
1012     if (videoStartup)
1013     {
1014       videoStartup = false;
1015       video->reset();
1016       video->play();
1017       video->sync();
1018       vfeed.release();
1019       unLock();
1020     }
1021
1022     threadSignalNoLock();
1023   }
1024 }
1025
1026 // ----------------------------------- Feed thread
1027
1028 void Player::threadMethod()
1029 {
1030   // this method used to be simple, the only thing it does
1031   // is farm out to threadFeed Live/Play/Scan
1032   // All the guff is to support scan hitting one end
1033
1034   if ((state == S_FFWD) || (state == S_FBWD))
1035   {
1036     if (video->PTSIFramePlayback()) threadPTSFeedScan();
1037     else threadFeedScan();
1038     // if this returns then scan hit one end
1039     if (state == S_FFWD) // scan hit the end. stop
1040     {
1041       threadCheckExit();
1042       Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1043       m->to = messageReceiver;
1044       m->from = this;
1045       m->message = Message::PLAYER_EVENT;
1046       m->parameter = STOP_PLAYBACK;
1047       logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1048       messageQueue->postMessage(m);
1049       logger->log("Player", Log::DEBUG, "Message posted...");
1050       return;
1051     }
1052     // if execution gets to here, threadFeedScan hit the start, go to play mode
1053     state = S_PLAY;
1054     audio->reset();
1055     audio->setStreamType(Audio::MPEG2_PES);
1056     demuxer->flush();
1057     demuxer->seek();
1058     demuxer->setFrameNum(currentFrameNumber);
1059     videoStartup = true;
1060     afeed.start();
1061     tfeed.start();
1062     vfeed.start();
1063     subtitles->start();
1064     audio->play();
1065     audio->sync();
1066     audio->systemMuteOff();
1067     audio->doMuting();
1068   }
1069
1070   if (state == S_PLAY) threadFeedPlay();
1071 }
1072
1073 void Player::threadFeedPlay()
1074 {
1075   ULLONG feedPosition;
1076   UINT thisRead, writeLength, thisWrite, askFor;
1077   time_t lastRescan = time(NULL);
1078
1079   feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1080   if (!vdr->isConnected()) { doConnectionLost(); return; }
1081   logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1082
1083
1084   while(1)
1085   {
1086     thisRead = 0;
1087     writeLength = 0;
1088     thisWrite = 0;
1089
1090     threadCheckExit();
1091
1092     // If we havn't rescanned for a while..
1093     if ((lastRescan + 60) < time(NULL))
1094     {
1095       lengthBytes = vdr->rescanRecording(&lengthFrames);
1096       if (!vdr->isConnected()) { doConnectionLost(); return; }
1097       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1098       lastRescan = time(NULL);
1099     }
1100
1101     if (feedPosition >= lengthBytes) break;  // finished playback
1102
1103     if (startup)
1104     {
1105       if (startupBlockSize > lengthBytes)
1106         askFor = lengthBytes; // is a very small recording!
1107       else
1108         askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1109     }
1110     else
1111     {
1112       if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1113         askFor = lengthBytes - feedPosition;
1114       else // normal
1115         askFor = blockSize;
1116     }
1117     //logger->log("Player", Log::DEBUG, "Get Block in");
1118
1119     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1120     //logger->log("Player", Log::DEBUG, "Get Block out");
1121
1122     feedPosition += thisRead;
1123
1124     if (!vdr->isConnected())
1125     {
1126       doConnectionLost();
1127       return;
1128     }
1129
1130     if (!threadBuffer) break;
1131
1132     if (startup)
1133     {
1134       int a_stream = demuxer->scan(threadBuffer, thisRead);
1135       demuxer->setAudioStream(a_stream);
1136       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1137       startup = false;
1138     }
1139
1140     threadCheckExit();
1141
1142     while(writeLength < thisRead)
1143     {
1144       //logger->log("Player", Log::DEBUG, "Put in");
1145       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1146       //logger->log("Player", Log::DEBUG, "Put out");
1147       writeLength += thisWrite;
1148
1149       if (!thisWrite)
1150       {
1151         // demuxer is full and can't take anymore
1152         threadLock();
1153         threadWaitForSignal();
1154         threadUnlock();
1155       }
1156
1157       threadCheckExit();
1158     }
1159
1160     free(threadBuffer);
1161     threadBuffer = NULL;
1162
1163   }
1164
1165   // end of recording
1166   logger->log("Player", Log::DEBUG, "Recording playback ends");
1167
1168   if (videoStartup) // oh woe. there never was a stream, I was conned!
1169   {
1170     videoStartup = false;
1171     unLock();
1172     MILLISLEEP(500); // I think this will solve a race
1173   }
1174
1175   threadCheckExit();
1176
1177
1178   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1179   m->to = messageReceiver;
1180   m->from = this;
1181   m->message = Message::PLAYER_EVENT;
1182   m->parameter = Player::STOP_PLAYBACK;
1183   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1184   messageQueue->postMessage(m);
1185 }
1186
1187
1188 void Player::threadPTSFeedScan()
1189 {
1190   // This method manipulates the PTS instead of waiting, this is for the android devices, maybe later for windows?
1191
1192   ULONG direction = 0;
1193   int dir_fac=-1;
1194   ULONG baseFrameNumber = 0;
1195   ULONG iframeNumber = 0;
1196   ULONG iframeLength = 0;
1197   ULONG currentfeedFrameNumber=currentFrameNumber;
1198   ULONG firstFrameNumber=currentFrameNumber;
1199   ULLONG filePos;
1200   UINT amountReceived;
1201   UINT videoLength;
1202
1203   UINT playtime=0;
1204
1205 #ifndef WIN32
1206   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1207   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1208   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1209 #else
1210   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1211 #endif
1212
1213   int frameTimeOffset = 0; // Time in msec between frames
1214   int disp_msec = 0;  // Time taken to display data
1215   int total_msec = 0; // Time taken to fetch data and display it
1216   int sleepTime = 0;
1217
1218   if (state == S_FFWD) {
1219           direction = 1; // and 0 for backward
1220           dir_fac=1;
1221   }
1222   video->EnterIframePlayback();
1223
1224   while(1)
1225   {
1226     // Fetch I-frames until we get one that can be displayed in good time
1227     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1228
1229     baseFrameNumber = currentfeedFrameNumber;
1230
1231     threadCheckExit();
1232     if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1233        return;
1234
1235     if (iframeNumber >= lengthFrames) return;
1236         // scan has got to the end of what we knew to be there before we started scanning
1237
1238     baseFrameNumber = iframeNumber;
1239
1240     frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentfeedFrameNumber) * 1000) / (fps * (double)ifactor));
1241
1242     logger->log("Player", Log::DEBUG, "XXX Got frame");
1243
1244     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1245
1246     if (!vdr->isConnected())
1247     {
1248       if (threadBuffer) free(threadBuffer);
1249       doConnectionLost();
1250       break;
1251     }
1252
1253
1254     threadCheckExit();
1255
1256
1257     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1258     demuxer->changeTimes(threadBuffer,videoLength,playtime);
1259     int count=0;
1260     while (!video->displayIFrame(threadBuffer, videoLength)) // the device might block
1261     {
1262         MILLISLEEP(20);
1263         threadCheckExit();
1264         count++;
1265         if (count%300==0) {
1266                 ULLONG cur_time=video->getCurrentTimestamp();
1267         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1268                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1269                 if (cur_time!=0) {
1270                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1271                 }
1272         }
1273
1274     }
1275     playtime +=frameTimeOffset;
1276     currentfeedFrameNumber = iframeNumber;
1277     {
1278                 ULLONG cur_time=video->getCurrentTimestamp();
1279         //       logger->log("Player", Log::ERR, "FFN: %d CFN: %d dirfac %d time %lld ifac %d fps %g",
1280                 //              firstFrameNumber, currentFrameNumber,dir_fac,cur_time,ifactor,fps);
1281                 if (cur_time!=0) {
1282                     currentFrameNumber=firstFrameNumber+(int)(((double)(dir_fac*((long long)cur_time)*((int)ifactor))*fps/90000.));
1283                 }
1284         }
1285
1286     free(threadBuffer);
1287     threadBuffer = NULL;
1288   }
1289 }
1290
1291
1292
1293 void Player::threadFeedScan()
1294 {
1295   // This method is actually really simple - get frame from vdr,
1296   // spit it at the video chip, wait for a time. Most of the code here
1297   // is to get the wait right so that the scan occurs at the correct rate.
1298
1299   ULONG direction = 0;
1300   ULONG baseFrameNumber = 0;
1301   ULONG iframeNumber = 0;
1302   ULONG iframeLength = 0;
1303   ULLONG filePos;
1304   UINT amountReceived;
1305   UINT videoLength;
1306
1307 #ifndef WIN32
1308   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1309   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1310   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1311 #else
1312   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1313 #endif
1314
1315   int frameTimeOffset = 0; // Time in msec between frames
1316   int disp_msec = 0;  // Time taken to display data
1317   int total_msec = 0; // Time taken to fetch data and display it
1318   int sleepTime = 0;
1319
1320   if (state == S_FFWD) direction = 1; // and 0 for backward
1321
1322   while(1)
1323   {
1324     // Fetch I-frames until we get one that can be displayed in good time
1325     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1326
1327     baseFrameNumber = currentFrameNumber;
1328     do
1329     {
1330       threadCheckExit();
1331       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1332         return;
1333
1334       if (iframeNumber >= lengthFrames) return;
1335         // scan has got to the end of what we knew to be there before we started scanning
1336
1337       baseFrameNumber = iframeNumber;
1338       frameTimeOffset =(int) ((double)(abs((int)iframeNumber - (int)currentFrameNumber) * 1000) / (fps * (double)ifactor));
1339 #ifndef WIN32
1340       gettimeofday(&clock0, NULL);
1341 #else
1342       clock0 = timeGetTime();
1343 #endif
1344     }
1345 #ifndef WIN32
1346     while (clock2.tv_sec != 0 &&
1347           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1348           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1349 #else
1350     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1351 #endif
1352     logger->log("Player", Log::DEBUG, "XXX Got frame");
1353
1354     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1355     
1356     if (!vdr->isConnected())
1357     {
1358       if (threadBuffer) free(threadBuffer);
1359       doConnectionLost();
1360       break;
1361     }
1362     
1363 #ifndef WIN32
1364     gettimeofday(&clock1, NULL);
1365     if (clock2.tv_sec != 0)
1366       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1367                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1368                 + frameTimeOffset - disp_msec;
1369 #else
1370     clock1 = timeGetTime();
1371     if (clock2 != 0)
1372       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1373 #endif
1374     if (sleepTime < 0) sleepTime = 0;
1375     threadCheckExit();
1376     MILLISLEEP(sleepTime);
1377    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1378
1379     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1380     video->displayIFrame(threadBuffer, videoLength);
1381     currentFrameNumber = iframeNumber;
1382     free(threadBuffer);
1383     threadBuffer = NULL;
1384
1385 #ifndef WIN32
1386     gettimeofday(&clock2, NULL);
1387     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1388                + (clock2.tv_usec - clock0.tv_usec) / 1000
1389                - sleepTime;
1390     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1391               + (clock2.tv_usec - clock1.tv_usec) / 1000
1392               - sleepTime;
1393 #else
1394     clock2 = timeGetTime();
1395     total_msec = clock2 - clock0 - sleepTime;
1396     disp_msec = clock2 - clock1 - sleepTime;
1397 #endif
1398     logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1399   }
1400 }
1401
1402 void Player::threadPostStopCleanup()
1403 {
1404   if (threadBuffer)
1405   {
1406     free(threadBuffer);
1407     threadBuffer = NULL;
1408   }
1409 }
1410
1411 // ----------------------------------- Dev
1412
1413 #ifdef DEV
1414 void Player::test1()
1415 {
1416   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1417 }
1418
1419 void Player::test2()
1420 {
1421   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1422 }
1423 #endif