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