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