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