]> git.vomp.tv Git - vompclient.git/blob - vvideorec.cc
Fix for possible crash when removing bar
[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
210       return 4;
211     }
212     case Remote::PAUSE:
213     {
214       player->pause();
215       doBar(0);
216       return 2;
217     }
218     case Remote::SKIPFORWARD:
219     {
220       doBar(3);
221       player->skipForward(60);
222       return 2;
223     }
224     case Remote::SKIPBACK:
225     {
226       doBar(4);
227       player->skipBackward(60);
228       return 2;
229     }
230     case Remote::FORWARD:
231     {
232       player->fastForward();
233       doBar(0);
234       return 2;
235     }
236     case Remote::REVERSE:
237     {
238       player->fastBackward();
239       doBar(0);
240       return 2;
241     }
242     case Remote::YELLOW:
243     {
244       if (myRec->hasMarks())
245       {
246         // skip to previous mark
247         Log* logger = Log::getInstance();
248         int currentFrame = (player->getCurrentFrameNum()); // get current Frame
249         currentFrame -= 5 * video->getFPS(); // subtrack 5 seconds, else you cannot skip more than once back ..
250
251         int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
252         if (prevMark)
253         {
254           logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
255           player->jumpToMark(prevMark);
256         }
257         doBar(4);
258       }
259       else
260       {
261         doBar(2);
262         player->skipBackward(10);
263       }
264       return 2;
265     }
266     case Remote::BLUE:
267     {
268       if (myRec->hasMarks())
269       {
270         // skip to next mark
271         Log* logger = Log::getInstance();
272         int currentFrame = (player->getCurrentFrameNum());
273
274         int nextMark = myRec->getNextMark(currentFrame);
275
276         if (nextMark)
277         {
278           logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
279           player->jumpToMark(nextMark);
280         }
281         doBar(3);
282       }
283       else
284       {
285         doBar(1);
286         player->skipForward(10);
287       }
288       return 2;
289     }
290     case Remote::STAR:
291     {
292       doBar(2);
293       player->skipBackward(10);
294       return 2;
295     }
296     case Remote::HASH:
297     {
298       doBar(1);
299       player->skipForward(10);
300       return 2;
301     }
302     case Remote::GREEN:
303     {
304       doAudioSelector();
305       return 2;
306     }
307     case Remote::FULL:
308     case Remote::TV:
309     {
310       toggleChopSides();
311       return 2;
312     }
313
314     case Remote::OK:
315     {
316       if (barShowing) removeBar();
317       else doBar(0);
318       return 2;
319     }
320
321     case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
322     case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
323     case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
324     case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
325     case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
326     case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
327     case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
328     case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
329     case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
330     case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
331
332 #ifdef DEV
333     case Remote::RED:
334     {
335       //Don't use RED for anything. It will eventually be recording summary
336
337       //player->test1();
338
339
340       /*
341       // for testing EPG in NTSC with a NTSC test video
342       Video::getInstance()->setMode(Video::QUARTER);
343       Video::getInstance()->setPosition(170, 5);
344       VEpg* vepg = new VEpg(NULL, 0);
345       vepg->draw();
346       ViewMan::getInstance()->add(vepg);
347       ViewMan::getInstance()->updateView(vepg);
348       */
349
350       return 2;
351     }
352
353 #endif
354
355   }
356
357   return 1;
358 }
359
360 void VVideoRec::processMessage(Message* m)
361 {
362   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
363
364   if (m->message == Message::MOUSE_LBDOWN)
365   {
366     UINT x = (m->parameter>>16) - getScreenX();
367     UINT y = (m->parameter&0xFFFF) - getScreenY();
368
369     if (!barShowing)
370     {
371       ViewMan::getInstance()->handleCommand(Remote::OK); //simulate rok press
372     }
373     else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
374     {
375       int progBarXbase = barRegion.x + 300;
376       if (myRec->hasMarks())
377       {
378         MarkList* markList = myRec->getMarkList();
379         MarkList::iterator i;
380         Mark* loopMark = NULL;
381         int posPix;
382         ULONG lengthFrames;
383         if (myRec->recInfo->timerEnd > time(NULL))
384         {
385           // chasing playback
386           // Work out an approximate length in frames (good to 1s...)
387           lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
388         }
389         else
390         {
391           lengthFrames = player->getLengthFrames();
392         }
393         for(i = markList->begin(); i != markList->end(); i++)
394         {
395           loopMark = *i;
396           if (loopMark->pos)
397           {
398             posPix = 302 * loopMark->pos / lengthFrames;
399             rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
400             if (x>=barRegion.x + progBarXbase + 2 + posPix
401                 && x<=barRegion.x + progBarXbase + 2 + posPix+3
402                 && y>=barRegion.y + 12 - 2
403                 && y<=barRegion.y + 12 - 2+28)
404             {
405               player->jumpToMark(loopMark->pos);
406               doBar(3);
407               return;
408             }
409           }
410         }
411       }
412
413       if (x>=barRegion.x + progBarXbase + 24
414           && x<=barRegion.x + progBarXbase + 4 + 302
415           && y>=barRegion.y + 12 - 2
416           && y<=barRegion.y + 12 - 2+28)
417       {
418         int cx=x-(barRegion.x + progBarXbase + 4);
419         double percent=((double)cx)/302.*100.;
420         player->jumpToPercent(percent);
421         doBar(3);
422         return;
423         //  int progressWidth = 302 * currentFrameNum / lengthFrames;
424         //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
425       }
426     }
427     else
428     {
429       ViewMan::getInstance()->handleCommand(Remote::OK); //simulate rok press
430     }
431   }
432   else if (m->from == player)
433   {
434     if (m->message != Message::PLAYER_EVENT) return;
435     switch(m->parameter)
436     {
437       case Player::CONNECTION_LOST: // connection lost detected
438       {
439         // I can't handle this, send it to command
440         Message* m2 = new Message();
441         m2->to = Command::getInstance();
442         m2->message = Message::CONNECTION_LOST;
443         Command::getInstance()->postMessageNoLock(m2);
444         break;
445       }
446       case Player::STOP_PLAYBACK:
447       {
448         // FIXME Obselete ish - improve this
449         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
450         m2->to = Command::getInstance();
451         m2->message = Message::STOP_PLAYBACK;
452         Command::getInstance()->postMessageNoLock(m2);
453         break;
454       }
455       case Player::ASPECT43:
456       {
457         if (dowss)
458         {
459           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
460           wss.setWide(false);
461           wss.draw();
462           viewman->updateView(this, &wssRegion);
463         }
464         break;
465       }
466       case Player::ASPECT169:
467       {
468         if (dowss)
469         {
470           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
471           wss.setWide(true);
472           wss.draw();
473           viewman->updateView(this, &wssRegion);
474         }
475         break;
476       }
477     }
478   }
479   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
480   {
481     Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
482     player->setAudioChannel(m->parameter);
483   }
484   else if (m->message == Message::CHILD_CLOSE)
485   {
486     if (m->from == vas)
487     {
488       vas = NULL;
489       barVasHold = false;
490       if (!barGenHold && !barScanHold && !barVasHold) removeBar();
491     }
492   }
493 }
494
495 void VVideoRec::stopPlay()
496 {
497   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
498
499   // FIXME work out a better soln for this
500   // Fix a problem to do with thread sync here
501   // because the bar gets a timer every 0.2s and it seems to take up to 0.1s,
502   // (or maybe just the wrong thread being selected?) for the main loop to lock and process
503   // the video stop message it is possible for a bar message to stack up after a stop message
504   // when the bar message is finally processed the prog crashes because this is deleted by then
505   removeBar();
506   //
507
508   player->stop();
509   vdr->stopStreaming();
510   delete player;
511
512   playing = false;
513
514   if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
515   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
516 }
517
518 void VVideoRec::toggleChopSides()
519 {
520   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
521
522   if (videoMode == Video::NORMAL)
523   {
524     videoMode = Video::LETTERBOX;
525     video->setMode(Video::LETTERBOX);
526   }
527   else
528   {
529     videoMode = Video::NORMAL;
530     video->setMode(Video::NORMAL);
531   }
532 }
533
534 void VVideoRec::doAudioSelector()
535 {
536   bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
537   bool* availableAc3AudioChannels = 0;
538   int currentAudioChannel = player->getCurrentAudioChannel();
539   if (Audio::getInstance()->supportsAc3())
540   {
541       availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
542   }
543
544   vas = new VAudioSelector(this, availableMpegAudioChannels,availableAc3AudioChannels, currentAudioChannel, myRec->recInfo);
545   vas->setBackgroundColour(barBlue);
546   if (video->getFormat() == Video::PAL)
547   {
548 //    vas->setScreenPos(62, barRegion.y - 120);
549     vas->setScreenPos(0, barRegion.y - 120);
550   }
551   else
552   {
553 //    vas->setScreenPos(57, barRegion.y - 120);
554     vas->setScreenPos(0, barRegion.y - 120);
555   }
556
557   barVasHold = true;
558   doBar(0);
559
560   vas->draw();
561   viewman->add(vas);
562   viewman->updateView(vas);
563 }
564
565 void VVideoRec::doBar(int action)
566 {
567   barShowing = true;
568
569   rectangle(barRegion, barBlue);
570
571   /* Work out what to display - choices:
572
573   Playing  >
574   Paused   ||
575   FFwd     >>
576   FBwd     <<
577
578   Specials, informed by parameter
579
580   Skip forward 10s    >|
581   Skip backward 10s   |<
582   Skip forward 1m     >>|
583   Skip backward 1m    |<<
584
585   */
586
587   WSymbol w;
588   w.setSurface(surface);
589   w.nextSymbol = 0;
590   w.setSurfaceOffset(barRegion.x + 66, barRegion.y + 16);
591
592   UCHAR playerState = 0;
593
594   if (action)
595   {
596     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
597     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
598     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
599     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
600   }
601   else
602   {
603     playerState = player->getState();
604     if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
605     else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
606     else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
607     else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
608     else                                       w.nextSymbol = WSymbol::PLAY;
609   }
610
611   w.draw();
612
613   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
614   {
615     // draw blips to show how fast the scan is
616     UCHAR scanrate = player->getIScanRate();
617     if (scanrate >= 2)
618     {
619       char text[5];
620       SNPRINTF(text, 5, "%ux", scanrate);
621       drawText(text, barRegion.x + 102, barRegion.y + 12, Colour::LIGHTTEXT);
622     }
623   }
624
625   drawBarClocks();
626
627   viewman->updateView(this, &barRegion);
628
629   timers->cancelTimer(this, 1);
630
631
632   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
633   else barScanHold = false;
634
635   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
636
637   timers->setTimerD(this, 2, 0, 200000000);
638 }
639
640 void VVideoRec::timercall(int clientReference)
641 {
642   switch(clientReference)
643   {
644     case 1:
645     {
646       // Remove bar
647       removeBar();
648       break;
649     }
650     case 2:
651     {
652       // Update clock
653       if (!barShowing) break;
654       drawBarClocks();
655       Message* m = new Message();
656       m->message = Message::REDRAW;
657       m->to = ViewMan::getInstance();
658       m->from = this;
659       m->parameter = (ULONG)&barRegion;
660       Command::getInstance()->postMessageFromOuterSpace(m);
661       timers->setTimerD(this, 2, 0, 200000000);
662       break;
663     }
664   }
665 }
666
667 void VVideoRec::drawBarClocks()
668 {
669   if (barScanHold)
670   {
671     UCHAR playerState = player->getState();
672     // sticky bar is set if we are in ffwd/fbwd mode
673     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
674     // will repaint all the bar (it will call this function again, but
675     // this section won't run because stickyBarF will then == false)
676
677     if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
678     {
679       barScanHold = false;
680       doBar(0);
681       return; // doBar will call this function and do the rest
682     }
683   }
684
685   Log* logger = Log::getInstance();
686   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
687
688   // Draw RTC
689   // Blank the area first
690   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
691   char timeString[20];
692   time_t t;
693   time(&t);
694   struct tm* tms = localtime(&t);
695   strftime(timeString, 19, "%H:%M", tms);
696   drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
697
698   // Draw clocks
699
700   rectangle(clocksRegion, barBlue);
701
702   ULONG currentFrameNum = player->getCurrentFrameNum();
703   ULONG lengthFrames;
704   if (myRec->recInfo->timerEnd > time(NULL))
705   {
706     // chasing playback
707     // Work out an approximate length in frames (good to 1s...)
708     lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
709   }
710   else
711   {
712     lengthFrames = player->getLengthFrames();
713   }
714
715   hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
716   hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
717
718   char buffer[100];
719   if (currentFrameNum >= lengthFrames)
720   {
721     strcpy(buffer, "-:--:-- / -:--:--");
722   }
723   else
724   {
725     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
726     logger->log("VVideoRec", Log::DEBUG, buffer);
727   }
728
729   drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
730
731
732
733
734
735
736
737   // Draw progress bar
738   int progBarXbase = barRegion.x + 300;
739
740   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
741   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
742
743   if (currentFrameNum > lengthFrames) return;
744   if (lengthFrames == 0) return;
745
746   // Draw yellow portion
747   int progressWidth = 302 * currentFrameNum / lengthFrames;
748   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
749
750   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
751   {
752     int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
753
754     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
755     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
756     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
757     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
758   }
759
760   int posPix;
761   // Now calc position for blips
762
763   if (myRec->hasMarks())
764   {
765     // Draw blips where there are cut marks
766     MarkList* markList = myRec->getMarkList();
767     MarkList::iterator i;
768     Mark* loopMark = NULL;
769
770     for(i = markList->begin(); i != markList->end(); i++)
771     {
772       loopMark = *i;
773       if (loopMark->pos)
774       {
775         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
776         posPix = 302 * loopMark->pos / lengthFrames;
777         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, Colour::DANGER);
778       }
779     }
780   }
781   else
782   {
783     // Draw blips where start and end margins probably are
784
785     posPix = 302 * startMargin * video->getFPS() / lengthFrames;
786
787     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
788     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
789
790     posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames;
791
792     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
793     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
794   }
795 }
796
797 void VVideoRec::removeBar()
798 {
799   if (!barShowing) return;
800   timers->cancelTimer(this, 2);
801   barShowing = false;
802   barGenHold = false;
803   barScanHold = false;
804   barVasHold = false;
805   rectangle(barRegion, transparent);
806
807   Message* m = new Message();
808   m->message = Message::REDRAW;
809   m->to = ViewMan::getInstance();
810   m->from = this;
811   m->parameter = (ULONG)&barRegion;
812   Command::getInstance()->postMessageFromOuterSpace(m);
813 }