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