]> git.vomp.tv Git - vompclient.git/blob - vvideorec.cc
Ac3 for Windows
[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* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
536   bool* availableAc3AudioChannels = 0;
537   int currentAudioChannel = player->getCurrentAudioChannel();
538   if (Audio::getInstance()->supportsAc3())
539   {
540       availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
541   }
542
543   vas = new VAudioSelector(this, availableMpegAudioChannels,availableAc3AudioChannels, currentAudioChannel, myRec->recInfo);
544   vas->setBackgroundColour(barBlue);
545   if (video->getFormat() == Video::PAL)
546   {
547 //    vas->setScreenPos(62, barRegion.y - 120);
548     vas->setScreenPos(0, barRegion.y - 120);
549   }
550   else
551   {
552 //    vas->setScreenPos(57, barRegion.y - 120);
553     vas->setScreenPos(0, barRegion.y - 120);
554   }
555
556   barVasHold = true;
557   doBar(0);
558
559   vas->draw();
560   viewman->add(vas);
561   viewman->updateView(vas);
562 }
563
564 void VVideoRec::doBar(int action)
565 {
566   barShowing = true;
567
568   rectangle(barRegion, barBlue);
569
570   /* Work out what to display - choices:
571
572   Playing  >
573   Paused   ||
574   FFwd     >>
575   FBwd     <<
576
577   Specials, informed by parameter
578
579   Skip forward 10s    >|
580   Skip backward 10s   |<
581   Skip forward 1m     >>|
582   Skip backward 1m    |<<
583
584   */
585
586   WSymbol w;
587   w.setSurface(surface);
588   w.nextSymbol = 0;
589   w.setSurfaceOffset(barRegion.x + 66, barRegion.y + 16);
590
591   UCHAR playerState = 0;
592
593   if (action)
594   {
595     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
596     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
597     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
598     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
599   }
600   else
601   {
602     playerState = player->getState();
603     if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
604     else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
605     else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
606     else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
607     else                                       w.nextSymbol = WSymbol::PLAY;
608   }
609
610   w.draw();
611
612   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
613   {
614     // draw blips to show how fast the scan is
615     UCHAR scanrate = player->getIScanRate();
616     if (scanrate >= 2)
617     {
618       char* text = new char[5];
619       SNPRINTF(text, 5, "%ux", scanrate);
620       drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
621     }
622   }
623
624   drawBarClocks();
625
626   viewman->updateView(this, &barRegion);
627
628   timers->cancelTimer(this, 1);
629
630
631   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
632   else barScanHold = false;
633
634   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
635
636   timers->setTimerD(this, 2, 0, 200000000);
637 }
638
639 void VVideoRec::timercall(int clientReference)
640 {
641   switch(clientReference)
642   {
643     case 1:
644     {
645       // Remove bar
646       removeBar();
647       break;
648     }
649     case 2:
650     {
651       // Update clock
652       if (!barShowing) break;
653       drawBarClocks();
654       viewman->updateView(this, &barRegion);
655       timers->setTimerD(this, 2, 0, 200000000);
656       break;
657     }
658   }
659 }
660
661 void VVideoRec::drawBarClocks()
662 {
663   if (barScanHold)
664   {
665     UCHAR playerState = player->getState();
666     // sticky bar is set if we are in ffwd/fbwd mode
667     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
668     // will repaint all the bar (it will call this function again, but
669     // this section won't run because stickyBarF will then == false)
670
671     if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
672     {
673       barScanHold = false;
674       doBar(0);
675       return; // doBar will call this function and do the rest
676     }
677   }
678
679   Log* logger = Log::getInstance();
680   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
681
682   // Draw RTC
683   // Blank the area first
684   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
685   char timeString[20];
686   time_t t;
687   time(&t);
688   struct tm* tms = localtime(&t);
689   strftime(timeString, 19, "%H:%M", tms);
690   drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
691
692   // Draw clocks
693
694   rectangle(clocksRegion, barBlue);
695
696   ULONG currentFrameNum = player->getCurrentFrameNum();
697   ULONG lengthFrames;
698   if (myRec->recInfo->timerEnd > time(NULL))
699   {
700     // chasing playback
701     // Work out an approximate length in frames (good to 1s...)
702     lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
703   }
704   else
705   {
706     lengthFrames = player->getLengthFrames();
707   }
708
709   hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
710   hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
711
712   char buffer[100];
713   if (currentFrameNum >= lengthFrames)
714   {
715     strcpy(buffer, "-:--:-- / -:--:--");
716   }
717   else
718   {
719     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
720     logger->log("VVideoRec", Log::DEBUG, buffer);
721   }
722
723   drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
724
725
726
727
728
729
730
731   // Draw progress bar
732   int progBarXbase = barRegion.x + 300;
733
734   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
735   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
736
737   if (currentFrameNum > lengthFrames) return;
738   if (lengthFrames == 0) return;
739
740   // Draw yellow portion
741   int progressWidth = 302 * currentFrameNum / lengthFrames;
742   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
743
744   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
745   {
746     int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
747
748     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
749     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
750     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
751     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
752   }
753
754   int posPix;
755   // Now calc position for blips
756
757   if (myRec->hasMarks())
758   {
759     // Draw blips where there are cut marks
760     MarkList* markList = myRec->getMarkList();
761     MarkList::iterator i;
762     Mark* loopMark = NULL;
763
764     for(i = markList->begin(); i != markList->end(); i++)
765     {
766       loopMark = *i;
767       if (loopMark->pos)
768       {
769         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
770         posPix = 302 * loopMark->pos / lengthFrames;
771         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
772       }
773     }
774   }
775   else
776   {
777     // Draw blips where start and end margins probably are
778
779     posPix = 302 * startMargin * 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     posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames;
785
786     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
787     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
788   }
789 }
790
791 void VVideoRec::removeBar()
792 {
793   if (!barShowing) return;
794   timers->cancelTimer(this, 2);
795   barShowing = false;
796   barGenHold = false;
797   barScanHold = false;
798   barVasHold = false;
799   rectangle(barRegion, transparent);
800   viewman->updateView(this, &barRegion);
801 }