]> git.vomp.tv Git - vompclient.git/blob - vvideorec.cc
Translation updates
[vompclient.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "vvideorec.h"
22
23 VVideoRec::VVideoRec(Recording* rec)
24 {
25   viewman = ViewMan::getInstance();
26   vdr = VDR::getInstance();
27   video = Video::getInstance();
28   timers = Timers::getInstance();
29   vas = NULL;
30
31   player = new Player(Command::getInstance(), this, true);
32   player->init();
33
34   videoMode = video->getMode();
35   myRec = rec;
36
37   playing = false;
38
39   startMargin = 0;
40   endMargin = 0;
41   char* cstartMargin = vdr->configLoad("Timers", "Start margin");
42   char* cendMargin = vdr->configLoad("Timers", "End margin");
43   if (!cstartMargin)
44   {
45     startMargin = 300; // 5 mins default
46   }
47   else
48   {
49     startMargin = atoi(cstartMargin) * 60;
50     delete[] cstartMargin;
51   }
52
53   if (!cendMargin)
54   {
55     endMargin = 300; // 5 mins default
56   }
57   else
58   {
59     endMargin = atoi(cendMargin) * 60;
60     delete[] cendMargin;
61   }
62
63   Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
64
65   create(video->getScreenWidth(), video->getScreenHeight());
66   transparent.set(0, 0, 0, 0);
67   setBackgroundColour(transparent);
68
69   barRegion.x = 0;
70   barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
71   barRegion.w = video->getScreenWidth();
72   barRegion.h = 58;
73
74   clocksRegion.x = barRegion.x + 140;
75   clocksRegion.y = barRegion.y + 12;
76   clocksRegion.w = 170;
77   clocksRegion.h = surface->getFontHeight();
78
79
80   barBlue.set(0, 0, 150, 150);
81
82   barShowing = false;
83   barGenHold = false;
84   barScanHold = false;
85   barVasHold = false;
86
87   dowss = false;
88   char* optionWSS = vdr->configLoad("General", "WSS");
89   if (optionWSS)
90   {
91     if (strstr(optionWSS, "Yes")) dowss = true;
92     delete[] optionWSS;
93   }
94   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);
95
96   wss.setFormat(video->getFormat());
97   wss.setSurface(surface);
98   wss.setWide(true);
99
100 /*
101   wssRegion.x = 0;
102   wssRegion.y = 6;
103   wssRegion.w = video->getScreenWidth();
104   wssRegion.h = 2;
105 */
106   wssRegion.x = 0;
107   wssRegion.y = 0;
108   wssRegion.w = video->getScreenWidth();
109   wssRegion.h = 300;
110 }
111
112 VVideoRec::~VVideoRec()
113 {
114   if (vas)
115   {
116     viewman->removeView(vas);
117     vas = NULL;
118   }
119
120   if (playing) stopPlay();
121   video->setDefaultAspect();
122
123   timers->cancelTimer(this, 1);
124   timers->cancelTimer(this, 2);
125
126   // kill recInfo in case resumePoint has changed (likely)
127   myRec->dropRecInfo();
128   // FIXME - do this properly - save the resume point back to the server manually and update
129   // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
130 }
131
132 void VVideoRec::draw()
133 {
134   View::draw();
135 }
136
137 void VVideoRec::go(bool resume)
138 {
139   ULONG startFrameNum;
140   if (resume)
141     startFrameNum = myRec->recInfo->resumePoint;
142   else
143     startFrameNum = 0;
144
145   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);
146   ULONG lengthFrames = 0;
147   ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames);
148   if (lengthBytes)
149   {
150     player->setLengthBytes(lengthBytes);
151     player->setLengthFrames(lengthFrames);
152     player->setStartFrame(startFrameNum);
153     player->play();
154     playing = true;
155     doBar(0);
156   }
157   else
158   {
159     stopPlay(); // clean up
160
161     if (!vdr->isConnected())
162     {
163       Command::getInstance()->connectionLost();
164       return;
165     }
166
167     Message* m = new Message();
168     m->message = Message::CLOSE_ME;
169     m->from = this;
170     m->to = viewman;
171     Command::getInstance()->postMessageNoLock(m);
172
173     VInfo* vi = new VInfo();
174     vi->create(400, 150);
175     if (video->getFormat() == Video::PAL)
176       vi->setScreenPos(170, 200);
177     else
178       vi->setScreenPos(160, 150);
179     vi->setExitable();
180     vi->setBorderOn(1);
181     vi->setTitleBarOn(0);
182     vi->setOneLiner(tr("Error playing recording"));
183     vi->draw();
184
185     m = new Message();
186     m->message = Message::ADD_VIEW;
187     m->to = viewman;
188     m->parameter = (ULONG)vi;
189     Command::getInstance()->postMessageNoLock(m);
190   }
191 }
192
193 int VVideoRec::handleCommand(int command)
194 {
195   switch(command)
196   {
197     case Remote::PLAY:
198     {
199       player->play();
200       doBar(0);
201       return 2;
202     }
203
204     case Remote::STOP:
205     case Remote::BACK:
206     case Remote::MENU:
207     {
208       if (playing) stopPlay();
209       return 4;
210     }
211     case Remote::PAUSE:
212     {
213       player->pause();
214       doBar(0);
215       return 2;
216     }
217     case Remote::SKIPFORWARD:
218     {
219       doBar(3);
220       player->skipForward(60);
221       return 2;
222     }
223     case Remote::SKIPBACK:
224     {
225       doBar(4);
226       player->skipBackward(60);
227       return 2;
228     }
229     case Remote::FORWARD:
230     {
231       player->fastForward();
232       doBar(0);
233       return 2;
234     }
235     case Remote::REVERSE:
236     {
237       player->fastBackward();
238       doBar(0);
239       return 2;
240     }
241     case Remote::YELLOW:
242     {
243       if (myRec->hasMarks())
244       {
245         // skip to previous mark
246         Log* logger = Log::getInstance();
247         int currentFrame = (player->getCurrentFrameNum()); // get current Frame
248         currentFrame -= 5 * video->getFPS(); // subtrack 5 seconds, else you cannot skip more than once back ..
249
250         int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
251         if (prevMark)
252         {
253           logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
254           player->jumpToMark(prevMark);
255         }
256         doBar(4);
257       }
258       else
259       {
260         doBar(2);
261         player->skipBackward(10);
262       }
263       return 2;
264     }
265     case Remote::BLUE:
266     {
267       if (myRec->hasMarks())
268       {
269         // skip to next mark
270         Log* logger = Log::getInstance();
271         int currentFrame = (player->getCurrentFrameNum());
272
273         int nextMark = myRec->getNextMark(currentFrame);
274
275         if (nextMark)
276         {
277           logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
278           player->jumpToMark(nextMark);
279         }
280         doBar(3);
281       }
282       else
283       {
284         doBar(1);
285         player->skipForward(10);
286       }
287       return 2;
288     }
289     case Remote::STAR:
290     {
291       doBar(2);
292       player->skipBackward(10);
293       return 2;
294     }
295     case Remote::HASH:
296     {
297       doBar(1);
298       player->skipForward(10);
299       return 2;
300     }
301     case Remote::GREEN:
302     {
303       doAudioSelector();
304       return 2;
305     }
306     case Remote::FULL:
307     case Remote::TV:
308     {
309       toggleChopSides();
310       return 2;
311     }
312
313     case Remote::OK:
314     {
315       if (barShowing) removeBar();
316       else doBar(0);
317       return 2;
318     }
319
320     case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
321     case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
322     case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
323     case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
324     case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
325     case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
326     case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
327     case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
328     case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
329     case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
330
331 #ifdef DEV
332     case Remote::RED:
333     {
334       //Don't use RED for anything. It will eventually be recording summary
335
336       //player->test1();
337
338
339       /*
340       // for testing EPG in NTSC with a NTSC test video
341       Video::getInstance()->setMode(Video::QUARTER);
342       Video::getInstance()->setPosition(170, 5);
343       VEpg* vepg = new VEpg(NULL, 0);
344       vepg->draw();
345       ViewMan::getInstance()->add(vepg);
346       ViewMan::getInstance()->updateView(vepg);
347       */
348
349       return 2;
350     }
351
352 #endif
353
354   }
355
356   return 1;
357 }
358
359 void VVideoRec::processMessage(Message* m)
360 {
361   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
362
363   if (m->message == Message::MOUSE_LBDOWN)
364   {
365     UINT x = (m->parameter>>16) - getScreenX();
366     UINT y = (m->parameter&0xFFFF) - getScreenY();
367
368     if (!barShowing)
369     {
370       ViewMan::getInstance()->handleCommand(Remote::OK); //simulate rok press
371     }
372     else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
373     {
374       int progBarXbase = barRegion.x + 300;
375       if (myRec->hasMarks())
376       {
377         MarkList* markList = myRec->getMarkList();
378         MarkList::iterator i;
379         Mark* loopMark = NULL;
380         int posPix;
381         ULONG lengthFrames;
382         if (myRec->recInfo->timerEnd > time(NULL))
383         {
384           // chasing playback
385           // Work out an approximate length in frames (good to 1s...)
386           lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
387         }
388         else
389         {
390           lengthFrames = player->getLengthFrames();
391         }
392         for(i = markList->begin(); i != markList->end(); i++)
393         {
394           loopMark = *i;
395           if (loopMark->pos)
396           {
397             posPix = 302 * loopMark->pos / lengthFrames;
398             rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
399             if (x>=barRegion.x + progBarXbase + 2 + posPix
400                 && x<=barRegion.x + progBarXbase + 2 + posPix+3
401                 && y>=barRegion.y + 12 - 2
402                 && y<=barRegion.y + 12 - 2+28)
403             {
404               player->jumpToMark(loopMark->pos);
405               doBar(3);
406               return;
407             }
408           }
409         }
410       }
411
412       if (x>=barRegion.x + progBarXbase + 24
413           && x<=barRegion.x + progBarXbase + 4 + 302
414           && y>=barRegion.y + 12 - 2
415           && y<=barRegion.y + 12 - 2+28)
416       {
417         int cx=x-(barRegion.x + progBarXbase + 4);
418         double percent=((double)cx)/302.*100.;
419         player->jumpToPercent(percent);
420         doBar(3);
421         return;
422         //  int progressWidth = 302 * currentFrameNum / lengthFrames;
423         //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
424       }
425     }
426     else
427     {
428       ViewMan::getInstance()->handleCommand(Remote::OK); //simulate rok press
429     }
430   }
431   else if (m->from == player)
432   {
433     if (m->message != Message::PLAYER_EVENT) return;
434     switch(m->parameter)
435     {
436       case Player::CONNECTION_LOST: // connection lost detected
437       {
438         // I can't handle this, send it to command
439         Message* m2 = new Message();
440         m2->to = Command::getInstance();
441         m2->message = Message::CONNECTION_LOST;
442         Command::getInstance()->postMessageNoLock(m2);
443         break;
444       }
445       case Player::STOP_PLAYBACK:
446       {
447         // FIXME Obselete ish - improve this
448         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
449         m2->to = Command::getInstance();
450         m2->message = Message::STOP_PLAYBACK;
451         Command::getInstance()->postMessageNoLock(m2);
452         break;
453       }
454       case Player::ASPECT43:
455       {
456         if (dowss)
457         {
458           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
459           wss.setWide(false);
460           wss.draw();
461           viewman->updateView(this, &wssRegion);
462         }
463         break;
464       }
465       case Player::ASPECT169:
466       {
467         if (dowss)
468         {
469           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
470           wss.setWide(true);
471           wss.draw();
472           viewman->updateView(this, &wssRegion);
473         }
474         break;
475       }
476     }
477   }
478   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
479   {
480     Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
481     player->setAudioChannel(m->parameter);
482   }
483   else if (m->message == Message::CHILD_CLOSE)
484   {
485     if (m->from == vas)
486     {
487       vas = NULL;
488       barVasHold = false;
489       if (!barGenHold && !barScanHold && !barVasHold) removeBar();
490     }
491   }
492 }
493
494 void VVideoRec::stopPlay()
495 {
496   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
497
498   // FIXME work out a better soln for this
499   // Fix a problem to do with thread sync here
500   // because the bar gets a timer every 0.2s and it seems to take up to 0.1s,
501   // (or maybe just the wrong thread being selected?) for the main loop to lock and process
502   // the video stop message it is possible for a bar message to stack up after a stop message
503   // when the bar message is finally processed the prog crashes because this is deleted by then
504   removeBar();
505   //
506
507   player->stop();
508   vdr->stopStreaming();
509   delete player;
510
511   playing = false;
512
513   if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
514   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
515 }
516
517 void VVideoRec::toggleChopSides()
518 {
519   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
520
521   if (videoMode == Video::NORMAL)
522   {
523     videoMode = Video::LETTERBOX;
524     video->setMode(Video::LETTERBOX);
525   }
526   else
527   {
528     videoMode = Video::NORMAL;
529     video->setMode(Video::NORMAL);
530   }
531 }
532
533 void VVideoRec::doAudioSelector()
534 {
535   bool* availableAudioChannels = player->getDemuxerAudioChannels();
536   int currentAudioChannel = player->getCurrentAudioChannel();
537
538   vas = new VAudioSelector(this, availableAudioChannels, currentAudioChannel, myRec->recInfo);
539   vas->setBackgroundColour(barBlue);
540   if (video->getFormat() == Video::PAL)
541   {
542 //    vas->setScreenPos(62, barRegion.y - 120);
543     vas->setScreenPos(0, barRegion.y - 120);
544   }
545   else
546   {
547 //    vas->setScreenPos(57, barRegion.y - 120);
548     vas->setScreenPos(0, barRegion.y - 120);
549   }
550
551   barVasHold = true;
552   doBar(0);
553
554   vas->draw();
555   viewman->add(vas);
556   viewman->updateView(vas);
557 }
558
559 void VVideoRec::doBar(int action)
560 {
561   barShowing = true;
562
563   rectangle(barRegion, barBlue);
564
565   /* Work out what to display - choices:
566
567   Playing  >
568   Paused   ||
569   FFwd     >>
570   FBwd     <<
571
572   Specials, informed by parameter
573
574   Skip forward 10s    >|
575   Skip backward 10s   |<
576   Skip forward 1m     >>|
577   Skip backward 1m    |<<
578
579   */
580
581   WSymbol w;
582   w.setSurface(surface);
583   w.nextSymbol = 0;
584   w.setSurfaceOffset(barRegion.x + 66, barRegion.y + 16);
585
586   UCHAR playerState = 0;
587
588   if (action)
589   {
590     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
591     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
592     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
593     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
594   }
595   else
596   {
597     playerState = player->getState();
598     if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
599     else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
600     else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
601     else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
602     else                                       w.nextSymbol = WSymbol::PLAY;
603   }
604
605   w.draw();
606
607   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
608   {
609     // draw blips to show how fast the scan is
610     UCHAR scanrate = player->getIScanRate();
611     if (scanrate >= 2)
612     {
613       char* text = new char[5];
614       SNPRINTF(text, 5, "%ux", scanrate);
615       drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
616     }
617   }
618
619   drawBarClocks();
620
621   viewman->updateView(this, &barRegion);
622
623   timers->cancelTimer(this, 1);
624
625
626   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
627   else barScanHold = false;
628
629   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
630
631   timers->setTimerD(this, 2, 0, 200000000);
632 }
633
634 void VVideoRec::timercall(int clientReference)
635 {
636   switch(clientReference)
637   {
638     case 1:
639     {
640       // Remove bar
641       removeBar();
642       break;
643     }
644     case 2:
645     {
646       // Update clock
647       if (!barShowing) break;
648       drawBarClocks();
649       viewman->updateView(this, &barRegion);
650       timers->setTimerD(this, 2, 0, 200000000);
651       break;
652     }
653   }
654 }
655
656 void VVideoRec::drawBarClocks()
657 {
658   if (barScanHold)
659   {
660     UCHAR playerState = player->getState();
661     // sticky bar is set if we are in ffwd/fbwd mode
662     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
663     // will repaint all the bar (it will call this function again, but
664     // this section won't run because stickyBarF will then == false)
665
666     if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
667     {
668       barScanHold = false;
669       doBar(0);
670       return; // doBar will call this function and do the rest
671     }
672   }
673
674   Log* logger = Log::getInstance();
675   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
676
677   // Draw RTC
678   // Blank the area first
679   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
680   char timeString[20];
681   time_t t;
682   time(&t);
683   struct tm* tms = localtime(&t);
684   strftime(timeString, 19, "%H:%M", tms);
685   drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
686
687   // Draw clocks
688
689   rectangle(clocksRegion, barBlue);
690
691   ULONG currentFrameNum = player->getCurrentFrameNum();
692   ULONG lengthFrames;
693   if (myRec->recInfo->timerEnd > time(NULL))
694   {
695     // chasing playback
696     // Work out an approximate length in frames (good to 1s...)
697     lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
698   }
699   else
700   {
701     lengthFrames = player->getLengthFrames();
702   }
703
704   hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
705   hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
706
707   char buffer[100];
708   if (currentFrameNum >= lengthFrames)
709   {
710     strcpy(buffer, "-:--:-- / -:--:--");
711   }
712   else
713   {
714     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
715     logger->log("VVideoRec", Log::DEBUG, buffer);
716   }
717
718   drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
719
720
721
722
723
724
725
726   // Draw progress bar
727   int progBarXbase = barRegion.x + 300;
728
729   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
730   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
731
732   if (currentFrameNum > lengthFrames) return;
733   if (lengthFrames == 0) return;
734
735   // Draw yellow portion
736   int progressWidth = 302 * currentFrameNum / lengthFrames;
737   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
738
739   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
740   {
741     int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
742
743     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
744     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
745     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
746     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
747   }
748
749   int posPix;
750   // Now calc position for blips
751
752   if (myRec->hasMarks())
753   {
754     // Draw blips where there are cut marks
755     MarkList* markList = myRec->getMarkList();
756     MarkList::iterator i;
757     Mark* loopMark = NULL;
758
759     for(i = markList->begin(); i != markList->end(); i++)
760     {
761       loopMark = *i;
762       if (loopMark->pos)
763       {
764         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
765         posPix = 302 * loopMark->pos / lengthFrames;
766         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
767       }
768     }
769   }
770   else
771   {
772     // Draw blips where start and end margins probably are
773
774     posPix = 302 * startMargin * video->getFPS() / lengthFrames;
775
776     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
777     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
778
779     posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames;
780
781     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
782     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
783   }
784 }
785
786 void VVideoRec::removeBar()
787 {
788   if (!barShowing) return;
789   timers->cancelTimer(this, 2);
790   barShowing = false;
791   barGenHold = false;
792   barScanHold = false;
793   barVasHold = false;
794   rectangle(barRegion, transparent);
795   viewman->updateView(this, &barRegion);
796 }