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