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