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