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