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