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