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