]> git.vomp.tv Git - vompclient.git/blob - player.cc
Update scan speeds
[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         audio->sync();
863         audio->play();
864         video->sync();
865         video->pause();
866         afeed.start();
867         vfeed.start();
868 //        unLock(); // thread will be locked by play until here
869         // FIXME - see if this can segfault because it is starting threads out of the master mutex
870       }
871     }
872
873     threadCheckExit();
874
875     while(writeLength < thisRead)
876     {
877       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
878       writeLength += thisWrite;
879
880       if (!thisWrite)
881       {
882         // demuxer is full and can't take anymore
883         threadLock();
884         threadWaitForSignal();
885         threadUnlock();
886       }
887
888       threadCheckExit();
889     }
890
891     free(threadBuffer);
892     threadBuffer = NULL;
893
894   }
895
896   logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
897
898   if (videoStartup) // oh woe. there never was a stream, I was conned!
899   {
900     videoStartup = false;
901     unLock();
902     MILLISLEEP(500); // I think this will solve a race
903   }
904
905   threadCheckExit();
906
907   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
908   m->to = messageReceiver;
909   m->from = this;
910   m->message = Message::PLAYER_EVENT;
911   m->parameter = Player::STREAM_END;
912   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
913   messageQueue->postMessage(m);
914   logger->log("Player", Log::DEBUG, "Message posted...");
915 }
916
917 void Player::threadFeedPlay()
918 {
919   ULLONG feedPosition;
920   UINT thisRead, writeLength, thisWrite, askFor;
921   time_t lastRescan = time(NULL);
922
923   feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
924   if (!vdr->isConnected()) { doConnectionLost(); return; }
925   logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
926
927
928   while(1)
929   {
930     thisRead = 0;
931     writeLength = 0;
932     thisWrite = 0;
933
934     threadCheckExit();
935
936     // If we havn't rescanned for a while..
937     if ((lastRescan + 60) < time(NULL))
938     {
939       lengthBytes = vdr->rescanRecording(&lengthFrames);
940       if (!vdr->isConnected()) { doConnectionLost(); return; }
941       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
942       lastRescan = time(NULL);
943     }
944
945     if (feedPosition >= lengthBytes) break;  // finished playback
946
947     if (startup)
948     {
949       if (startupBlockSize > lengthBytes)
950         askFor = lengthBytes; // is a very small recording!
951       else
952         askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
953     }
954     else
955     {
956       if ((feedPosition + blockSize) > lengthBytes) // last block of recording
957         askFor = lengthBytes - feedPosition;
958       else // normal
959         askFor = blockSize;
960     }
961
962     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
963     feedPosition += thisRead;
964
965     if (!vdr->isConnected())
966     {
967       doConnectionLost();
968       return;
969     }
970
971     if (!threadBuffer) break;
972
973     if (startup)
974     {
975       int a_stream = demuxer->scan(threadBuffer, thisRead);
976       demuxer->setAudioStream(a_stream);
977       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
978       startup = false;
979     }
980
981     threadCheckExit();
982
983     while(writeLength < thisRead)
984     {
985       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
986       writeLength += thisWrite;
987
988       if (!thisWrite)
989       {
990         // demuxer is full and can't take anymore
991         threadLock();
992         threadWaitForSignal();
993         threadUnlock();
994       }
995
996       threadCheckExit();
997     }
998
999     free(threadBuffer);
1000     threadBuffer = NULL;
1001
1002   }
1003
1004   // end of recording
1005   logger->log("Player", Log::DEBUG, "Recording playback ends");
1006
1007   if (videoStartup) // oh woe. there never was a stream, I was conned!
1008   {
1009     videoStartup = false;
1010     unLock();
1011     MILLISLEEP(500); // I think this will solve a race
1012   }
1013
1014   threadCheckExit();
1015
1016
1017   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1018   m->to = messageReceiver;
1019   m->from = this;
1020   m->message = Message::PLAYER_EVENT;
1021   m->parameter = Player::STOP_PLAYBACK;
1022   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1023   messageQueue->postMessage(m);
1024 }
1025
1026 void Player::threadFeedScan()
1027 {
1028   // This method is actually really simple - get frame from vdr,
1029   // spit it at the video chip, wait for a time. Most of the code here
1030   // is to get the wait right so that the scan occurs at the correct rate.
1031
1032   ULONG direction = 0;
1033   ULONG baseFrameNumber = 0;
1034   ULONG iframeNumber = 0;
1035   ULONG iframeLength = 0;
1036   ULLONG filePos;
1037   UINT amountReceived;
1038   UINT videoLength;
1039
1040 #ifndef _MSC_VER
1041   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1042   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1043   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1044 #else
1045   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1046 #endif
1047
1048   int frameTimeOffset = 0; // Time in msec between frames
1049   int disp_msec = 0;  // Time taken to display data
1050   int total_msec = 0; // Time taken to fetch data and display it
1051   int sleepTime = 0;
1052
1053   if (state == S_FFWD) direction = 1; // and 0 for backward
1054
1055   while(1)
1056   {
1057     // Fetch I-frames until we get one that can be displayed in good time
1058     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1059     baseFrameNumber = currentFrameNumber;
1060     do
1061     {
1062       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1063         return;
1064
1065       baseFrameNumber = iframeNumber;
1066       frameTimeOffset = abs(iframeNumber - currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1067 #ifndef WIN32
1068       gettimeofday(&clock0, NULL);
1069 #else
1070       clock0 = timeGetTime();
1071 #endif
1072     }
1073 #ifndef WIN32
1074     while (clock2.tv_sec != 0 &&
1075           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1076           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1077 #else
1078     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1079 #endif
1080 //    logger->log("Player", Log::DEBUG, "XXX Got frame");
1081
1082     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1083 #ifndef WIN32
1084     gettimeofday(&clock1, NULL);
1085     if (clock2.tv_sec != 0)
1086       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1087                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1088                 + frameTimeOffset - disp_msec;
1089 #else
1090     clock1 = timeGetTime();
1091     if (clock2 != 0)
1092       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1093 #endif
1094     if (sleepTime < 0) sleepTime = 0;
1095     threadCheckExit();
1096     MILLISLEEP(sleepTime);
1097 //    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1098
1099     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1100     video->displayIFrame(threadBuffer, videoLength);
1101     currentFrameNumber = iframeNumber;
1102     free(threadBuffer);
1103     threadBuffer = NULL;
1104
1105 #ifndef WIN32
1106     gettimeofday(&clock2, NULL);
1107     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1108                + (clock2.tv_usec - clock0.tv_usec) / 1000
1109                - sleepTime;
1110     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1111               + (clock2.tv_usec - clock1.tv_usec) / 1000
1112               - sleepTime;
1113 #else
1114     clock2 = timeGetTime();
1115     total_msec = clock2 - clock0 - sleepTime;
1116     disp_msec = clock2 - clock1 - sleepTime;
1117 #endif
1118 //    logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1119   }
1120 }
1121
1122 void Player::threadPostStopCleanup()
1123 {
1124   if (threadBuffer)
1125   {
1126     free(threadBuffer);
1127     threadBuffer = NULL;
1128   }
1129 }
1130
1131 // ----------------------------------- Dev
1132
1133 #ifdef DEV
1134 void Player::test1()
1135 {
1136   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1137   video->play();
1138 //  video->setAspectRatio(Video::ASPECT4X3);
1139 }
1140
1141 void Player::test2()
1142 {
1143   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1144   video->setAspectRatio(Video::ASPECT16X9);
1145 }
1146 #endif