]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
Minor fixes
[vompclient-marten.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->systemMuteOn();
471           audio->unPause();
472           restartAtFrame(jumpFrame);
473           return;
474         }
475         case S_JUMP_PI: // to S_JUMP_PI
476         {
477           audio->systemMuteOn();
478           audio->unPause();
479           threadStop();
480           vfeed.stop();
481           afeed.stop();
482           demuxer->flush();
483           state = S_PAUSE_I;
484           video->reset();
485           video->play();
486           restartAtFramePI(jumpFrame);
487           return;
488         }
489       }
490     }
491     case S_PAUSE_I: // from S_PAUSE_I -----------------------------------
492     {
493       switch(toState)
494       {
495         case S_PLAY: // to S_PLAY
496         {
497           state = S_PLAY;
498           restartAtFrame(currentFrameNumber);
499           return;
500         }
501         case S_PAUSE_P: // to S_PAUSE_P
502         {
503           return;
504         }
505         case S_PAUSE_I: // to S_PAUSE_I
506         {
507           return;
508         }
509         case S_FFWD: // to S_FFWD
510         {
511           state = S_FFWD;
512           threadStart();
513           return;
514         }
515         case S_FBWD: // to S_FBWD
516         {
517           state = S_FBWD;
518           threadStart();
519           return;
520         }
521         case S_STOP: // to S_STOP
522         {
523           video->stop();
524           video->blank();
525           audio->stop();
526           video->reset();
527           demuxer->reset();
528           audio->systemMuteOff();
529           state = S_STOP;
530           return;
531         }
532         case S_JUMP: // to S_JUMP
533         {
534           state = S_PLAY;
535           restartAtFrame(jumpFrame);
536           return;
537         }
538         case S_JUMP_PI: // to S_JUMP_PI
539         {
540           restartAtFramePI(jumpFrame);
541           return;
542         }
543       }
544     }
545     case S_FFWD: // from S_FFWD -----------------------------------
546     {
547       switch(toState)
548       {
549         case S_PLAY: // to S_PLAY
550         {
551           state = S_PLAY;
552           ULONG stepback = USER_RESPONSE_TIME * video->getFPS() * ifactor / 1000;
553           if (stepback < currentFrameNumber)
554             currentFrameNumber -= stepback;
555           else
556             currentFrameNumber = 0;
557           restartAtFrame(currentFrameNumber);
558           return;
559         }
560         case S_PAUSE_P: // to S_PAUSE_P
561         {
562           // can't occur
563           return;
564         }
565         case S_PAUSE_I: // to S_PAUSE_I
566         {
567           threadStop();
568           state = S_PAUSE_I;
569           return;
570         }
571         case S_FFWD: // to S_FFWD
572         {
573           return;
574         }
575         case S_FBWD: // to S_FBWD
576         {
577           threadStop();
578           state = S_FBWD;
579           threadStart();
580           return;
581         }
582         case S_STOP: // to S_STOP
583         {
584           threadStop();
585           video->stop();
586           video->blank();
587           audio->stop();
588           video->reset();
589           demuxer->reset();
590           state = S_STOP;
591           return;
592         }
593         case S_JUMP: // to S_JUMP
594         {
595           state = S_PLAY;
596           restartAtFrame(jumpFrame);
597           return;
598         }
599         case S_JUMP_PI: // to S_JUMP_PI
600         {
601           threadStop();
602           state = S_PAUSE_I;
603           restartAtFramePI(jumpFrame);
604           return;
605         }
606       }
607     }
608     case S_FBWD: // from S_FBWD -----------------------------------
609     {
610       switch(toState)
611       {
612         case S_PLAY: // to S_PLAY
613         {
614           state = S_PLAY;
615           restartAtFrame(currentFrameNumber);
616           return;
617         }
618         case S_PAUSE_P: // to S_PAUSE_P
619         {
620           // can't occur
621           return;
622         }
623         case S_PAUSE_I: // to S_PAUSE_I
624         {
625           threadStop();
626           state = S_PAUSE_I;
627           return;
628         }
629         case S_FFWD: // to S_FFWD
630         {
631           threadStop();
632           state = S_FFWD;
633           threadStart();
634           return;
635         }
636         case S_FBWD: // to S_FBWD
637         {
638           return;
639         }
640         case S_STOP: // to S_STOP
641         {
642           threadStop();
643           video->stop();
644           video->blank();
645           audio->stop();
646           video->reset();
647           demuxer->reset();
648           state = S_STOP;
649           return;
650         }
651         case S_JUMP: // to S_JUMP
652         {
653           state = S_PLAY;
654           restartAtFrame(jumpFrame);
655           return;
656         }
657         case S_JUMP_PI: // to S_JUMP_PI
658         {
659           threadStop();
660           state = S_PAUSE_I;
661           restartAtFramePI(jumpFrame);
662           return;
663         }
664       }
665     }
666     case S_STOP: // from S_STOP -----------------------------------
667     {
668       switch(toState)
669       {
670         case S_PLAY: // to S_PLAY
671         {
672           startup = true;
673
674           audio->reset();
675           audio->setStreamType(Audio::MPEG2_PES);
676           audio->systemMuteOff();
677           video->reset();
678           demuxer->reset();
679           if (isRecording)
680           {
681             // FIXME use restartAtFrame here?
682             if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
683             demuxer->setFrameNum(currentFrameNumber);
684           }
685           demuxer->seek();
686
687           videoStartup = true;
688           state = S_PLAY;
689           threadStart();
690
691           if (isRecording)
692           {
693             logger->log("Player", Log::DEBUG, "Immediate play");
694             afeed.start();
695             vfeed.start();
696             video->sync();
697             audio->sync();
698             audio->play();
699             video->pause();
700           }
701           else // do prebuffering
702           {
703             logger->log("Player", Log::DEBUG, "Prebuffering...");
704             preBuffering = true;
705           }
706           return;
707         }
708         case S_PAUSE_P: // to S_PAUSE_P
709         {
710           return;
711         }
712         case S_PAUSE_I: // to S_PAUSE_I
713         {
714           return;
715         }
716         case S_FFWD: // to S_FFWD
717         {
718           return;
719         }
720         case S_FBWD: // to S_FBWD
721         {
722           return;
723         }
724         case S_STOP: // to S_STOP
725         {
726           return;
727         }
728         case S_JUMP: // to S_JUMP
729         {
730           return;
731         }
732         case S_JUMP_PI: // to S_JUMP_PI
733         {
734           return;
735         }
736       }
737     }
738     // case S_JUMP cannot be a start state because it auto flips to play
739     // case S_JUMP_PI cannot be a start state because it auto flips to S_PAUSE_I
740   }
741 }
742
743 // ----------------------------------- Internal functions
744
745 void Player::lock()
746 {
747 #ifndef WIN32
748   pthread_mutex_lock(&mutex);
749   logger->log("Player", Log::DEBUG, "LOCKED");
750
751 #else
752    WaitForSingleObject(mutex, INFINITE);
753 #endif
754 }
755
756 void Player::unLock()
757 {
758 #ifndef WIN32
759   logger->log("Player", Log::DEBUG, "UNLOCKING");
760   pthread_mutex_unlock(&mutex);
761 #else
762    ReleaseMutex(mutex);
763 #endif
764 }
765
766 void Player::restartAtFrame(ULONG newFrame)
767 {
768   vfeed.stop();
769   afeed.stop();
770   threadStop();
771   video->stop();
772   video->reset();
773   audio->reset();
774   audio->setStreamType(Audio::MPEG2_PES);
775   demuxer->flush();
776   demuxer->seek();
777   currentFrameNumber = newFrame;
778   demuxer->setFrameNum(newFrame);
779   videoStartup = true;
780   afeed.start();
781   vfeed.start();
782   threadStart();
783   audio->play();
784   video->sync();
785   audio->sync();
786   audio->systemMuteOff();
787   audio->doMuting();
788 }
789
790
791 void Player::restartAtFramePI(ULONG newFrame)
792 {
793   ULLONG filePos;
794   ULONG nextiframeNumber;
795   ULONG iframeLength;
796   ULONG iframeNumber;
797
798   UCHAR* buffer;
799   UINT amountReceived;
800   UINT videoLength;
801
802   // newFrame could be anywhere, go forwards to next I-Frame
803   if (!vdr->getNextIFrame(newFrame, 1, &filePos, &nextiframeNumber, &iframeLength)) return;
804
805   // Now step back a GOP. This ensures we go to the greatest I-Frame equal to or less than the requested frame
806   vdr->getNextIFrame(nextiframeNumber, 0, &filePos, &iframeNumber, &iframeLength);
807
808   buffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
809   videoLength = demuxer->stripAudio(buffer, amountReceived);
810   video->displayIFrame(buffer, videoLength);
811   video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
812   free(buffer);
813
814   currentFrameNumber = iframeNumber;
815 }
816
817 void Player::doConnectionLost()
818 {
819   logger->log("Player", Log::DEBUG, "Connection lost, sending message");
820   Message* m = new Message();
821   m->to = messageReceiver;
822   m->from = this;
823   m->message = Message::PLAYER_EVENT;
824   m->parameter = Player::CONNECTION_LOST;
825   messageQueue->postMessage(m);
826 }
827
828 // ----------------------------------- Callback
829
830 void Player::call(void* caller)
831 {
832   if (caller == demuxer)
833   {
834     logger->log("Player", Log::DEBUG, "Callback from demuxer");
835
836     if (video->getTVsize() == Video::ASPECT4X3)
837     {
838       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
839       return;
840     }
841
842     int dxCurrentAspect = demuxer->getAspectRatio();
843     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
844     {
845       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
846       video->setAspectRatio(Video::ASPECT4X3);
847
848       Message* m = new Message();
849       m->from = this;
850       m->to = messageReceiver;
851       m->message = Message::PLAYER_EVENT;
852       m->parameter = Player::ASPECT43;
853       messageQueue->postMessageFromOuterSpace(m);
854     }
855     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
856     {
857       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
858       video->setAspectRatio(Video::ASPECT16X9);
859
860       Message* m = new Message();
861       m->from = this;
862       m->to = messageReceiver;
863       m->message = Message::PLAYER_EVENT;
864       m->parameter = Player::ASPECT169;
865       messageQueue->postMessageFromOuterSpace(m);
866     }
867     else
868     {
869       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
870     }
871
872   }
873   else
874   {
875     if (videoStartup)
876     {
877       videoStartup = false;
878       video->reset();
879       video->play();
880       video->sync();
881       vfeed.release();
882       unLock();
883     }
884
885     threadSignalNoLock();
886   }
887 }
888
889 // ----------------------------------- Feed thread
890
891 void Player::threadMethod()
892 {
893   // this method used to be simple, the only thing it does
894   // is farm out to threadFeed Live/Play/Scan
895   // All the guff is to support scan hitting one end
896
897   if (isRecording)
898   {
899     if ((state == S_FFWD) || (state == S_FBWD))
900     {
901       threadFeedScan();
902       // if this returns then scan hit one end
903       if (state == S_FFWD) // scan hit the end. stop
904       {
905         threadCheckExit();
906         Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
907         m->to = messageReceiver;
908         m->from = this;
909         m->message = Message::PLAYER_EVENT;
910         m->parameter = STOP_PLAYBACK;
911         logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
912         messageQueue->postMessage(m);
913         logger->log("Player", Log::DEBUG, "Message posted...");
914         return;
915       }
916       // if execution gets to here, threadFeedScan hit the start, go to play mode
917       state = S_PLAY;
918       audio->reset();
919       audio->setStreamType(Audio::MPEG2_PES);
920       demuxer->flush();
921       demuxer->seek();
922       demuxer->setFrameNum(currentFrameNumber);
923       videoStartup = true;
924       afeed.start();
925       vfeed.start();
926       audio->play();
927       audio->sync();
928       audio->systemMuteOff();
929       audio->doMuting();
930     }
931
932     if (state == S_PLAY) threadFeedPlay();
933   }
934   else
935   {
936     threadFeedLive();
937   }
938 }
939
940 void Player::threadFeedLive()
941 {
942   UINT thisRead;
943   UINT writeLength;
944   UINT thisWrite;
945   UINT preBufferTotal = 0;
946
947   UINT askFor;
948   while(1)
949   {
950     thisRead = 0;
951     writeLength = 0;
952     thisWrite = 0;
953
954     threadCheckExit();
955
956     if (startup)
957       askFor = startupBlockSize; // find audio streams sized block
958     else
959       askFor = blockSize; // normal
960
961     threadBuffer = vdr->getBlock(0, askFor, &thisRead);
962
963     if (!vdr->isConnected())
964     {
965       doConnectionLost();
966       return;
967     }
968
969     if (!threadBuffer) break;
970
971     if (startup)
972     {
973       int a_stream = demuxer->scan(threadBuffer, thisRead);
974       demuxer->setAudioStream(a_stream);
975       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
976       startup = false;
977     }
978
979     if (preBuffering)
980     {
981       preBufferTotal += thisRead;
982       if (preBufferTotal >= preBufferSize)
983       {
984         logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
985
986         preBuffering = false;
987         preBufferTotal = 0;
988
989
990 // FIXME check the win32 code on the mvp
991 #ifndef WIN32
992         audio->sync();
993         audio->play();
994         video->sync();
995         video->pause();
996         afeed.start();
997         vfeed.start();
998 #else
999         afeed.start();
1000         vfeed.start();
1001         audio->sync();
1002         audio->play();
1003         video->sync();
1004         video->pause();
1005 #endif
1006
1007 //        unLock(); // thread will be locked by play until here
1008         // FIXME - see if this can segfault because it is starting threads out of the master mutex
1009       }
1010     }
1011
1012     threadCheckExit();
1013
1014     while(writeLength < thisRead)
1015     {
1016       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1017       writeLength += thisWrite;
1018
1019 //      logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
1020
1021       if (!thisWrite)
1022       {
1023 //        logger->log("Player", Log::DEBUG, "Demuxer full");
1024         // demuxer is full and can't take anymore
1025         threadLock();
1026         threadWaitForSignal();
1027         threadUnlock();
1028       }
1029
1030       threadCheckExit();
1031     }
1032
1033     free(threadBuffer);
1034     threadBuffer = NULL;
1035
1036   }
1037
1038   logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
1039
1040   if (videoStartup) // oh woe. there never was a stream, I was conned!
1041   {
1042     videoStartup = false;
1043     unLock();
1044     MILLISLEEP(500); // I think this will solve a race
1045   }
1046
1047   threadCheckExit();
1048
1049   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1050   m->to = messageReceiver;
1051   m->from = this;
1052   m->message = Message::PLAYER_EVENT;
1053   m->parameter = Player::STREAM_END;
1054   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1055   messageQueue->postMessage(m);
1056   logger->log("Player", Log::DEBUG, "Message posted...");
1057 }
1058
1059 void Player::threadFeedPlay()
1060 {
1061   ULLONG feedPosition;
1062   UINT thisRead, writeLength, thisWrite, askFor;
1063   time_t lastRescan = time(NULL);
1064
1065   feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1066   if (!vdr->isConnected()) { doConnectionLost(); return; }
1067   logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1068
1069
1070   while(1)
1071   {
1072     thisRead = 0;
1073     writeLength = 0;
1074     thisWrite = 0;
1075
1076     threadCheckExit();
1077
1078     // If we havn't rescanned for a while..
1079     if ((lastRescan + 60) < time(NULL))
1080     {
1081       lengthBytes = vdr->rescanRecording(&lengthFrames);
1082       if (!vdr->isConnected()) { doConnectionLost(); return; }
1083       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1084       lastRescan = time(NULL);
1085     }
1086
1087     if (feedPosition >= lengthBytes) break;  // finished playback
1088
1089     if (startup)
1090     {
1091       if (startupBlockSize > lengthBytes)
1092         askFor = lengthBytes; // is a very small recording!
1093       else
1094         askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1095     }
1096     else
1097     {
1098       if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1099         askFor = lengthBytes - feedPosition;
1100       else // normal
1101         askFor = blockSize;
1102     }
1103
1104     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1105     feedPosition += thisRead;
1106
1107     if (!vdr->isConnected())
1108     {
1109       doConnectionLost();
1110       return;
1111     }
1112
1113     if (!threadBuffer) break;
1114
1115     if (startup)
1116     {
1117       int a_stream = demuxer->scan(threadBuffer, thisRead);
1118       demuxer->setAudioStream(a_stream);
1119       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1120       startup = false;
1121     }
1122
1123     threadCheckExit();
1124
1125     while(writeLength < thisRead)
1126     {
1127       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1128       writeLength += thisWrite;
1129
1130       if (!thisWrite)
1131       {
1132         // demuxer is full and can't take anymore
1133         threadLock();
1134         threadWaitForSignal();
1135         threadUnlock();
1136       }
1137
1138       threadCheckExit();
1139     }
1140
1141     free(threadBuffer);
1142     threadBuffer = NULL;
1143
1144   }
1145
1146   // end of recording
1147   logger->log("Player", Log::DEBUG, "Recording playback ends");
1148
1149   if (videoStartup) // oh woe. there never was a stream, I was conned!
1150   {
1151     videoStartup = false;
1152     unLock();
1153     MILLISLEEP(500); // I think this will solve a race
1154   }
1155
1156   threadCheckExit();
1157
1158
1159   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1160   m->to = messageReceiver;
1161   m->from = this;
1162   m->message = Message::PLAYER_EVENT;
1163   m->parameter = Player::STOP_PLAYBACK;
1164   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1165   messageQueue->postMessage(m);
1166 }
1167
1168 void Player::threadFeedScan()
1169 {
1170   // This method is actually really simple - get frame from vdr,
1171   // spit it at the video chip, wait for a time. Most of the code here
1172   // is to get the wait right so that the scan occurs at the correct rate.
1173
1174   ULONG direction = 0;
1175   ULONG baseFrameNumber = 0;
1176   ULONG iframeNumber = 0;
1177   ULONG iframeLength = 0;
1178   ULLONG filePos;
1179   UINT amountReceived;
1180   UINT videoLength;
1181
1182 #ifndef WIN32
1183   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1184   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1185   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1186 #else
1187   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1188 #endif
1189
1190   int frameTimeOffset = 0; // Time in msec between frames
1191   int disp_msec = 0;  // Time taken to display data
1192   int total_msec = 0; // Time taken to fetch data and display it
1193   int sleepTime = 0;
1194
1195   if (state == S_FFWD) direction = 1; // and 0 for backward
1196
1197   while(1)
1198   {
1199     // Fetch I-frames until we get one that can be displayed in good time
1200     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1201     baseFrameNumber = currentFrameNumber;
1202     do
1203     {
1204       threadCheckExit();
1205       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1206         return;
1207
1208       if (iframeNumber >= lengthFrames) return;
1209         // scan has got to the end of what we knew to be there before we started scanning
1210
1211       baseFrameNumber = iframeNumber;
1212       frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1213 #ifndef WIN32
1214       gettimeofday(&clock0, NULL);
1215 #else
1216       clock0 = timeGetTime();
1217 #endif
1218     }
1219 #ifndef WIN32
1220     while (clock2.tv_sec != 0 &&
1221           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1222           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1223 #else
1224     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1225 #endif
1226 //    logger->log("Player", Log::DEBUG, "XXX Got frame");
1227
1228     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1229 #ifndef WIN32
1230     gettimeofday(&clock1, NULL);
1231     if (clock2.tv_sec != 0)
1232       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1233                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1234                 + frameTimeOffset - disp_msec;
1235 #else
1236     clock1 = timeGetTime();
1237     if (clock2 != 0)
1238       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1239 #endif
1240     if (sleepTime < 0) sleepTime = 0;
1241     threadCheckExit();
1242     MILLISLEEP(sleepTime);
1243 //    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1244
1245     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1246     video->displayIFrame(threadBuffer, videoLength);
1247     currentFrameNumber = iframeNumber;
1248     free(threadBuffer);
1249     threadBuffer = NULL;
1250
1251 #ifndef WIN32
1252     gettimeofday(&clock2, NULL);
1253     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1254                + (clock2.tv_usec - clock0.tv_usec) / 1000
1255                - sleepTime;
1256     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1257               + (clock2.tv_usec - clock1.tv_usec) / 1000
1258               - sleepTime;
1259 #else
1260     clock2 = timeGetTime();
1261     total_msec = clock2 - clock0 - sleepTime;
1262     disp_msec = clock2 - clock1 - sleepTime;
1263 #endif
1264 //    logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1265   }
1266 }
1267
1268 void Player::threadPostStopCleanup()
1269 {
1270   if (threadBuffer)
1271   {
1272     free(threadBuffer);
1273     threadBuffer = NULL;
1274   }
1275 }
1276
1277 // ----------------------------------- Dev
1278
1279 #ifdef DEV
1280 void Player::test1()
1281 {
1282   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1283 //  video->play();
1284 //  video->setAspectRatio(Video::ASPECT4X3);
1285   jumpToFrameP(37507);
1286 }
1287
1288 void Player::test2()
1289 {
1290   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1291   video->setAspectRatio(Video::ASPECT16X9);
1292 }
1293 #endif