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