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