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