]> git.vomp.tv Git - vompclient.git/blob - vvideomedia.cc
Preparations for dynamic mode switching
[vompclient.git] / vvideomedia.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 "vvideomedia.h"\r
22 #include "vmedialist.h"\r
23 #include "media.h"\r
24 #include "mediaplayer.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 "video.h"\r
31 #include "timers.h"\r
32 #include "playermedia.h"\r
33 #include "recording.h"\r
34 #include "vaudioselector.h"\r
35 #include "message.h"\r
36 #include "remote.h"\r
37 #include "boxstack.h"\r
38 #include "vinfo.h"\r
39 #include "i18n.h"\r
40 #include "log.h"\r
41 #include "recinfo.h"\r
42 \r
43 //use the picture channel\r
44 #define MEDIACHANNEL 1\r
45 \r
46 //we misuse PLAYER_EVENTS for timer messages\r
47 //this should be larger then any player message\r
48 #define PLAYER_TIMER_BASE 100\r
49 \r
50 VVideoMedia::VVideoMedia(Media* media, VMediaList *p)\r
51 {\r
52   lparent=p;\r
53   boxstack = BoxStack::getInstance();\r
54   video = Video::getInstance();\r
55   timers = Timers::getInstance();\r
56   vas = NULL;\r
57   vsummary = NULL;\r
58   lengthBytes=0;\r
59   myMedia = new Media(media);\r
60 \r
61   player = new PlayerMedia(this);\r
62   player->run();\r
63 \r
64   videoMode = video->getMode();\r
65 \r
66   playing = false;\r
67 \r
68 \r
69   setSize(video->getScreenWidth(), video->getScreenHeight());\r
70   createBuffer();\r
71   transparent.set(0, 0, 0, 0);\r
72   setBackgroundColour(transparent);\r
73 \r
74   barRegion.x = 0;\r
75   barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
76   barRegion.w = video->getScreenWidth();\r
77   barRegion.h = 58;\r
78 \r
79   clocksRegion.x = barRegion.x + 140;\r
80   clocksRegion.y = barRegion.y + 12;\r
81   clocksRegion.w = 170;\r
82   clocksRegion.h = getFontHeight();\r
83 \r
84 \r
85   barBlue.set(0, 0, 150, 150);\r
86 \r
87   barShowing = false;\r
88   barGenHold = false;\r
89   barScanHold = false;\r
90   barVasHold = false;\r
91 \r
92   dowss = false;\r
93   char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");\r
94   if (optionWSS)\r
95   {\r
96     if (strstr(optionWSS, "Yes")) dowss = true;\r
97     delete[] optionWSS;\r
98   }\r
99   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);\r
100 \r
101   if (dowss)\r
102   {\r
103     wss.setFormat(video->getFormat());\r
104     wss.setWide(true);\r
105     add(&wss);\r
106 \r
107     wssRegion.x = 0;\r
108     wssRegion.y = 0;\r
109     wssRegion.w = video->getScreenWidth();\r
110     wssRegion.h = 300;\r
111   }\r
112 }\r
113 \r
114 VVideoMedia::~VVideoMedia()\r
115 {\r
116   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering  destructor");\r
117 \r
118   if (vas)\r
119   {\r
120     boxstack->remove(vas);\r
121     vas = NULL;\r
122   }\r
123 \r
124   if (vsummary) {\r
125     remove(vsummary);\r
126     delete vsummary;\r
127   }\r
128 \r
129   if (playing) stopPlay();\r
130   video->setDefaultAspect();\r
131 \r
132   timers->cancelTimer(this, 1);\r
133   timers->cancelTimer(this, 2);\r
134 \r
135   delete myMedia;\r
136   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");\r
137   player->shutdown();\r
138   delete player;\r
139   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");\r
140 }\r
141 \r
142 void VVideoMedia::go(bool resume)\r
143 {\r
144   ULONG startFrameNum=0;\r
145 \r
146   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);\r
147 \r
148   lengthBytes = 0;\r
149 \r
150   int rt=0;\r
151   const MediaURI *u=myMedia->getURI();\r
152   if (!u) {\r
153     Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());\r
154     rt=-1;\r
155   }\r
156   else {\r
157     rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);\r
158   }\r
159   if (rt==0)\r
160   {\r
161     //TODO: figure out len in frames\r
162     int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);\r
163     int ok=player->waitForSequence(2,seq);\r
164     if (ok < 0) rt=-1; \r
165     else {\r
166       playing = true;\r
167       doBar(0);\r
168     }\r
169   }\r
170   if (rt != 0)\r
171   {\r
172     stopPlay(); // clean up\r
173 \r
174     Message* m = new Message();\r
175     m->message = Message::CLOSE_ME;\r
176     m->from = this;\r
177     m->to = boxstack;\r
178     Command::getInstance()->postMessageNoLock(m);\r
179 \r
180     VInfo* vi = new VInfo();\r
181     vi->setSize(400, 150);\r
182     vi->createBuffer();\r
183     if (video->getFormat() == Video::PAL)\r
184       vi->setPosition(170, 200);\r
185     else\r
186       vi->setPosition(160, 150);\r
187     vi->setExitable();\r
188     vi->setBorderOn(1);\r
189     vi->setTitleBarOn(0);\r
190     vi->setOneLiner(tr("Error playing media"));\r
191     vi->draw();\r
192 \r
193     m = new Message();\r
194     m->message = Message::ADD_VIEW;\r
195     m->to = boxstack;\r
196     m->parameter = (ULONG)vi;\r
197     Command::getInstance()->postMessageNoLock(m);\r
198   }\r
199 }\r
200 \r
201 int VVideoMedia::handleCommand(int command)\r
202 {\r
203   switch(command)\r
204   {\r
205     case Remote::PLAY:\r
206     {\r
207       player->play();\r
208       doBar(0);\r
209       return 2;\r
210     }\r
211 \r
212     case Remote::BACK:\r
213     {\r
214       if (vsummary)\r
215       {\r
216         removeSummary();\r
217         return 2;\r
218       }\r
219     } // DROP THROUGH\r
220     case Remote::STOP:\r
221     case Remote::MENU:\r
222     {\r
223       if (playing) stopPlay();\r
224 \r
225       return 4;\r
226     }\r
227     case Remote::PAUSE:\r
228     {\r
229       player->pause();\r
230       doBar(0);\r
231       return 2;\r
232     }\r
233     case Remote::SKIPFORWARD:\r
234     {\r
235       doBar(3);\r
236       player->skipForward(60);\r
237       return 2;\r
238     }\r
239     case Remote::SKIPBACK:\r
240     {\r
241       doBar(4);\r
242       player->skipBackward(60);\r
243       return 2;\r
244     }\r
245     case Remote::FORWARD:\r
246     {\r
247       player->fastForward();\r
248       doBar(0);\r
249       return 2;\r
250     }\r
251     case Remote::REVERSE:\r
252     {\r
253       player->fastBackward();\r
254       doBar(0);\r
255       return 2;\r
256     }\r
257     case Remote::RED:\r
258     {\r
259       if (vsummary) removeSummary();\r
260       else doSummary();\r
261       return 2;\r
262     }\r
263     case Remote::GREEN:\r
264     {\r
265       doAudioSelector();\r
266       return 2;\r
267     }\r
268     case Remote::YELLOW:\r
269     {\r
270       doBar(2);\r
271       player->skipBackward(10);\r
272       return 2;\r
273     }\r
274     case Remote::BLUE:\r
275     {\r
276       doBar(1);\r
277       player->skipForward(10);\r
278       return 2;\r
279     }\r
280     case Remote::STAR:\r
281     {\r
282       doBar(2);\r
283       player->skipBackward(10);\r
284       return 2;\r
285     }\r
286     case Remote::HASH:\r
287     {\r
288       doBar(1);\r
289       player->skipForward(10);\r
290       return 2;\r
291     }\r
292     case Remote::FULL:\r
293     case Remote::TV:\r
294     {\r
295       toggleChopSides();\r
296       return 2;\r
297     }\r
298 \r
299     case Remote::OK:\r
300     {\r
301       if (vsummary)\r
302       {\r
303         removeSummary();\r
304         return 2;\r
305       }\r
306       \r
307       if (barShowing) removeBar();\r
308       else {\r
309         doBar(0);\r
310         barGenHold=true;\r
311       }\r
312       return 2;\r
313     }\r
314 \r
315     case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
316     case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
317     case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
318     case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
319     case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
320     case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
321     case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
322     case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
323     case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
324     case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
325 \r
326 \r
327   }\r
328 \r
329   return 1;\r
330 }\r
331 \r
332 void VVideoMedia::processMessage(Message* m)\r
333 {\r
334   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");\r
335 \r
336   if (m->message == Message::MOUSE_LBDOWN)\r
337   {\r
338     UINT x = (m->parameter>>16) - getScreenX();\r
339     UINT y = (m->parameter&0xFFFF) - getScreenY();\r
340 \r
341     if (!barShowing)\r
342     {\r
343       BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
344     }\r
345     else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
346     {\r
347       int progBarXbase = barRegion.x + 300;\r
348       if (x>=barRegion.x + progBarXbase + 24\r
349           && x<=barRegion.x + progBarXbase + 4 + 302\r
350           && y>=barRegion.y + 12 - 2\r
351           && y<=barRegion.y + 12 - 2+28)\r
352       {\r
353         int cx=x-(barRegion.x + progBarXbase + 4);\r
354         double percent=((double)cx)/302.*100.;\r
355         player->jumpToPercent(percent);\r
356         doBar(3);\r
357         return;\r
358         //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
359         //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
360       }\r
361     }\r
362     else\r
363     {\r
364       BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
365     }\r
366   }\r
367   else if (m->message == Message::PLAYER_EVENT)\r
368   {\r
369     switch(m->parameter)\r
370     {\r
371       case PlayerMedia::CONNECTION_LOST: // connection lost detected\r
372       {\r
373         // I can't handle this, send it to command\r
374         Message* m2 = new Message();\r
375         m2->to = Command::getInstance();\r
376         m2->message = Message::CONNECTION_LOST;\r
377         Command::getInstance()->postMessageNoLock(m2);\r
378         break;\r
379       }\r
380       case PlayerMedia::STREAM_END:\r
381       {\r
382         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
383         m2->to = BoxStack::getInstance();\r
384         m2->message = Message::CLOSE_ME;\r
385         Command::getInstance()->postMessageNoLock(m2);\r
386         break;\r
387       }\r
388       case PlayerMedia::STATUS_CHANGE:\r
389         doBar(0);\r
390         break;\r
391       case PlayerMedia::ASPECT43:\r
392       {\r
393         if (dowss)\r
394         {\r
395           Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");\r
396           wss.setWide(false);\r
397           wss.draw();\r
398           boxstack->update(this, &wssRegion);\r
399         }\r
400         break;\r
401       }\r
402       case PlayerMedia::ASPECT169:\r
403       {\r
404         if (dowss)\r
405         {\r
406           Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");\r
407           wss.setWide(true);\r
408           wss.draw();\r
409           boxstack->update(this, &wssRegion);\r
410         }\r
411         break;\r
412       }\r
413       case (PLAYER_TIMER_BASE+1) :\r
414         //timer1:\r
415         // Remove bar\r
416         removeBar();\r
417         break;\r
418       case (PLAYER_TIMER_BASE+2) :\r
419         //timer2:\r
420         // Update clock\r
421         if (!barShowing) break;\r
422         drawBarClocks();\r
423         BoxStack::getInstance()->update(this,&barRegion);\r
424         if (player->getLengthFrames() != 0)   timers->setTimerD(this, 2, 0, 200000000);\r
425         else   timers->setTimerD(this, 2, 1);\r
426         break;\r
427     }\r
428   }\r
429   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
430   {\r
431     Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
432     player->setAudioChannel(m->parameter);\r
433   }\r
434   else if (m->message == Message::CHILD_CLOSE)\r
435   {\r
436     if (m->from == vas)\r
437     {\r
438       vas = NULL;\r
439       barVasHold = false;\r
440       if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
441     }\r
442   }\r
443 }\r
444 \r
445 void VVideoMedia::stopPlay()\r
446 {\r
447   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");\r
448 \r
449   removeBar();\r
450 \r
451   player->stop();\r
452 \r
453   playing = false;\r
454   MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);\r
455 \r
456   Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");\r
457 }\r
458 \r
459 void VVideoMedia::toggleChopSides()\r
460 {\r
461   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
462 \r
463   if (videoMode == Video::NORMAL)\r
464   {\r
465     videoMode = Video::LETTERBOX;\r
466     video->setMode(Video::LETTERBOX);\r
467   }\r
468   else\r
469   {\r
470     videoMode = Video::NORMAL;\r
471     video->setMode(Video::NORMAL);\r
472   }\r
473 }\r
474 \r
475 void VVideoMedia::doAudioSelector()\r
476 {\r
477   bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
478   bool* availableAc3AudioChannels = 0;\r
479   int currentAudioChannel = player->getCurrentAudioChannel();\r
480   if (Audio::getInstance()->supportsAc3())\r
481   {\r
482       availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
483   }\r
484 \r
485 \r
486   RecInfo ri;\r
487   ri.summary=new char[strlen(myMedia->getDisplayName())+1];\r
488   strcpy(ri.summary,myMedia->getDisplayName());\r
489   vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);\r
490  \r
491   vas->setBackgroundColour(barBlue);\r
492   vas->setPosition(0, barRegion.y - 120);\r
493 \r
494 // pal 62, ntsc 57\r
495 \r
496   barVasHold = true;\r
497   doBar(0);\r
498 \r
499   vas->draw();\r
500   boxstack->add(vas);\r
501   boxstack->update(vas);\r
502 }\r
503 \r
504 void VVideoMedia::doBar(int action)\r
505 {\r
506   Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);\r
507   barShowing = true;\r
508 \r
509   rectangle(barRegion, barBlue);\r
510 \r
511   /* Work out what to display - choices:\r
512 \r
513   Playing  >\r
514   Paused   ||\r
515   FFwd     >>\r
516   FBwd     <<\r
517 \r
518   Specials, informed by parameter\r
519 \r
520   Skip forward 10s    >|\r
521   Skip backward 10s   |<\r
522   Skip forward 1m     >>|\r
523   Skip backward 1m    |<<\r
524 \r
525   */\r
526 \r
527   WSymbol w;\r
528   TEMPADD(&w);\r
529   w.nextSymbol = 0;\r
530   w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
531 \r
532   UCHAR playerState = 0;\r
533 \r
534   if (action)\r
535   {\r
536     if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
537     else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
538     else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
539     else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
540   }\r
541   else\r
542   {\r
543     playerState = player->getState();\r
544     if (playerState == PlayerMedia::S_PLAY)      w.nextSymbol = WSymbol::PLAY;\r
545     else if (playerState == PlayerMedia::S_FF)    w.nextSymbol = WSymbol::FFWD;\r
546     else if (playerState == PlayerMedia::S_BACK)    w.nextSymbol = WSymbol::FBWD;\r
547     else if (playerState == PlayerMedia::S_SEEK)    w.nextSymbol = WSymbol::RIGHTARROW;\r
548     else if (playerState == PlayerMedia::S_STOP)    w.nextSymbol = WSymbol::PAUSE;\r
549     else                                       w.nextSymbol = WSymbol::PAUSE;\r
550   }\r
551 \r
552   w.draw();\r
553 \r
554   if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))\r
555   {\r
556     // draw blips to show how fast the scan is\r
557     UCHAR scanrate = 2;//player->getIScanRate();\r
558     if (scanrate >= 2)\r
559     {\r
560       char text[5];\r
561       SNPRINTF(text, 5, "%ux", scanrate);\r
562       drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
563     }\r
564   }\r
565 \r
566   drawBarClocks();\r
567   boxstack->update(this, &barRegion);\r
568 \r
569   timers->cancelTimer(this, 1);\r
570 \r
571 \r
572   if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;\r
573   else barScanHold = false;\r
574 \r
575   if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
576 \r
577   if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);\r
578   else timers->setTimerD(this, 2, 1);\r
579 }\r
580 \r
581 void VVideoMedia::timercall(int clientReference)\r
582 {\r
583   Message *m=new Message();\r
584   m->message=Message::PLAYER_EVENT;\r
585   m->to=this;\r
586   m->from=this;\r
587   m->parameter=PLAYER_TIMER_BASE+clientReference;\r
588   Command::getInstance()->postMessageFromOuterSpace(m);\r
589 }\r
590 \r
591 void VVideoMedia::drawBarClocks()\r
592 {\r
593   if (barScanHold)\r
594   {\r
595     UCHAR playerState = player->getState();\r
596     // sticky bar is set if we are in ffwd/fbwd mode\r
597     // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
598     // will repaint all the bar (it will call this function again, but\r
599     // this section won't run because stickyBarF will then == false)\r
600 \r
601     if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))\r
602     {\r
603       barScanHold = false;\r
604       doBar(0);\r
605       return; \r
606     }\r
607   }\r
608 \r
609   Log* logger = Log::getInstance();\r
610   logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");\r
611 \r
612   // Draw RTC\r
613   // Blank the area first\r
614   rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
615   char timeString[20];\r
616   time_t t;\r
617   time(&t);\r
618   struct tm* tms = localtime(&t);\r
619   strftime(timeString, 19, "%H:%M", tms);\r
620   drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
621 \r
622   ULLONG lenPTS=player->getLenPTS();\r
623   // Draw clocks\r
624 \r
625   rectangle(clocksRegion, barBlue);\r
626 \r
627   ULLONG currentPTS = player->getCurrentPTS();\r
628 \r
629   hmsf currentFrameHMSF = ptsToHMS(currentPTS);\r
630   hmsf lengthHMSF = ptsToHMS(lenPTS);\r
631 \r
632   char buffer[100];\r
633   if (currentPTS > lenPTS && lenPTS != 0)\r
634   {\r
635     strcpy(buffer, "-:--:-- / -:--:--");\r
636   }\r
637   else\r
638   {\r
639     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
640   }\r
641     logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);\r
642 \r
643   drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
644 \r
645 \r
646 \r
647 \r
648 \r
649 \r
650 \r
651   // Draw progress bar\r
652   int progBarXbase = barRegion.x + 300;\r
653 \r
654   if (lenPTS == 0) return;\r
655   rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);\r
656   rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
657 \r
658   if (currentPTS > lenPTS) return;\r
659 \r
660   // Draw yellow portion\r
661   int progressWidth = 302 * currentPTS / lenPTS;\r
662   rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
663 \r
664 }\r
665 \r
666 void VVideoMedia::removeBar()\r
667 {\r
668   if (!barShowing) return;\r
669   timers->cancelTimer(this, 2);\r
670   barShowing = false;\r
671   barGenHold = false;\r
672   barScanHold = false;\r
673   barVasHold = false;\r
674   rectangle(barRegion, transparent);\r
675   BoxStack::getInstance()->update(this, &barRegion);\r
676 }\r
677 \r
678 void VVideoMedia::doSummary()\r
679 {\r
680   vsummary = new VInfo();\r
681   vsummary->setTitleText(myMedia->getDisplayName());\r
682   vsummary->setBorderOn(1);\r
683   vsummary->setExitable();\r
684   const MediaURI *u=myMedia->getURI();\r
685   int stlen=0;\r
686   if (u) {\r
687     stlen+=strlen(myMedia->getFileName());\r
688     stlen+=strlen(tr("FileName"))+10;\r
689   }\r
690   stlen+=strlen(tr("Size"))+50;\r
691   stlen+=strlen(tr("Directory"))+500;\r
692   stlen+=strlen(tr("Time"))+50;\r
693   char *pinfo=player->getInfo();\r
694   stlen+=strlen(pinfo)+10;\r
695   char *buf=new char [stlen];\r
696   char *tsbuf=new char [stlen];\r
697   char *tsbuf2=new char [stlen];\r
698   char *tbuf=new char[Media::TIMEBUFLEN];\r
699   SNPRINTF(buf,stlen,"%s\n" \r
700                    "%s: %llu Bytes\n"\r
701                    "%s\n"\r
702                    "%s: %s\n"\r
703                    "%s",\r
704       shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),\r
705       tr("Size"),\r
706       lengthBytes,\r
707       shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),\r
708       tr("Time"),\r
709       myMedia->getTimeString(tbuf),\r
710       pinfo\r
711       );\r
712   //TODO more info\r
713   if (u) {\r
714       Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);\r
715       vsummary->setMainText(buf);\r
716   }\r
717   else vsummary->setMainText(tr("Info unavailable"));\r
718   delete pinfo;\r
719   if (Video::getInstance()->getFormat() == Video::PAL)\r
720   {\r
721     vsummary->setPosition(70, 100);\r
722   }\r
723   else\r
724   {\r
725     vsummary->setPosition(40, 70);\r
726   }\r
727   vsummary->setSize(580, 350);\r
728   add(vsummary);\r
729   vsummary->draw();\r
730 \r
731   BoxStack::getInstance()->update(this);\r
732    delete [] buf;\r
733   delete []  tsbuf;\r
734   delete [] tsbuf2;\r
735   delete []  tbuf;\r
736 }\r
737 \r
738 void VVideoMedia::removeSummary()\r
739 {\r
740   if (vsummary)\r
741   {\r
742     remove(vsummary);\r
743     delete vsummary;\r
744     vsummary = NULL;\r
745     draw();\r
746     BoxStack::getInstance()->update(this);\r
747   }\r
748 }\r
749 \r
750 \r
751 hmsf VVideoMedia::ptsToHMS(ULLONG pts) {\r
752   ULLONG secs=pts/90000;\r
753   hmsf rt;\r
754   rt.frames=0;\r
755   rt.seconds=secs%60;\r
756   secs=secs/60;\r
757   rt.minutes=secs%60;\r
758   secs=secs/60;\r
759   rt.hours=secs;\r
760   return rt;\r
761 }\r
762   \r
763 char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {\r
764   if (! intext) {\r
765     intext="";\r
766   }\r
767   UINT twidth=0;\r
768   for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);\r
769   for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);\r
770   const char *prfx="...";\r
771   UINT prfwidth=3*charWidth('.');\r
772   const char *istart=intext+strlen(intext);\r
773   UINT iwidth=0;\r
774   while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {\r
775     istart--;\r
776     iwidth+=charWidth(*istart);\r
777   }\r
778   if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;\r
779   if (istart == intext) prfx="";\r
780   sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);\r
781   return buffer;\r
782 }\r
783 \r
784 \r