]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
Remove a couple of log lines
[vompclient-marten.git] / player.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 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   videoLength = demuxer->stripAudio(buffer, amountReceived);
826   video->displayIFrame(buffer, videoLength);
827   video->displayIFrame(buffer, videoLength); // If you do it twice, it works :)
828   free(buffer);
829
830   currentFrameNumber = iframeNumber;
831 }
832
833 void Player::doConnectionLost()
834 {
835   logger->log("Player", Log::DEBUG, "Connection lost, sending message");
836   Message* m = new Message();
837   m->to = messageReceiver;
838   m->from = this;
839   m->message = Message::PLAYER_EVENT;
840   m->parameter = Player::CONNECTION_LOST;
841   messageQueue->postMessage(m);
842 }
843
844 // ----------------------------------- Callback
845
846 void Player::call(void* caller)
847 {
848   if (caller == demuxer)
849   {
850     logger->log("Player", Log::DEBUG, "Callback from demuxer");
851
852     if (video->getTVsize() == Video::ASPECT4X3)
853     {
854       logger->log("Player", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
855       return;
856     }
857
858     int dxCurrentAspect = demuxer->getAspectRatio();
859     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
860     {
861       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
862       video->setAspectRatio(Video::ASPECT4X3);
863
864       Message* m = new Message();
865       m->from = this;
866       m->to = messageReceiver;
867       m->message = Message::PLAYER_EVENT;
868       m->parameter = Player::ASPECT43;
869       messageQueue->postMessageFromOuterSpace(m);
870     }
871     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
872     {
873       logger->log("Player", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
874       video->setAspectRatio(Video::ASPECT16X9);
875
876       Message* m = new Message();
877       m->from = this;
878       m->to = messageReceiver;
879       m->message = Message::PLAYER_EVENT;
880       m->parameter = Player::ASPECT169;
881       messageQueue->postMessageFromOuterSpace(m);
882     }
883     else
884     {
885       logger->log("Player", Log::DEBUG, "Demuxer said video is something else... ignoring");
886     }
887
888   }
889   else
890   {
891     if (videoStartup)
892     {
893       videoStartup = false;
894       video->reset();
895       video->play();
896       video->sync();
897       vfeed.release();
898       unLock();
899     }
900
901     threadSignalNoLock();
902   }
903 }
904
905 // ----------------------------------- Feed thread
906
907 void Player::threadMethod()
908 {
909   // this method used to be simple, the only thing it does
910   // is farm out to threadFeed Live/Play/Scan
911   // All the guff is to support scan hitting one end
912
913   if (isRecording)
914   {
915     if ((state == S_FFWD) || (state == S_FBWD))
916     {
917       threadFeedScan();
918       // if this returns then scan hit one end
919       if (state == S_FFWD) // scan hit the end. stop
920       {
921         threadCheckExit();
922         Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
923         m->to = messageReceiver;
924         m->from = this;
925         m->message = Message::PLAYER_EVENT;
926         m->parameter = STOP_PLAYBACK;
927         logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
928         messageQueue->postMessage(m);
929         logger->log("Player", Log::DEBUG, "Message posted...");
930         return;
931       }
932       // if execution gets to here, threadFeedScan hit the start, go to play mode
933       state = S_PLAY;
934       audio->reset();
935       audio->setStreamType(Audio::MPEG2_PES);
936       demuxer->flush();
937       demuxer->seek();
938       demuxer->setFrameNum(currentFrameNumber);
939       videoStartup = true;
940       afeed.start();
941       vfeed.start();
942       audio->play();
943       audio->sync();
944       audio->systemMuteOff();
945       audio->doMuting();
946     }
947
948     if (state == S_PLAY) threadFeedPlay();
949   }
950   else
951   {
952     threadFeedLive();
953   }
954 }
955
956 void Player::threadFeedLive()
957 {
958   UINT thisRead;
959   UINT writeLength;
960   UINT thisWrite;
961   UINT preBufferTotal = 0;
962
963   UINT askFor;
964   while(1)
965   {
966     thisRead = 0;
967     writeLength = 0;
968     thisWrite = 0;
969
970     threadCheckExit();
971
972     if (startup)
973       askFor = startupBlockSize; // find audio streams sized block
974     else
975       askFor = blockSize; // normal
976
977     threadBuffer = vdr->getBlock(0, askFor, &thisRead);
978
979     if (!vdr->isConnected())
980     {
981       doConnectionLost();
982       return;
983     }
984
985     if (!threadBuffer) break;
986
987     if (startup)
988     {
989       int a_stream = demuxer->scan(threadBuffer, thisRead);
990       demuxer->setAudioStream(a_stream);
991       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
992       startup = false;
993     }
994
995     if (preBuffering)
996     {
997       preBufferTotal += thisRead;
998       if (preBufferTotal >= preBufferSize)
999       {
1000         logger->log("Player", Log::DEBUG, "Got >500K, prebuffering complete");
1001
1002         preBuffering = false;
1003         preBufferTotal = 0;
1004
1005
1006 // FIXME check the win32 code on the mvp
1007 #ifndef WIN32
1008         audio->sync();
1009         audio->play();
1010         video->sync();
1011         video->pause();
1012         afeed.start();
1013         vfeed.start();
1014 #else
1015         afeed.start();
1016         vfeed.start();
1017         audio->sync();
1018         audio->play();
1019         video->sync();
1020         video->pause();
1021 #endif
1022
1023 //        unLock(); // thread will be locked by play until here
1024         // FIXME - see if this can segfault because it is starting threads out of the master mutex
1025       }
1026     }
1027
1028     threadCheckExit();
1029
1030     while(writeLength < thisRead)
1031     {
1032       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1033       writeLength += thisWrite;
1034
1035 //      logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
1036
1037       if (!thisWrite)
1038       {
1039 //        logger->log("Player", Log::DEBUG, "Demuxer full");
1040         // demuxer is full and can't take anymore
1041         threadLock();
1042         threadWaitForSignal();
1043         threadUnlock();
1044       }
1045
1046       threadCheckExit();
1047     }
1048
1049     free(threadBuffer);
1050     threadBuffer = NULL;
1051
1052   }
1053
1054   logger->log("Player", Log::DEBUG, "Live play failed to start or interrupted");
1055
1056   if (videoStartup) // oh woe. there never was a stream, I was conned!
1057   {
1058     videoStartup = false;
1059     unLock();
1060     MILLISLEEP(500); // I think this will solve a race
1061   }
1062
1063   threadCheckExit();
1064
1065   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1066   m->to = messageReceiver;
1067   m->from = this;
1068   m->message = Message::PLAYER_EVENT;
1069   m->parameter = Player::STREAM_END;
1070   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1071   messageQueue->postMessage(m);
1072   logger->log("Player", Log::DEBUG, "Message posted...");
1073 }
1074
1075 void Player::threadFeedPlay()
1076 {
1077   ULLONG feedPosition;
1078   UINT thisRead, writeLength, thisWrite, askFor;
1079   time_t lastRescan = time(NULL);
1080
1081   feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
1082   if (!vdr->isConnected()) { doConnectionLost(); return; }
1083   logger->log("Player", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
1084
1085
1086   while(1)
1087   {
1088     thisRead = 0;
1089     writeLength = 0;
1090     thisWrite = 0;
1091
1092     threadCheckExit();
1093
1094     // If we havn't rescanned for a while..
1095     if ((lastRescan + 60) < time(NULL))
1096     {
1097       lengthBytes = vdr->rescanRecording(&lengthFrames);
1098       if (!vdr->isConnected()) { doConnectionLost(); return; }
1099       logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
1100       lastRescan = time(NULL);
1101     }
1102
1103     if (feedPosition >= lengthBytes) break;  // finished playback
1104
1105     if (startup)
1106     {
1107       if (startupBlockSize > lengthBytes)
1108         askFor = lengthBytes; // is a very small recording!
1109       else
1110         askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
1111     }
1112     else
1113     {
1114       if ((feedPosition + blockSize) > lengthBytes) // last block of recording
1115         askFor = lengthBytes - feedPosition;
1116       else // normal
1117         askFor = blockSize;
1118     }
1119
1120     threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
1121     feedPosition += thisRead;
1122
1123     if (!vdr->isConnected())
1124     {
1125       doConnectionLost();
1126       return;
1127     }
1128
1129     if (!threadBuffer) break;
1130
1131     if (startup)
1132     {
1133       int a_stream = demuxer->scan(threadBuffer, thisRead);
1134       demuxer->setAudioStream(a_stream);
1135       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
1136       startup = false;
1137     }
1138
1139     threadCheckExit();
1140
1141     while(writeLength < thisRead)
1142     {
1143       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
1144       writeLength += thisWrite;
1145
1146       if (!thisWrite)
1147       {
1148         // demuxer is full and can't take anymore
1149         threadLock();
1150         threadWaitForSignal();
1151         threadUnlock();
1152       }
1153
1154       threadCheckExit();
1155     }
1156
1157     free(threadBuffer);
1158     threadBuffer = NULL;
1159
1160   }
1161
1162   // end of recording
1163   logger->log("Player", Log::DEBUG, "Recording playback ends");
1164
1165   if (videoStartup) // oh woe. there never was a stream, I was conned!
1166   {
1167     videoStartup = false;
1168     unLock();
1169     MILLISLEEP(500); // I think this will solve a race
1170   }
1171
1172   threadCheckExit();
1173
1174
1175   Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
1176   m->to = messageReceiver;
1177   m->from = this;
1178   m->message = Message::PLAYER_EVENT;
1179   m->parameter = Player::STOP_PLAYBACK;
1180   logger->log("Player", Log::DEBUG, "Posting message to %p...", messageQueue);
1181   messageQueue->postMessage(m);
1182 }
1183
1184 void Player::threadFeedScan()
1185 {
1186   // This method is actually really simple - get frame from vdr,
1187   // spit it at the video chip, wait for a time. Most of the code here
1188   // is to get the wait right so that the scan occurs at the correct rate.
1189
1190   ULONG direction = 0;
1191   ULONG baseFrameNumber = 0;
1192   ULONG iframeNumber = 0;
1193   ULONG iframeLength = 0;
1194   ULLONG filePos;
1195   UINT amountReceived;
1196   UINT videoLength;
1197
1198 #ifndef WIN32
1199   struct timeval clock0 = {0,0};  // Time stamp after fetching I-frame info
1200   struct timeval clock1 = {0,0};  // Time stamp after fetching I-frame data
1201   struct timeval clock2 = {0,0} ; // Time stamp after displaying I-frame
1202 #else
1203   DWORD clock0 = 0, clock1 = 0, clock2 = 0;
1204 #endif
1205
1206   int frameTimeOffset = 0; // Time in msec between frames
1207   int disp_msec = 0;  // Time taken to display data
1208   int total_msec = 0; // Time taken to fetch data and display it
1209   int sleepTime = 0;
1210
1211   if (state == S_FFWD) direction = 1; // and 0 for backward
1212
1213   while(1)
1214   {
1215     // Fetch I-frames until we get one that can be displayed in good time
1216     // Repeat while clock0 + total_msec > clock2 + frameTimeOffset
1217     baseFrameNumber = currentFrameNumber;
1218     do
1219     {
1220       threadCheckExit();
1221       if (!vdr->getNextIFrame(baseFrameNumber, direction, &filePos, &iframeNumber, &iframeLength))
1222         return;
1223
1224       if (iframeNumber >= lengthFrames) return;
1225         // scan has got to the end of what we knew to be there before we started scanning
1226
1227       baseFrameNumber = iframeNumber;
1228       frameTimeOffset = abs((int)iframeNumber - (int)currentFrameNumber) * 1000 / (video->getFPS() * ifactor);
1229 #ifndef WIN32
1230       gettimeofday(&clock0, NULL);
1231 #else
1232       clock0 = timeGetTime();
1233 #endif
1234     }
1235 #ifndef WIN32
1236     while (clock2.tv_sec != 0 &&
1237           (clock0.tv_sec - clock2.tv_sec) * 1000 +
1238           (clock0.tv_usec - clock2.tv_usec) / 1000 > frameTimeOffset - total_msec);
1239 #else
1240     while (clock2 != 0 && clock0 + total_msec > clock2 + frameTimeOffset);
1241 #endif
1242 //    logger->log("Player", Log::DEBUG, "XXX Got frame");
1243
1244     threadBuffer = vdr->getBlock(filePos, iframeLength, &amountReceived);
1245 #ifndef WIN32
1246     gettimeofday(&clock1, NULL);
1247     if (clock2.tv_sec != 0)
1248       sleepTime = (clock2.tv_sec - clock1.tv_sec) * 1000
1249                 + (clock2.tv_usec - clock1.tv_usec) / 1000
1250                 + frameTimeOffset - disp_msec;
1251 #else
1252     clock1 = timeGetTime();
1253     if (clock2 != 0)
1254       sleepTime = clock2 + frameTimeOffset - disp_msec - clock1;
1255 #endif
1256     if (sleepTime < 0) sleepTime = 0;
1257     threadCheckExit();
1258     MILLISLEEP(sleepTime);
1259 //    logger->log("Player", Log::DEBUG, "XXX Slept for %d", sleepTime);
1260
1261     videoLength = demuxer->stripAudio(threadBuffer, amountReceived);
1262     video->displayIFrame(threadBuffer, videoLength);
1263     currentFrameNumber = iframeNumber;
1264     free(threadBuffer);
1265     threadBuffer = NULL;
1266
1267 #ifndef WIN32
1268     gettimeofday(&clock2, NULL);
1269     total_msec = (clock2.tv_sec - clock0.tv_sec) * 1000
1270                + (clock2.tv_usec - clock0.tv_usec) / 1000
1271                - sleepTime;
1272     disp_msec = (clock2.tv_sec - clock1.tv_sec) * 1000
1273               + (clock2.tv_usec - clock1.tv_usec) / 1000
1274               - sleepTime;
1275 #else
1276     clock2 = timeGetTime();
1277     total_msec = clock2 - clock0 - sleepTime;
1278     disp_msec = clock2 - clock1 - sleepTime;
1279 #endif
1280 //    logger->log("Player", Log::DEBUG, "XXX disp_msec = %4d total_msec = %4d", disp_msec, total_msec);
1281   }
1282 }
1283
1284 void Player::threadPostStopCleanup()
1285 {
1286   if (threadBuffer)
1287   {
1288     free(threadBuffer);
1289     threadBuffer = NULL;
1290   }
1291 }
1292
1293 // ----------------------------------- Dev
1294
1295 #ifdef DEV
1296 void Player::test1()
1297 {
1298   logger->log("Player", Log::DEBUG, "PLAYER TEST 1");
1299 //  video->play();
1300 //  video->setAspectRatio(Video::ASPECT4X3);
1301   jumpToFrameP(37507);
1302 }
1303
1304 void Player::test2()
1305 {
1306   logger->log("Player", Log::DEBUG, "PLAYER TEST 2");
1307   video->setAspectRatio(Video::ASPECT16X9);
1308 }
1309 #endif