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