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