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