]> git.vomp.tv Git - vompclient.git/blob - vvideorec.cc
Preparations for AC3 passthrough and parser for deinterlacing
[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 );\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         \r
692         unsigned char type;\r
693         char* lang;\r
694         char* description;\r
695         int i;\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->name==NULL) {\r
739                 ac->name = new char[strlen(tr("unknown")) + 1];\r
740                 strcpy(ac->name, tr("unknown"));\r
741             }\r
742         }\r
743         for (i=0;i<temp_channel.numDPids;i++) {\r
744             apid *ac=&temp_channel.dpids[i];\r
745             if (ac->name==NULL) {\r
746                 ac->name = new char[strlen(tr("unknown")) + 1];\r
747                 strcpy(ac->name, tr("unknown"));\r
748             }\r
749         }\r
750         for (i=0;i<temp_channel.numSPids;i++) {\r
751             apid *ac=&temp_channel.spids[i];\r
752             if (ac->name==NULL) {\r
753                 ac->name = new char[strlen(tr("unknown")) + 1];\r
754                 strcpy(ac->name, tr("unknown"));\r
755             }\r
756         }\r
757 \r
758         vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(),\r
759             subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  \r
760          for (i=0;i<temp_channel.numAPids;i++) {\r
761             apid *ac=&temp_channel.apids[i];\r
762             delete[] ac->name;\r
763             ac->name=NULL;\r
764         }\r
765         for (i=0;i<temp_channel.numDPids;i++) {\r
766             apid *ac=&temp_channel.dpids[i];\r
767             delete[] ac->name;\r
768             ac->name=NULL;\r
769         }\r
770         for (i=0;i<temp_channel.numSPids;i++) {\r
771             apid *ac=&temp_channel.spids[i];\r
772             delete[] ac->name;\r
773             ac->name=NULL;\r
774         }\r
775     }\r
776 \r
777 \r
778   vas->setBackgroundColour(barBlue);\r
779   vas->setPosition(0, barRegion.y - 120);\r
780 \r
781 // pal 62, ntsc 57\r
782 \r
783   barVasHold = true;\r
784   doBar(0);\r
785 \r
786   vas->draw();\r
787   boxstack->add(vas);\r
788   boxstack->update(vas);\r
789 }\r
790 \r
791 void VVideoRec::doBar(int action)\r
792 {\r
793   barShowing = true;\r
794 \r
795   rectangle(barRegion, barBlue);\r
796 \r
797   /* Work out what to display - choices:\r
798 \r
799   Playing  >\r
800   Paused   ||\r
801   FFwd     >>\r
802   FBwd     <<\r
803 \r
804   Specials, informed by parameter\r
805 \r
806   Skip forward 10s    >|\r
807   Skip backward 10s   |<\r
808   Skip forward 1m     >>|\r
809   Skip backward 1m    |<<\r
810 \r
811   */\r
812 \r
813   WSymbol w;\r
814   TEMPADD(&w);\r
815   w.nextSymbol = 0;\r
816   w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
817 \r
818   UCHAR playerState = 0;\r
819 \r
820   if (action)\r
821   {\r
822     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
823     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
824     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
825     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
826   }\r
827   else\r
828   {\r
829     playerState = player->getState();\r
830     if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;\r
831     else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
832     else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;\r
833     else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;\r
834     else                                       w.nextSymbol = WSymbol::PLAY;\r
835   }\r
836 \r
837   w.draw();\r
838 \r
839   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))\r
840   {\r
841     // draw blips to show how fast the scan is\r
842     UCHAR scanrate = player->getIScanRate();\r
843     if (scanrate >= 2)\r
844     {\r
845       char text[5];\r
846       SNPRINTF(text, 5, "%ux", scanrate);\r
847       drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
848     }\r
849   }\r
850 \r
851   drawBarClocks();\r
852 \r
853   boxstack->update(this, &barRegion);\r
854 \r
855   timers->cancelTimer(this, 1);\r
856 \r
857 \r
858   if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;\r
859   else barScanHold = false;\r
860 \r
861   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
862 \r
863   timers->setTimerD(this, 2, 0, 200000000);\r
864 }\r
865 \r
866 void VVideoRec::timercall(int clientReference)\r
867 {\r
868   switch(clientReference)\r
869   {\r
870     case 1:\r
871     {\r
872       // Remove bar\r
873       removeBar();\r
874       break;\r
875     }\r
876     case 2:\r
877     {\r
878       // Update clock\r
879       if (!barShowing) break;\r
880       drawBarClocks();\r
881       boxstack->update(this, &barRegion);\r
882       \r
883       timers->setTimerD(this, 2, 0, 200000000);\r
884       break;\r
885     }\r
886   }\r
887 }\r
888 \r
889 hmsf VVideoRec::framesToHMSF(ULONG frames)\r
890 {\r
891   hmsf ret;\r
892   /* from vdr */\r
893   double Seconds;\r
894   double fps=myRec->recInfo->fps;\r
895   ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
896   int s = int(Seconds);\r
897   ret.seconds=s % 60;\r
898   ret.minutes = s / 60 % 60;\r
899   ret.hours = s / 3600;\r
900 \r
901 \r
902   return ret;\r
903 }\r
904 \r
905 void VVideoRec::drawBarClocks()\r
906 {\r
907   if (barScanHold)\r
908   {\r
909     UCHAR playerState = player->getState();\r
910     // sticky bar is set if we are in ffwd/fbwd mode\r
911     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
912     // will repaint all the bar (it will call this function again, but\r
913     // this section won't run because stickyBarF will then == false)\r
914 \r
915     if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))\r
916     {\r
917       barScanHold = false;\r
918       doBar(0);\r
919       return; // doBar will call this function and do the rest\r
920     }\r
921   }\r
922 \r
923   Log* logger = Log::getInstance();\r
924   logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");\r
925 \r
926   // Draw RTC\r
927   // Blank the area first\r
928   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
929   char timeString[20];\r
930   time_t t;\r
931   time(&t);\r
932   struct tm* tms = localtime(&t);\r
933   strftime(timeString, 19, "%H:%M", tms);\r
934   drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
935 \r
936   // Draw clocks\r
937 \r
938   rectangle(clocksRegion, barBlue);\r
939 \r
940   ULONG currentFrameNum = player->getCurrentFrameNum();\r
941   ULONG lengthFrames;\r
942   if (myRec->recInfo->timerEnd > time(NULL))\r
943   {\r
944     // chasing playback\r
945     // Work out an approximate length in frames (good to 1s...)\r
946     lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
947   }\r
948   else\r
949   {\r
950     lengthFrames = player->getLengthFrames();\r
951   }\r
952 \r
953   hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);\r
954   hmsf lengthHMSF = framesToHMSF(lengthFrames);\r
955 \r
956   char buffer[100];\r
957   if (currentFrameNum >= lengthFrames)\r
958   {\r
959     strcpy(buffer, "-:--:-- / -:--:--");\r
960   }\r
961   else\r
962   {\r
963     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
964     logger->log("VVideoRec", Log::DEBUG, buffer);\r
965   }\r
966 \r
967   drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
968 \r
969 \r
970 \r
971 \r
972 \r
973 \r
974 \r
975   // Draw progress bar\r
976   int progBarXbase = barRegion.x + 300;\r
977 \r
978   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);\r
979   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
980 \r
981   if (currentFrameNum > lengthFrames) return;\r
982   if (lengthFrames == 0) return;\r
983 \r
984   // Draw yellow portion\r
985   int progressWidth = 302 * currentFrameNum / lengthFrames;\r
986   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
987 \r
988   if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
989   {\r
990     int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));\r
991 \r
992     Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
993     Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
994     Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
995     rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);\r
996   }\r
997 \r
998   int posPix;\r
999   // Now calc position for blips\r
1000 \r
1001   if (myRec->hasMarks())\r
1002   {\r
1003     // Draw blips where there are cut marks\r
1004     MarkList* markList = myRec->getMarkList();\r
1005     MarkList::iterator i;\r
1006     Mark* loopMark = NULL;\r
1007 \r
1008     for(i = markList->begin(); i != markList->end(); i++)\r
1009     {\r
1010       loopMark = *i;\r
1011       if (loopMark->pos)\r
1012       {\r
1013         logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);\r
1014         posPix = 302 * loopMark->pos / lengthFrames;\r
1015         rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);\r
1016       }\r
1017     }\r
1018   }\r
1019   else\r
1020   {\r
1021     // Draw blips where start and end margins probably are\r
1022 \r
1023           posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));\r
1024 \r
1025     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
1026     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
1027 \r
1028     posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));\r
1029 \r
1030     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
1031     rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
1032   }\r
1033 }\r
1034 \r
1035 void VVideoRec::removeBar()\r
1036 {\r
1037   if (!barShowing) return;\r
1038   timers->cancelTimer(this, 2);\r
1039   barShowing = false;\r
1040   barGenHold = false;\r
1041   barScanHold = false;\r
1042   barVasHold = false;\r
1043   rectangle(barRegion, transparent);\r
1044   boxstack->update(this, &barRegion);\r
1045 }\r
1046 \r
1047 void VVideoRec::doSummary()\r
1048 {\r
1049   vsummary = new VInfo();\r
1050   vsummary->setTitleText(myRec->getProgName());\r
1051   vsummary->setBorderOn(1);\r
1052   vsummary->setExitable();\r
1053   if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);\r
1054   else vsummary->setMainText(tr("Summary unavailable"));\r
1055   if (Video::getInstance()->getFormat() == Video::PAL)\r
1056   {\r
1057     vsummary->setPosition(120, 130);\r
1058   }\r
1059   else\r
1060   {\r
1061     vsummary->setPosition(110, 90);\r
1062   }\r
1063   vsummary->setSize(510, 270);\r
1064   add(vsummary);\r
1065   vsummary->draw();\r
1066 \r
1067   BoxStack::getInstance()->update(this);\r
1068 }\r
1069 \r
1070 void VVideoRec::removeSummary()\r
1071 {\r
1072   if (vsummary)\r
1073   {\r
1074     remove(vsummary);\r
1075     delete vsummary;\r
1076     vsummary = NULL;\r
1077     draw();\r
1078     BoxStack::getInstance()->update(this);\r
1079   }\r
1080 }\r
1081 \r
1082 void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)\r
1083 {\r
1084   drawBitmap(posX, posY, bm, region);\r
1085   Region r;\r
1086   r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
1087   boxstack->update(this, &r);\r
1088 }\r
1089 \r
1090 void VVideoRec::clearOSD()\r
1091 {\r
1092   rectangle(area, transparent);\r
1093   boxstack->update(this, &area);\r
1094 }\r
1095 \r
1096 void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)\r
1097 {\r
1098   Region r;\r
1099   r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;\r
1100   //now convert to our display\r
1101   float scalex=720.f/((float) (region.framewidth+1));\r
1102   float scaley=576.f/((float) (region.frameheight+1));\r
1103   r.x=floor(scalex*((float)r.x));\r
1104   r.y=floor(scaley*((float)r.y));\r
1105   r.w=ceil(scalex*((float)r.w));\r
1106   r.h=ceil(scaley*((float)r.h));\r
1107 \r
1108   rectangle(r, transparent);\r
1109   boxstack->update(this, &r);\r
1110 }\r