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