]> git.vomp.tv Git - vompclient.git/blob - vvideorec.cc
DrawStyle: Add consts, add white and transparent statics
[vompclient.git] / vvideorec.cc
1 /*
2     Copyright 2004-2019 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <math.h>
21
22 #include "control.h"
23 #include "osd.h"
24 #include "wsymbol.h"
25 #include "audio.h"
26 #include "vdr.h"
27 #include "video.h"
28 #include "playervideorec.h"
29 #include "recording.h"
30 #include "vaudioselector.h"
31 #include "message.h"
32 #include "input.h"
33 #include "boxstack.h"
34 #include "vinfo.h"
35 #include "i18n.h"
36 #include "bitmap.h"
37 #include "recinfo.h"
38 #include "log.h"
39 #include "channel.h"
40 #include "vteletextview.h"
41 #include "messagequeue.h"
42
43 #include "vvideorec.h"
44
45 VVideoRec::VVideoRec(Recording* rec, bool ish264)
46 {
47   boxstack = BoxStack::getInstance();
48   vdr = VDR::getInstance();
49   video = Video::getInstance();
50   timers = Timers::getInstance();
51   vas = NULL;
52   vsummary = NULL;
53
54   videoMode = video->getMode();
55   myRec = rec;
56
57   video->seth264mode(ish264);
58
59   player = new PlayerVideoRec(Control::getInstance(), this, this);
60   player->init(myRec->IsPesRecording,myRec->recInfo->fps);
61
62   char* cstartMargin = vdr->configLoad("Timers", "Start margin"); // NCONFIG
63   char* cendMargin = vdr->configLoad("Timers", "End margin");
64   if (!cstartMargin)
65   {
66     startMargin = 300; // 5 mins default
67   }
68   else
69   {
70     startMargin = atoi(cstartMargin) * 60;
71     delete[] cstartMargin;
72   }
73
74   if (!cendMargin)
75   {
76     endMargin = 300; // 5 mins default
77   }
78   else
79   {
80     endMargin = atoi(cendMargin) * 60;
81     delete[] cendMargin;
82   }
83
84   Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
85
86   setSize(video->getScreenWidth(), video->getScreenHeight());
87   createBuffer();
88   setBackgroundColour(DrawStyle::TRANSPARENT);
89
90   OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
91   if (osdv)
92   {
93     osdv->updateBackgroundColor(DrawStyle::BLACK);
94   }
95
96   barRegion.x = 0;
97   barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
98   barRegion.w = video->getScreenWidth();
99   barRegion.h = 58;
100
101   clocksRegion.x = barRegion.x + 140;
102   clocksRegion.y = barRegion.y + 12;
103   clocksRegion.w = 170;
104   clocksRegion.h = getFontHeight();
105 //  barBlue.set(0, 0, 150, 150);
106   barBlue.set(0, 0, 0, 128);
107
108   barShowing = false;
109   barGenHold = false;
110   barScanHold = false;
111   barVasHold = false;
112
113   vdisplay.mode=Fullscreen;
114   vdisplay.fallbackMode=Fullscreen;
115   vdisplay.x=0;
116   vdisplay.y=0;
117   vdisplay.width=0;
118   vdisplay.height=0;
119 }
120
121 void VVideoRec::preDelete()
122 {
123   timers->cancelTimer(this, 1);
124   timers->cancelTimer(this, 2);
125
126   if (vas)
127   {
128     boxstack->remove(vas);
129     vas = NULL;
130   }
131
132   if (vsummary) delete vsummary;
133
134   if (playing) stopPlay();
135 }
136
137 VVideoRec::~VVideoRec()
138 {
139   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");
140
141   video->setDefaultAspect();
142
143   // kill recInfo in case resumePoint has changed (likely)
144   myRec->dropRecInfo();
145   // FIXME - do this properly - save the resume point back to the server manually and update
146   // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
147
148   OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
149   if (osdv)
150   {
151           osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
152   }
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   bool isPesRecording;
166   ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
167   myRec->IsPesRecording = isPesRecording;
168   if (lengthBytes)
169   {
170     player->setLengthBytes(lengthBytes);
171     player->setLengthFrames(lengthFrames);
172     player->setStartFrame(startFrameNum);
173     player->play();
174     playing = true;
175     doBar(0);
176   }
177   else
178   {
179     stopPlay(); // clean up
180
181     if (!vdr->isConnected())
182     {
183       Control::getInstance()->connectionLost();
184       return;
185     }
186
187     Message* m = new Message();
188     m->message = Message::CLOSE_ME;
189     m->from = this;
190     m->p_to = Message::BOXSTACK;
191     MessageQueue::getInstance()->postMessage(m);
192
193     VInfo* vi = new VInfo();
194     vi->setSize(360, 200);
195     vi->createBuffer();
196     if (Video::getInstance()->getFormat() == Video::PAL)
197       vi->setPosition(190, 170);
198     else
199       vi->setPosition(180, 120);
200     vi->setOneLiner(tr("Error playing recording"));
201     vi->setExitable();
202     vi->setBorderOn(1);
203     vi->setTitleBarColour(DrawStyle::DANGER);
204     vi->okButton();
205     vi->draw();
206
207     m = new Message();
208     m->message = Message::ADD_VIEW;
209     m->p_to = Message::BOXSTACK;
210     m->data = reinterpret_cast<void*>(vi);
211     MessageQueue::getInstance()->postMessage(m);
212   }
213 }
214
215 int VVideoRec::handleCommand(int command)
216 {
217   switch(command)
218   {
219     case Input::UP:
220     case Input::PLAY:
221     {
222       player->play();
223       doBar(0);
224       return 2;
225     }
226
227     case Input::PLAYPAUSE:
228     {
229         player->playpause();
230         doBar(0);
231         return 2;
232     }
233
234     case Input::BACK:
235     {
236       if (vsummary)
237       {
238         removeSummary();
239         return 2;
240       }
241     }
242     FALLTHROUGH
243     case Input::STOP:
244     case Input::MENU:
245     {
246       if (playing) stopPlay();
247
248       return 4;
249     }
250     case Input::DOWN:
251     case Input::PAUSE:
252     {
253       player->pause();
254       doBar(0);
255       return 2;
256     }
257     case Input::SKIPFORWARD:
258     {
259       doBar(3);
260       player->skipForward(60);
261       return 2;
262     }
263     case Input::SKIPBACK:
264     {
265       doBar(4);
266       player->skipBackward(60);
267       return 2;
268     }
269     case Input::RIGHT:
270     case Input::FORWARD:
271     {
272       player->fastForward();
273       doBar(0);
274       return 2;
275     }
276     case Input::LEFT:
277     case Input::REVERSE:
278     {
279       player->fastBackward();
280       doBar(0);
281       return 2;
282     }
283     case Input::RED:
284     {
285       if (vsummary) removeSummary();
286       else doSummary();
287       return 2;
288     }
289     case Input::GREEN:
290     {
291       doAudioSelector();
292       return 2;
293     }
294     case Input::YELLOW:
295     {
296       if (myRec->hasMarks())
297       {
298         // skip to previous mark
299         Log* logger = Log::getInstance();
300         int currentFrame = (player->getCurrentFrameNum()); // get current Frame
301         currentFrame -= static_cast<int>(5 * myRec->recInfo->fps); // subtrack 5 seconds, else you cannot skip more than once back ..
302
303         int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
304         if (prevMark)
305         {
306           logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
307           player->jumpToMark(prevMark);
308         }
309         doBar(4);
310       }
311       else
312       {
313         doBar(2);
314         player->skipBackward(10);
315       }
316       return 2;
317     }
318     case Input::BLUE:
319     {
320       if (myRec->hasMarks())
321       {
322         // skip to next mark
323         Log* logger = Log::getInstance();
324         int currentFrame = (player->getCurrentFrameNum());
325
326         int nextMark = myRec->getNextMark(currentFrame);
327
328         if (nextMark)
329         {
330           logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
331           player->jumpToMark(nextMark);
332         }
333         doBar(3);
334       }
335       else
336       {
337         doBar(1);
338         player->skipForward(10);
339       }
340       return 2;
341     }
342     case Input::PREVCHANNEL:
343     {
344       player->skipBackward(2);
345       return 2;
346     }
347     case Input::STAR:
348     {
349       doBar(2);
350       player->skipBackward(10);
351       return 2;
352     }
353     case Input::HASH:
354     {
355       doBar(1);
356       player->skipForward(10);
357       return 2;
358     }
359     case Input::FULL:
360     case Input::TV:
361     {
362       toggleChopSides();
363       return 2;
364     }
365
366     case Input::OK:
367     {
368       if (vsummary)
369       {
370         removeSummary();
371         return 2;
372       }
373       
374       if (barShowing) removeBar();
375       else doBar(0);
376       return 2;
377     }
378
379     case Input::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
380     case Input::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
381     case Input::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
382     case Input::THREE: player->jumpToPercent(30); doBar(0);  return 2;
383     case Input::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
384     case Input::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
385     case Input::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
386     case Input::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
387     case Input::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
388     case Input::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
389
390     case Input::RECORD: player->toggleSubtitles(); return 2;
391 #ifdef DEV
392 //    case Input::RED:
393 //    {
394       //Don't use RED for anything. It will eventually be recording summary
395
396       //player->test1();
397
398
399       /*
400       // for testing EPG in NTSC with a NTSC test video
401       Video::getInstance()->setMode(Video::QUARTER);
402       Video::getInstance()->setPosition(170, 5);
403       VEpg* vepg = new VEpg(NULL, 0);
404       vepg->draw();
405       BoxStack::getInstance()->add(vepg);
406       BoxStack::getInstance()->update(vepg);
407       */
408
409 //      return 2;
410 //    }
411
412 #endif
413
414   }
415
416   return 1;
417 }
418
419 void VVideoRec::doTeletext()
420 {
421   
422   bool exists=true;
423
424   
425   // Draw the teletxt
426   VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
427   if (vtxv==NULL) {
428        vtxv= new VTeletextView((player)->getTeletextDecoder(),this,NULL);
429       (player)->getTeletextDecoder()->registerTeletextView(vtxv);
430       exists=false;
431   }
432   vtxv->setSubtitleMode(true);
433   vtxv->draw();
434   draw();
435   
436   if (!exists) {
437       BoxStack::getInstance()->add(vtxv);
438   }
439   BoxStack::getInstance()->update(this);
440   BoxStack::getInstance()->update(vtxv); 
441 }
442
443 void VVideoRec::processMessage(Message* m)
444 {
445   Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
446
447   if (m->message == Message::MOUSE_LBDOWN)
448   {
449     UINT x = m->parameter - getScreenX();
450     UINT y = m->tag - getScreenY();
451
452     if (!barShowing)
453     {
454       BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
455     }
456     else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
457     {
458       int progBarXbase = barRegion.x + 300;
459       if (myRec->hasMarks())
460       {
461         MarkList* markList = myRec->getMarkList();
462         MarkList::iterator i;
463         Mark* loopMark = NULL;
464         int posPix;
465         ULONG lengthFrames;
466         if (myRec->recInfo->timerEnd > time(NULL))
467         {
468           // chasing playback
469           // Work out an approximate length in frames (good to 1s...)
470           lengthFrames = static_cast<ULONG>((myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
471         }
472         else
473         {
474           lengthFrames = player->getLengthFrames();
475         }
476         for(i = markList->begin(); i != markList->end(); i++)
477         {
478           loopMark = *i;
479           if (loopMark->pos)
480           {
481             posPix = 302 * loopMark->pos / lengthFrames;
482             rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);
483             if (x>=barRegion.x + progBarXbase + 2 + posPix
484                 && x<=barRegion.x + progBarXbase + 2 + posPix+3
485                 && y>=barRegion.y + 12 - 2
486                 && y<=barRegion.y + 12 - 2+28)
487             {
488               player->jumpToMark(loopMark->pos);
489               doBar(3);
490               return;
491             }
492           }
493         }
494       }
495
496       if (x>=barRegion.x + progBarXbase + 24
497           && x<=barRegion.x + progBarXbase + 4 + 302
498           && y>=barRegion.y + 12 - 2
499           && y<=barRegion.y + 12 - 2+28)
500       {
501         int cx=x-(barRegion.x + progBarXbase + 4);
502         double percent = cx / 302. * 100.;
503         player->jumpToPercent(percent);
504         doBar(3);
505         return;
506         //  int progressWidth = 302 * currentFrameNum / lengthFrames;
507         //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
508       }
509     }
510     else
511     {
512       BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
513     }
514   }
515   else if (m->from == player)
516   {
517     if (m->message != Message::PLAYER_EVENT) return;
518     switch(m->parameter)
519     {
520       case PlayerVideoRec::CONNECTION_LOST: // connection lost detected
521       {
522         // I can't handle this, send it to control
523         Message* m2 = new Message();
524         m2->p_to = Message::CONTROL;
525         m2->message = Message::CONNECTION_LOST;
526         MessageQueue::getInstance()->postMessage(m2);
527         break;
528       }
529       case PlayerVideoRec::STOP_PLAYBACK:
530       {
531         // FIXME Obselete ish - improve this
532         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
533         m2->p_to = Message::CONTROL;
534         m2->message = Message::STOP_PLAYBACK;
535         MessageQueue::getInstance()->postMessage(m2);
536         break;
537       }
538       case PlayerVideoRec::ASPECT43:
539       {
540         break;
541       }
542       case PlayerVideoRec::ASPECT169:
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,(m->parameter&0xFF000000)>> 24 );
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->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->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->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()) { Control::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         ULONG mp_audcounter = 0;
669         ULONG ac3_counter = 0;
670         int dvb_subcounter = 1;*/
671         ULONG i;
672         
673         /*unsigned char type;
674         char* lang;
675         char* description;
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->desc[0]==0) {
719                 strncpy(ac->desc, tr("unknown"),9);
720             }
721         }
722         for (i=0;i<temp_channel->numDPids;i++) {
723             apid *ac=&temp_channel->dpids[i];
724             if (ac->desc[0]==0) {
725                 strncpy(ac->desc, tr("unknown"),9);
726             }
727         }
728         for (i=0;i<temp_channel->numSPids;i++) {
729             apid *ac=&temp_channel->spids[i];
730             if (ac->desc[0]==0) {
731                 strncpy(ac->desc, tr("unknown"),9);
732             }
733         }
734
735         vas = new VAudioSelector(this,temp_channel , (player)->getCurrentAudioChannel(),
736             subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  
737       /*   for (i=0;i<temp_channel.numAPids;i++) {
738             apid *ac=&temp_channel.apids[i];
739             delete[] ac->name;
740             ac->name=NULL;
741         }
742         for (i=0;i<temp_channel.numDPids;i++) {
743             apid *ac=&temp_channel.dpids[i];
744             delete[] ac->name;
745             ac->name=NULL;
746         }
747         for (i=0;i<temp_channel.numSPids;i++) {
748             apid *ac=&temp_channel.spids[i];
749             delete[] ac->name;
750             ac->name=NULL;
751         }*/
752     }
753
754
755   vas->setBackgroundColour(barBlue);
756   vas->setPosition(0, barRegion.y - 120);
757
758 // pal 62, ntsc 57
759
760   barVasHold = true;
761   doBar(0);
762
763   vas->draw();
764   boxstack->add(vas);
765   boxstack->update(vas);
766 }
767
768 void VVideoRec::doBar(int action_in)
769 {
770  // if (player->isSubtitlesOn()) clearOSD(); // remove dvbsubtitles
771  // player->tellSubtitlesOSDVisible(true);
772   barShowing = true;
773
774   int action = action_in;
775   if (action == -1) {
776           action = lastbar;
777   }
778   else {
779           lastbar = action;
780   }
781
782   rectangle(barRegion, barBlue);
783
784   /* Work out what to display - choices:
785
786   Playing  >
787   Paused   ||
788   FFwd     >>
789   FBwd     <<
790
791   Specials, informed by parameter
792
793   Skip forward 10s    >|
794   Skip backward 10s   |<
795   Skip forward 1m     >>|
796   Skip backward 1m    |<<
797
798   */
799
800   WSymbol w;
801   TEMPADD(&w);
802   w.nextSymbol = 0;
803   w.setPosition(barRegion.x + 66, barRegion.y + 16);
804
805   UCHAR playerState = 0;
806
807   if (action)
808   {
809     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
810     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
811     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
812     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
813   }
814   else
815   {
816     playerState = player->getState();
817     if (playerState == PlayerVideoRec::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
818     else if (playerState == PlayerVideoRec::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
819     else if (playerState == PlayerVideoRec::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
820     else if (playerState == PlayerVideoRec::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
821     else                                       w.nextSymbol = WSymbol::PLAY;
822   }
823
824   w.draw();
825
826   if ((playerState == PlayerVideoRec::S_FFWD) || (playerState == PlayerVideoRec::S_FBWD))
827   {
828     // draw blips to show how fast the scan is
829     UCHAR scanrate = player->getIScanRate();
830     if (scanrate >= 2)
831     {
832       char text[5];
833       SNPRINTF(text, 5, "%ux", scanrate);
834       drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);
835     }
836   }
837
838   drawBarClocks();
839
840   boxstack->update(this, &barRegion);
841
842   if (action_in != -1)
843   {
844     timers->cancelTimer(this, 1);
845
846     if ((playerState == PlayerVideoRec::S_FFWD) || (playerState == PlayerVideoRec::S_FBWD))
847       barScanHold = true;
848     else
849       barScanHold = false;
850
851     if (!barGenHold && !barScanHold && !barVasHold)
852       timers->setTimerD(this, 1, 4);
853
854     Log::getInstance()->log("VVideoRec", Log::DEBUG, "player state: %i", playerState);
855
856     if ((playerState == PlayerVideoRec::S_PAUSE_P) || (playerState == PlayerVideoRec::S_PAUSE_I))
857       timers->cancelTimer(this, 2);
858     else
859       timers->setTimerD(this, 2, 0, 200000000);
860   }
861 }
862
863 void VVideoRec::timercall(int clientReference)
864 {
865   switch(clientReference)
866   {
867     case 1:
868     {
869       // Remove bar
870       removeBar();
871       break;
872     }
873     case 2:
874     {
875       // Update clock
876       if (!barShowing) break;
877 #ifndef GRADIENT_DRAWING
878       drawBarClocks();
879       boxstack->update(this, &barRegion);
880 #else 
881           doBar(-1);
882 #endif
883       timers->setTimerD(this, 2, 0, 200000000);
884       break;
885     }
886   }
887 }
888
889 void VVideoRec::drawBarClocks()
890 {
891   if (barScanHold)
892   {
893     UCHAR playerState = player->getState();
894     // sticky bar is set if we are in ffwd/fbwd mode
895     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
896     // will repaint all the bar (it will call this function again, but
897     // this section won't run because stickyBarF will then == false)
898
899     if ((playerState != PlayerVideoRec::S_FFWD) && (playerState != PlayerVideoRec::S_FBWD))
900     {
901       barScanHold = false;
902       doBar(0);
903       return; // doBar will call this function and do the rest
904     }
905   }
906
907   Log* logger = Log::getInstance();
908   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
909
910   // Draw RTC
911   // Blank the area first
912 #ifndef GRADIENT_DRAWING
913   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
914 #endif
915   char timeString[20];
916   time_t t;
917   time(&t);
918   struct tm tms;
919   LOCALTIME_R(&t, &tms);
920   strftime(timeString, 19, "%H:%M", &tms);
921   drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);
922
923   // Draw clocks
924 #ifndef GRADIENT_DRAWING
925   rectangle(clocksRegion, barBlue);
926 #endif
927
928   ULONG currentFrameNum = player->getCurrentFrameNum();
929   ULONG lengthFrames;
930   if (myRec->recInfo->timerEnd > time(NULL))
931   {
932     // chasing playback
933     // Work out an approximate length in frames (good to 1s...)
934     lengthFrames = static_cast<ULONG>((myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
935   }
936   else
937   {
938     lengthFrames = player->getLengthFrames();
939   }
940
941   hmsf currentFrameHMSF = myRec->recInfo->framesToHMSF(currentFrameNum);
942   hmsf lengthHMSF = myRec->recInfo->framesToHMSF(lengthFrames);
943
944   char buffer[100];
945   if (currentFrameNum >= lengthFrames)
946   {
947     strcpy(buffer, "-:--:-- / -:--:--");
948   }
949   else
950   {
951     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
952     logger->log("VVideoRec", Log::DEBUG, buffer);
953   }
954
955   drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
956
957
958
959
960
961
962
963   // Draw progress bar
964   int progBarXbase = barRegion.x + 300;
965
966   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);
967   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
968
969   if (currentFrameNum > lengthFrames) return;
970   if (lengthFrames == 0) return;
971
972   // Draw yellow portion
973   int progressWidth = 302 * currentFrameNum / lengthFrames;
974   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
975
976   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
977   {
978     int nrWidth = 302 * (lengthFrames - player->getLengthFrames()) / lengthFrames;
979
980     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
981     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
982     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
983     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);
984   }
985
986   int posPix;
987   // Now calc position for blips
988
989   if (myRec->hasMarks())
990   {
991     // Draw blips where there are cut marks
992     MarkList* markList = myRec->getMarkList();
993     MarkList::iterator i;
994     Mark* loopMark = NULL;
995
996     for(i = markList->begin(); i != markList->end(); i++)
997     {
998       loopMark = *i;
999       if (loopMark->pos)
1000       {
1001         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
1002         posPix = 302 * loopMark->pos / lengthFrames;
1003         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);
1004       }
1005     }
1006   }
1007   else
1008   {
1009     // Draw blips where start and end margins probably are
1010
1011     posPix = static_cast<int>(302 * startMargin * myRec->recInfo->fps / lengthFrames);
1012
1013     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
1014     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
1015
1016     posPix   = static_cast<int>(302 * (lengthFrames - endMargin * myRec->recInfo->fps) / lengthFrames);
1017
1018     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
1019     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
1020   }
1021 }
1022
1023 void VVideoRec::removeBar()
1024 {
1025   if (!barShowing) return;
1026   timers->cancelTimer(this, 2);
1027   barShowing = false;
1028   barGenHold = false;
1029   barScanHold = false;
1030   barVasHold = false;
1031   rectangle(barRegion, DrawStyle::TRANSPARENT);
1032   boxstack->update(this, &barRegion);
1033   player->tellSubtitlesOSDVisible(false);
1034 }
1035
1036 void VVideoRec::doSummary()
1037 {
1038   clearOSD(); // remove dvbsubtitles
1039   player->tellSubtitlesOSDVisible(true);
1040   vsummary = new VInfo();
1041   vsummary->setTitleText(myRec->getProgName());
1042   vsummary->setBorderOn(1);
1043   vsummary->setExitable();
1044   if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);
1045   else vsummary->setMainText(tr("Summary unavailable"));
1046   if (Video::getInstance()->getFormat() == Video::PAL)
1047   {
1048     vsummary->setPosition(120, 130);
1049   }
1050   else
1051   {
1052     vsummary->setPosition(110, 90);
1053   }
1054   vsummary->setSize(510, 270);
1055   add(vsummary);
1056   vsummary->draw();
1057
1058   BoxStack::getInstance()->update(this);
1059 }
1060
1061 void VVideoRec::removeSummary()
1062 {
1063   if (vsummary)
1064   {
1065     remove(vsummary);
1066     delete vsummary;
1067     vsummary = NULL;
1068     draw();
1069     BoxStack::getInstance()->update(this);
1070     player->tellSubtitlesOSDVisible(false);
1071   }
1072 }
1073
1074 void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
1075 {
1076   drawBitmap(posX, posY, bm, region);
1077   Region r;
1078   r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
1079   boxstack->update(this, &r);
1080 }
1081
1082 void VVideoRec::clearOSD()
1083 {
1084   rectangle(area, DrawStyle::TRANSPARENT);
1085   boxstack->update(this, &area);
1086 }
1087
1088 void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
1089 {
1090   Region r(r.x = posX + region.windowx, posY + region.windowy, width, height);
1091   //now convert to our display
1092   float scalex = 720.f / static_cast<float>(region.framewidth + 1);
1093   float scaley = 576.f / static_cast<float>(region.frameheight + 1);
1094   r.x = static_cast<UINT>(floor(scalex * static_cast<float>(r.x)));
1095   r.y = static_cast<UINT>(floor(scaley * static_cast<float>(r.y)));
1096   r.w = static_cast<UINT>(ceil(scalex * static_cast<float>(r.w)) + 1.f);
1097   r.h = static_cast<UINT>(ceil(scaley * static_cast<float>(r.h)) + 1.f);
1098
1099   rectangle(r, DrawStyle::TRANSPARENT);
1100   boxstack->update(this, &r);
1101 }