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