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