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