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