]> git.vomp.tv Git - vompclient-marten.git/blob - vvideorec.cc
Windows updates
[vompclient-marten.git] / vvideorec.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "vvideorec.h"
22 #include "vteletextview.h"
23
24 #include "command.h"
25 #include "osd.h"
26 #include "wsymbol.h"
27 #include "audio.h"
28 #include "vdr.h"
29 #include "video.h"
30 #include "timers.h"
31 #include "player.h"
32 #include "recording.h"
33 #include "vaudioselector.h"
34 #include "message.h"
35 #include "remote.h"
36 #include "boxstack.h"
37 #include "vinfo.h"
38 #include "i18n.h"
39 #include "bitmap.h"
40 #include "recinfo.h"
41 #include "log.h"
42  
43 VVideoRec::VVideoRec(Recording* rec)
44 {
45   boxstack = BoxStack::getInstance();
46   vdr = VDR::getInstance();
47   video = Video::getInstance();
48   timers = Timers::getInstance();
49   vas = NULL;
50   vsummary = NULL;
51
52   player = new Player(Command::getInstance(), this, this);
53   player->init();
54
55   videoMode = video->getMode();
56   myRec = rec;
57
58   playing = false;
59
60   startMargin = 0;
61   endMargin = 0;
62   char* cstartMargin = vdr->configLoad("Timers", "Start margin");
63   char* cendMargin = vdr->configLoad("Timers", "End margin");
64   if (!cstartMargin)
65   {
66     startMargin = 300; // 5 mins default
67   }
68   else
69   {
70     startMargin = atoi(cstartMargin) * 60;
71     delete[] cstartMargin;
72   }
73
74   if (!cendMargin)
75   {
76     endMargin = 300; // 5 mins default
77   }
78   else
79   {
80     endMargin = atoi(cendMargin) * 60;
81     delete[] cendMargin;
82   }
83
84   Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
85
86   setSize(video->getScreenWidth(), video->getScreenHeight());
87   createBuffer();
88   transparent.set(0, 0, 0, 0);
89   setBackgroundColour(transparent);
90
91   barRegion.x = 0;
92   barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
93   barRegion.w = video->getScreenWidth();
94   barRegion.h = 58;
95
96   clocksRegion.x = barRegion.x + 140;
97   clocksRegion.y = barRegion.y + 12;
98   clocksRegion.w = 170;
99   clocksRegion.h = surface->getFontHeight();
100 //  barBlue.set(0, 0, 150, 150);
101   barBlue.set(0, 0, 0, 128);
102
103   barShowing = false;
104   barGenHold = false;
105   barScanHold = false;
106   barVasHold = false;
107
108   dowss = false;
109   char* optionWSS = vdr->configLoad("General", "WSS");
110   if (optionWSS)
111   {
112     if (strstr(optionWSS, "Yes")) dowss = true;
113     delete[] optionWSS;
114   }
115   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);
116
117   if (dowss)
118   {
119     wss.setFormat(video->getFormat());
120     wss.setWide(true);
121     add(&wss);
122
123     wssRegion.x = 0;
124     wssRegion.y = 0;
125     wssRegion.w = video->getScreenWidth();
126     wssRegion.h = 300;
127   }
128 }
129
130 void VVideoRec::preDelete()
131 {
132   timers->cancelTimer(this, 1);
133   timers->cancelTimer(this, 2);
134
135   if (vas)
136   {
137     boxstack->remove(vas);
138     vas = NULL;
139   }
140
141   if (vsummary) delete vsummary;
142
143   if (playing) stopPlay();
144 }
145
146 VVideoRec::~VVideoRec()
147 {
148   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");
149
150   video->setDefaultAspect();
151
152   // kill recInfo in case resumePoint has changed (likely)
153   myRec->dropRecInfo();
154   // FIXME - do this properly - save the resume point back to the server manually and update
155   // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
156 }
157
158 void VVideoRec::go(bool resume)
159 {
160   ULONG startFrameNum;
161   if (resume)
162     startFrameNum = myRec->recInfo->resumePoint;
163   else
164     startFrameNum = 0;
165
166   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);
167   ULONG lengthFrames = 0;
168   ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames);
169   if (lengthBytes)
170   {
171     player->setLengthBytes(lengthBytes);
172     player->setLengthFrames(lengthFrames);
173     player->setStartFrame(startFrameNum);
174     player->play();
175     playing = true;
176     doBar(0);
177   }
178   else
179   {
180     stopPlay(); // clean up
181
182     if (!vdr->isConnected())
183     {
184       Command::getInstance()->connectionLost();
185       return;
186     }
187
188     Message* m = new Message();
189     m->message = Message::CLOSE_ME;
190     m->from = this;
191     m->to = boxstack;
192     Command::getInstance()->postMessageNoLock(m);
193
194     VInfo* vi = new VInfo();
195     vi->setSize(400, 150);
196     vi->createBuffer();
197     if (video->getFormat() == Video::PAL)
198       vi->setPosition(170, 200);
199     else
200       vi->setPosition(160, 150);
201     vi->setExitable();
202     vi->setBorderOn(1);
203     vi->setTitleBarOn(0);
204     vi->setOneLiner(tr("Error playing recording"));
205     vi->draw();
206
207     m = new Message();
208     m->message = Message::ADD_VIEW;
209     m->to = boxstack;
210     m->parameter = (ULONG)vi;
211     Command::getInstance()->postMessageNoLock(m);
212   }
213 }
214
215 int VVideoRec::handleCommand(int command)
216 {
217   switch(command)
218   {
219     case Remote::PLAY:
220     {
221       player->play();
222       doBar(0);
223       return 2;
224     }
225
226     case Remote::BACK:
227     {
228       if (vsummary)
229       {
230         removeSummary();
231         return 2;
232       }
233     } // DROP THROUGH
234     case Remote::STOP:
235     case Remote::MENU:
236     {
237       if (playing) stopPlay();
238
239       return 4;
240     }
241     case Remote::PAUSE:
242     {
243       player->pause();
244       doBar(0);
245       return 2;
246     }
247     case Remote::SKIPFORWARD:
248     {
249       doBar(3);
250       player->skipForward(60);
251       return 2;
252     }
253     case Remote::SKIPBACK:
254     {
255       doBar(4);
256       player->skipBackward(60);
257       return 2;
258     }
259     case Remote::FORWARD:
260     {
261       player->fastForward();
262       doBar(0);
263       return 2;
264     }
265     case Remote::REVERSE:
266     {
267       player->fastBackward();
268       doBar(0);
269       return 2;
270     }
271     case Remote::RED:
272     {
273       if (vsummary) removeSummary();
274       else doSummary();
275       return 2;
276     }
277     case Remote::GREEN:
278     {
279       doAudioSelector();
280       return 2;
281     }
282     case Remote::YELLOW:
283     {
284       if (myRec->hasMarks())
285       {
286         // skip to previous mark
287         Log* logger = Log::getInstance();
288         int currentFrame = (player->getCurrentFrameNum()); // get current Frame
289         currentFrame -= 5 * video->getFPS(); // subtrack 5 seconds, else you cannot skip more than once back ..
290
291         int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
292         if (prevMark)
293         {
294           logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
295           player->jumpToMark(prevMark);
296         }
297         doBar(4);
298       }
299       else
300       {
301         doBar(2);
302         player->skipBackward(10);
303       }
304       return 2;
305     }
306     case Remote::BLUE:
307     {
308       if (myRec->hasMarks())
309       {
310         // skip to next mark
311         Log* logger = Log::getInstance();
312         int currentFrame = (player->getCurrentFrameNum());
313
314         int nextMark = myRec->getNextMark(currentFrame);
315
316         if (nextMark)
317         {
318           logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
319           player->jumpToMark(nextMark);
320         }
321         doBar(3);
322       }
323       else
324       {
325         doBar(1);
326         player->skipForward(10);
327       }
328       return 2;
329     }
330     case Remote::STAR:
331     {
332       doBar(2);
333       player->skipBackward(10);
334       return 2;
335     }
336     case Remote::HASH:
337     {
338       doBar(1);
339       player->skipForward(10);
340       return 2;
341     }
342     case Remote::FULL:
343     case Remote::TV:
344     {
345       toggleChopSides();
346       return 2;
347     }
348
349     case Remote::OK:
350     {
351       if (vsummary)
352       {
353         removeSummary();
354         return 2;
355       }
356       
357       if (barShowing) removeBar();
358       else doBar(0);
359       return 2;
360     }
361
362     case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
363     case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
364     case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
365     case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
366     case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
367     case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
368     case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
369     case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
370     case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
371     case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
372
373     case Remote::RECORD: player->toggleSubtitles(); return 2;
374 #ifdef DEV
375 //    case Remote::RED:
376 //    {
377       //Don't use RED for anything. It will eventually be recording summary
378
379       //player->test1();
380
381
382       /*
383       // for testing EPG in NTSC with a NTSC test video
384       Video::getInstance()->setMode(Video::QUARTER);
385       Video::getInstance()->setPosition(170, 5);
386       VEpg* vepg = new VEpg(NULL, 0);
387       vepg->draw();
388       BoxStack::getInstance()->add(vepg);
389       BoxStack::getInstance()->update(vepg);
390       */
391
392 //      return 2;
393 //    }
394
395 #endif
396
397   }
398
399   return 1;
400 }
401
402 void VVideoRec::doTeletext()
403 {
404   
405   bool exists=true;
406
407   
408   // Draw the teletxt
409   VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
410   if (vtxv==NULL) {
411        vtxv= new VTeletextView((player)->getTeletextDecoder(),this);
412       (player)->getTeletextDecoder()->registerTeletextView(vtxv);
413       exists=false;
414   }
415   vtxv->setSubtitleMode(true);
416   vtxv->draw();
417   draw();
418   
419   if (!exists) {
420       BoxStack::getInstance()->add(vtxv);
421   }
422   BoxStack::getInstance()->update(this);
423   BoxStack::getInstance()->update(vtxv); 
424 }
425
426 void VVideoRec::processMessage(Message* m)
427 {
428   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
429
430   if (m->message == Message::MOUSE_LBDOWN)
431   {
432     UINT x = (m->parameter>>16) - getScreenX();
433     UINT y = (m->parameter&0xFFFF) - getScreenY();
434
435     if (!barShowing)
436     {
437       BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
438     }
439     else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
440     {
441       int progBarXbase = barRegion.x + 300;
442       if (myRec->hasMarks())
443       {
444         MarkList* markList = myRec->getMarkList();
445         MarkList::iterator i;
446         Mark* loopMark = NULL;
447         int posPix;
448         ULONG lengthFrames;
449         if (myRec->recInfo->timerEnd > time(NULL))
450         {
451           // chasing playback
452           // Work out an approximate length in frames (good to 1s...)
453           lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
454         }
455         else
456         {
457           lengthFrames = player->getLengthFrames();
458         }
459         for(i = markList->begin(); i != markList->end(); i++)
460         {
461           loopMark = *i;
462           if (loopMark->pos)
463           {
464             posPix = 302 * loopMark->pos / lengthFrames;
465             rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
466             if (x>=barRegion.x + progBarXbase + 2 + posPix
467                 && x<=barRegion.x + progBarXbase + 2 + posPix+3
468                 && y>=barRegion.y + 12 - 2
469                 && y<=barRegion.y + 12 - 2+28)
470             {
471               player->jumpToMark(loopMark->pos);
472               doBar(3);
473               return;
474             }
475           }
476         }
477       }
478
479       if (x>=barRegion.x + progBarXbase + 24
480           && x<=barRegion.x + progBarXbase + 4 + 302
481           && y>=barRegion.y + 12 - 2
482           && y<=barRegion.y + 12 - 2+28)
483       {
484         int cx=x-(barRegion.x + progBarXbase + 4);
485         double percent=((double)cx)/302.*100.;
486         player->jumpToPercent(percent);
487         doBar(3);
488         return;
489         //  int progressWidth = 302 * currentFrameNum / lengthFrames;
490         //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
491       }
492     }
493     else
494     {
495       BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
496     }
497   }
498   else if (m->from == player)
499   {
500     if (m->message != Message::PLAYER_EVENT) return;
501     switch(m->parameter)
502     {
503       case Player::CONNECTION_LOST: // connection lost detected
504       {
505         // I can't handle this, send it to command
506         Message* m2 = new Message();
507         m2->to = Command::getInstance();
508         m2->message = Message::CONNECTION_LOST;
509         Command::getInstance()->postMessageNoLock(m2);
510         break;
511       }
512       case Player::STOP_PLAYBACK:
513       {
514         // FIXME Obselete ish - improve this
515         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
516         m2->to = Command::getInstance();
517         m2->message = Message::STOP_PLAYBACK;
518         Command::getInstance()->postMessageNoLock(m2);
519         break;
520       }
521       case Player::ASPECT43:
522       {
523         if (dowss)
524         {
525           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
526           wss.setWide(false);
527           wss.draw();
528           boxstack->update(this, &wssRegion);
529         }
530         break;
531       }
532       case Player::ASPECT169:
533       {
534         if (dowss)
535         {
536           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
537           wss.setWide(true);
538           wss.draw();
539           boxstack->update(this, &wssRegion);
540         }
541         break;
542       }
543     }
544   }
545   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
546   {
547     Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
548     player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16 );
549   }
550   else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
551   {
552       Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
553       int type=((m->parameter & 0xFF0000)>>16);
554       switch (type) {
555       case 0x10: { //dvbsubtitle
556           player->setSubtitleChannel((m->parameter & 0xFFFF));
557           player->turnSubtitlesOn(true);
558           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
559           if (vtxt && vtxt->isInSubtitleMode()) {
560               BoxStack::getInstance()->remove(vtxt);
561           }
562                  } break;
563       case 0xFF: { //nosubtitles
564           
565            player->turnSubtitlesOn(false);
566            VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
567            if (vtxt && vtxt->isInSubtitleMode()) {
568               BoxStack::getInstance()->remove(vtxt);
569            }  
570           
571                  } break;
572       case 0x11: { //videotext
573           player->turnSubtitlesOn(false);
574           doTeletext();
575           ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
576                  } break;
577       };
578       if (vas) {
579         BoxStack::getInstance()->update(vas);
580       }
581       BoxStack::getInstance()->update(this);
582
583       
584   } 
585   else if (m->message == Message::CHILD_CLOSE)
586   {
587     if (m->from == vas)
588     {
589       vas = NULL;
590       barVasHold = false;
591       if (!barGenHold && !barScanHold && !barVasHold) removeBar();
592     }
593   }
594 }
595
596 void VVideoRec::stopPlay()
597 {
598   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
599
600   removeBar();
601   Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");
602   player->stop();
603   Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");
604   vdr->stopStreaming();
605   Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");
606   delete player;
607
608   playing = false;
609
610   if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
611   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
612 }
613
614 void VVideoRec::toggleChopSides()
615 {
616   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
617
618   if (videoMode == Video::NORMAL)
619   {
620     videoMode = Video::LETTERBOX;
621     video->setMode(Video::LETTERBOX);
622   }
623   else
624   {
625     videoMode = Video::NORMAL;
626     video->setMode(Video::NORMAL);
627   }
628 }
629
630 void VVideoRec::doAudioSelector()
631 {
632   bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
633   bool* availableAc3AudioChannels = NULL;
634   bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();
635   int *availableTTxtpages = player->getTeletxtSubtitlePages();
636   int currentAudioChannel = player->getCurrentAudioChannel();
637   if (Audio::getInstance()->supportsAc3())
638   {
639       availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
640   }
641   int subtitleChannel=player->getCurrentSubtitleChannel();
642   int subtitleType=0x10;
643   if (!(player)->isSubtitlesOn()) {
644       if ((player)->getTeletextDecoder()->getTeletxtView() &&
645           (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
646           ) {
647               subtitleChannel=(player)->getTeletextDecoder()->getPage();
648               subtitleType=0x11;
649           
650       } else {
651           subtitleType=0xFF; //turnedOff
652           subtitleChannel=0;
653       }
654   }
655
656
657   vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,
658       subtitleChannel, subtitleType, myRec->recInfo);
659   vas->setBackgroundColour(barBlue);
660   vas->setPosition(0, barRegion.y - 120);
661
662 // pal 62, ntsc 57
663
664   barVasHold = true;
665   doBar(0);
666
667   vas->draw();
668   boxstack->add(vas);
669   boxstack->update(vas);
670 }
671
672 void VVideoRec::doBar(int action)
673 {
674   barShowing = true;
675
676   rectangle(barRegion, barBlue);
677
678   /* Work out what to display - choices:
679
680   Playing  >
681   Paused   ||
682   FFwd     >>
683   FBwd     <<
684
685   Specials, informed by parameter
686
687   Skip forward 10s    >|
688   Skip backward 10s   |<
689   Skip forward 1m     >>|
690   Skip backward 1m    |<<
691
692   */
693
694   WSymbol w;
695   TEMPADD(&w);
696   w.nextSymbol = 0;
697   w.setPosition(barRegion.x + 66, barRegion.y + 16);
698
699   UCHAR playerState = 0;
700
701   if (action)
702   {
703     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
704     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
705     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
706     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
707   }
708   else
709   {
710     playerState = player->getState();
711     if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
712     else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
713     else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
714     else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
715     else                                       w.nextSymbol = WSymbol::PLAY;
716   }
717
718   w.draw();
719
720   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
721   {
722     // draw blips to show how fast the scan is
723     UCHAR scanrate = player->getIScanRate();
724     if (scanrate >= 2)
725     {
726       char text[5];
727       SNPRINTF(text, 5, "%ux", scanrate);
728       drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
729     }
730   }
731
732   drawBarClocks();
733
734   boxstack->update(this, &barRegion);
735
736   timers->cancelTimer(this, 1);
737
738
739   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
740   else barScanHold = false;
741
742   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
743
744   timers->setTimerD(this, 2, 0, 200000000);
745 }
746
747 void VVideoRec::timercall(int clientReference)
748 {
749   switch(clientReference)
750   {
751     case 1:
752     {
753       // Remove bar
754       removeBar();
755       break;
756     }
757     case 2:
758     {
759       // Update clock
760       if (!barShowing) break;
761       drawBarClocks();
762       boxstack->update(this, &barRegion);
763       
764       timers->setTimerD(this, 2, 0, 200000000);
765       break;
766     }
767   }
768 }
769
770 void VVideoRec::drawBarClocks()
771 {
772   if (barScanHold)
773   {
774     UCHAR playerState = player->getState();
775     // sticky bar is set if we are in ffwd/fbwd mode
776     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
777     // will repaint all the bar (it will call this function again, but
778     // this section won't run because stickyBarF will then == false)
779
780     if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
781     {
782       barScanHold = false;
783       doBar(0);
784       return; // doBar will call this function and do the rest
785     }
786   }
787
788   Log* logger = Log::getInstance();
789   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
790
791   // Draw RTC
792   // Blank the area first
793   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
794   char timeString[20];
795   time_t t;
796   time(&t);
797   struct tm* tms = localtime(&t);
798   strftime(timeString, 19, "%H:%M", tms);
799   drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
800
801   // Draw clocks
802
803   rectangle(clocksRegion, barBlue);
804
805   ULONG currentFrameNum = player->getCurrentFrameNum();
806   ULONG lengthFrames;
807   if (myRec->recInfo->timerEnd > time(NULL))
808   {
809     // chasing playback
810     // Work out an approximate length in frames (good to 1s...)
811     lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
812   }
813   else
814   {
815     lengthFrames = player->getLengthFrames();
816   }
817
818   hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
819   hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
820
821   char buffer[100];
822   if (currentFrameNum >= lengthFrames)
823   {
824     strcpy(buffer, "-:--:-- / -:--:--");
825   }
826   else
827   {
828     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
829     logger->log("VVideoRec", Log::DEBUG, buffer);
830   }
831
832   drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
833
834
835
836
837
838
839
840   // Draw progress bar
841   int progBarXbase = barRegion.x + 300;
842
843   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
844   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
845
846   if (currentFrameNum > lengthFrames) return;
847   if (lengthFrames == 0) return;
848
849   // Draw yellow portion
850   int progressWidth = 302 * currentFrameNum / lengthFrames;
851   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
852
853   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
854   {
855     int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
856
857     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
858     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
859     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
860     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
861   }
862
863   int posPix;
864   // Now calc position for blips
865
866   if (myRec->hasMarks())
867   {
868     // Draw blips where there are cut marks
869     MarkList* markList = myRec->getMarkList();
870     MarkList::iterator i;
871     Mark* loopMark = NULL;
872
873     for(i = markList->begin(); i != markList->end(); i++)
874     {
875       loopMark = *i;
876       if (loopMark->pos)
877       {
878         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
879         posPix = 302 * loopMark->pos / lengthFrames;
880         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
881       }
882     }
883   }
884   else
885   {
886     // Draw blips where start and end margins probably are
887
888     posPix = 302 * startMargin * video->getFPS() / lengthFrames;
889
890     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
891     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
892
893     posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames;
894
895     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
896     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
897   }
898 }
899
900 void VVideoRec::removeBar()
901 {
902   if (!barShowing) return;
903   timers->cancelTimer(this, 2);
904   barShowing = false;
905   barGenHold = false;
906   barScanHold = false;
907   barVasHold = false;
908   rectangle(barRegion, transparent);
909   boxstack->update(this, &barRegion);
910 }
911
912 void VVideoRec::doSummary()
913 {
914   vsummary = new VInfo();
915   vsummary->setTitleText(myRec->getProgName());
916   vsummary->setBorderOn(1);
917   vsummary->setExitable();
918   if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);
919   else vsummary->setMainText(tr("Summary unavailable"));
920   if (Video::getInstance()->getFormat() == Video::PAL)
921   {
922     vsummary->setPosition(120, 130);
923   }
924   else
925   {
926     vsummary->setPosition(110, 90);
927   }
928   vsummary->setSize(510, 270);
929   add(vsummary);
930   vsummary->draw();
931
932   BoxStack::getInstance()->update(this);
933 }
934
935 void VVideoRec::removeSummary()
936 {
937   if (vsummary)
938   {
939     remove(vsummary);
940     delete vsummary;
941     vsummary = NULL;
942     draw();
943     BoxStack::getInstance()->update(this);
944   }
945 }
946
947 void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm)
948 {
949   drawBitmap(posX, posY, bm);
950   Region r;
951   r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
952   boxstack->update(this, &r);
953 }
954
955 void VVideoRec::clearOSD()
956 {
957   rectangle(area, transparent);
958   boxstack->update(this, &area);
959 }
960
961 void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height)
962 {
963   Region r;
964   r.x = posX; r.y = posY; r.w = width; r.h = height;
965   rectangle(r, transparent);
966   boxstack->update(this, &r);
967 }