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