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