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