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