2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
20 #include "vvideomedia.h"
21 #include "vmedialist.h"
23 #include "mediaplayer.h"
29 #include "playermedia.h"
30 #include "recording.h"
31 #include "vaudioselector.h"
39 #include "messagequeue.h"
41 //use the picture channel
42 #define MEDIACHANNEL 1
44 //we misuse PLAYER_EVENTS for timer messages
45 //this should be larger then any player message
46 #define PLAYER_TIMER_BASE 100
48 VVideoMedia::VVideoMedia(Media* media, VMediaList *p)
51 boxstack = BoxStack::getInstance();
52 video = Video::getInstance();
53 timers = Timers::getInstance();
57 myMedia = new Media(media);
59 player = new PlayerMedia(this);
62 videoMode = video->getMode();
67 setSize(video->getScreenWidth(), video->getScreenHeight());
69 transparent.set(0, 0, 0, 0);
70 setBackgroundColour(transparent);
73 barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?
74 barRegion.w = video->getScreenWidth();
77 clocksRegion.x = barRegion.x + 140;
78 clocksRegion.y = barRegion.y + 12;
80 clocksRegion.h = getFontHeight();
83 barBlue.set(0, 0, 150, 150);
91 char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");
94 if (strstr(optionWSS, "Yes")) dowss = true;
97 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);
101 wss.setFormat(video->getFormat());
107 wssRegion.w = video->getScreenWidth();
112 VVideoMedia::~VVideoMedia()
114 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering destructor");
118 boxstack->remove(vas);
127 if (playing) stopPlay();
128 video->setDefaultAspect();
130 timers->cancelTimer(this, 1);
131 timers->cancelTimer(this, 2);
134 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");
137 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");
140 void VVideoMedia::go(bool resume)
142 ULONG startFrameNum=0;
144 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);
149 const MediaURI *u=myMedia->getURI();
151 Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());
155 rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);
159 //TODO: figure out len in frames
160 int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);
161 int ok=player->waitForSequence(2,seq);
170 stopPlay(); // clean up
172 Message* m = new Message();
173 m->message = Message::CLOSE_ME;
175 m->p_to = Message::BOXSTACK;
176 MessageQueue::getInstance()->postMessage(m);
178 VInfo* vi = new VInfo();
179 vi->setSize(400, 150);
181 if (video->getFormat() == Video::PAL)
182 vi->setPosition(170, 200);
184 vi->setPosition(160, 150);
187 vi->setTitleBarOn(0);
188 vi->setOneLiner(tr("Error playing media"));
192 m->message = Message::ADD_VIEW;
193 m->p_to = Message::BOXSTACK;
194 m->data = reinterpret_cast<void*>(vi);
195 MessageQueue::getInstance()->postMessage(m);
199 int VVideoMedia::handleCommand(int command)
221 if (playing) stopPlay();
231 case Input::SKIPFORWARD:
234 player->skipForward(60);
237 case Input::SKIPBACK:
240 player->skipBackward(60);
245 player->fastForward();
251 player->fastBackward();
257 if (vsummary) removeSummary();
269 player->skipBackward(10);
275 player->skipForward(10);
281 player->skipBackward(10);
287 player->skipForward(10);
305 if (barShowing) removeBar();
313 case Input::ZERO: player->jumpToPercent(0); doBar(0); return 2;
314 case Input::ONE: player->jumpToPercent(10); doBar(0); return 2;
315 case Input::TWO: player->jumpToPercent(20); doBar(0); return 2;
316 case Input::THREE: player->jumpToPercent(30); doBar(0); return 2;
317 case Input::FOUR: player->jumpToPercent(40); doBar(0); return 2;
318 case Input::FIVE: player->jumpToPercent(50); doBar(0); return 2;
319 case Input::SIX: player->jumpToPercent(60); doBar(0); return 2;
320 case Input::SEVEN: player->jumpToPercent(70); doBar(0); return 2;
321 case Input::EIGHT: player->jumpToPercent(80); doBar(0); return 2;
322 case Input::NINE: player->jumpToPercent(90); doBar(0); return 2;
330 void VVideoMedia::processMessage(Message* m)
332 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");
334 if (m->message == Message::MOUSE_LBDOWN)
336 UINT x = m->parameter - getScreenX();
337 UINT y = m->tag - getScreenY();
341 BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
343 else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
345 int progBarXbase = barRegion.x + 300;
346 if (x>=barRegion.x + progBarXbase + 24
347 && x<=barRegion.x + progBarXbase + 4 + 302
348 && y>=barRegion.y + 12 - 2
349 && y<=barRegion.y + 12 - 2+28)
351 int cx=x-(barRegion.x + progBarXbase + 4);
352 double percent=((double)cx)/302.*100.;
353 player->jumpToPercent(percent);
356 // int progressWidth = 302 * currentFrameNum / lengthFrames;
357 // rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
362 BoxStack::getInstance()->handleCommand(Input::OK); //simulate rok press
365 else if (m->message == Message::PLAYER_EVENT)
369 case PlayerMedia::CONNECTION_LOST: // connection lost detected
371 // I can't handle this, send it to control
372 Message* m2 = new Message();
373 m2->p_to = Message::CONTROL;
374 m2->message = Message::CONNECTION_LOST;
375 MessageQueue::getInstance()->postMessage(m2);
378 case PlayerMedia::STREAM_END:
380 Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
381 m2->p_to = Message::BOXSTACK;
382 m2->message = Message::CLOSE_ME;
383 MessageQueue::getInstance()->postMessage(m2);
386 case PlayerMedia::STATUS_CHANGE:
389 case PlayerMedia::ASPECT43:
393 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");
396 boxstack->update(this, &wssRegion);
400 case PlayerMedia::ASPECT169:
404 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");
407 boxstack->update(this, &wssRegion);
411 case (PLAYER_TIMER_BASE+1) :
416 case (PLAYER_TIMER_BASE+2) :
419 if (!barShowing) break;
421 BoxStack::getInstance()->update(this,&barRegion);
422 if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
423 else timers->setTimerD(this, 2, 1);
427 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
429 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);
430 player->setAudioChannel(m->parameter);
432 else if (m->message == Message::CHILD_CLOSE)
438 if (!barGenHold && !barScanHold && !barVasHold) removeBar();
443 void VVideoMedia::stopPlay()
445 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");
452 MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);
454 Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");
457 void VVideoMedia::toggleChopSides()
459 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
461 if (videoMode == Video::NORMAL)
463 videoMode = Video::LETTERBOX;
464 video->setMode(Video::LETTERBOX);
468 videoMode = Video::NORMAL;
469 video->setMode(Video::NORMAL);
473 void VVideoMedia::doAudioSelector()
475 bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
476 bool* availableAc3AudioChannels = 0;
477 int currentAudioChannel = player->getCurrentAudioChannel();
478 if (Audio::getInstance()->supportsAc3())
480 availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
485 ri.summary=new char[strlen(myMedia->getDisplayName())+1];
486 strcpy(ri.summary,myMedia->getDisplayName());
487 vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);
489 vas->setBackgroundColour(barBlue);
490 vas->setPosition(0, barRegion.y - 120);
499 boxstack->update(vas);
502 void VVideoMedia::doBar(int action)
504 Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);
507 rectangle(barRegion, barBlue);
509 /* Work out what to display - choices:
516 Specials, informed by parameter
528 w.setPosition(barRegion.x + 66, barRegion.y + 16);
530 UCHAR playerState = 0;
534 if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;
535 else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;
536 else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;
537 else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;
541 playerState = player->getState();
542 if (playerState == PlayerMedia::S_PLAY) w.nextSymbol = WSymbol::PLAY;
543 else if (playerState == PlayerMedia::S_FF) w.nextSymbol = WSymbol::FFWD;
544 else if (playerState == PlayerMedia::S_BACK) w.nextSymbol = WSymbol::FBWD;
545 else if (playerState == PlayerMedia::S_SEEK) w.nextSymbol = WSymbol::RIGHTARROW;
546 else if (playerState == PlayerMedia::S_STOP) w.nextSymbol = WSymbol::PAUSE;
547 else w.nextSymbol = WSymbol::PAUSE;
552 if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))
554 // draw blips to show how fast the scan is
555 UCHAR scanrate = 2;//player->getIScanRate();
559 SNPRINTF(text, 5, "%ux", scanrate);
560 drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);
565 boxstack->update(this, &barRegion);
567 timers->cancelTimer(this, 1);
570 if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;
571 else barScanHold = false;
573 if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
575 if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
576 else timers->setTimerD(this, 2, 1);
579 void VVideoMedia::timercall(int clientReference)
581 Message *m=new Message();
582 m->message=Message::PLAYER_EVENT;
585 m->parameter=PLAYER_TIMER_BASE+clientReference;
586 MessageQueue::getInstance()->postMessage(m);
589 void VVideoMedia::drawBarClocks()
593 UCHAR playerState = player->getState();
594 // sticky bar is set if we are in ffwd/fbwd mode
595 // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
596 // will repaint all the bar (it will call this function again, but
597 // this section won't run because stickyBarF will then == false)
599 if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))
607 Log* logger = Log::getInstance();
608 logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");
611 // Blank the area first
612 rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
617 LOCALTIME_R(&t, &tms);
619 strftime(timeString, 19, "%H:%M", &tms);
620 drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);
622 ULLONG lenPTS=player->getLenPTS();
625 rectangle(clocksRegion, barBlue);
627 ULLONG currentPTS = player->getCurrentPTS();
629 hmsf currentFrameHMSF = ptsToHMS(currentPTS);
630 hmsf lengthHMSF = ptsToHMS(lenPTS);
633 if (currentPTS > lenPTS && lenPTS != 0)
635 strcpy(buffer, "-:--:-- / -:--:--");
639 SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
641 logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);
643 drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
652 int progBarXbase = barRegion.x + 300;
654 if (lenPTS == 0) return;
655 rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);
656 rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
658 if (currentPTS > lenPTS) return;
660 // Draw yellow portion
661 int progressWidth = 302 * currentPTS / lenPTS;
662 rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
666 void VVideoMedia::removeBar()
668 if (!barShowing) return;
669 timers->cancelTimer(this, 2);
674 rectangle(barRegion, transparent);
675 BoxStack::getInstance()->update(this, &barRegion);
678 void VVideoMedia::doSummary()
680 vsummary = new VInfo();
681 vsummary->setTitleText(myMedia->getDisplayName());
682 vsummary->setBorderOn(1);
683 vsummary->setExitable();
684 const MediaURI *u=myMedia->getURI();
687 stlen+=strlen(myMedia->getFileName());
688 stlen+=strlen(tr("FileName"))+10;
690 stlen+=strlen(tr("Size"))+50;
691 stlen+=strlen(tr("Directory"))+500;
692 stlen+=strlen(tr("Time"))+50;
693 char *pinfo=player->getInfo();
694 stlen+=strlen(pinfo)+10;
695 char *buf=new char [stlen];
696 char *tsbuf=new char [stlen];
697 char *tsbuf2=new char [stlen];
698 char *tbuf=new char[Media::TIMEBUFLEN];
699 SNPRINTF(buf,stlen,"%s\n"
704 shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),
707 shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),
709 myMedia->getTimeString(tbuf),
714 Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);
715 vsummary->setMainText(buf);
717 else vsummary->setMainText(tr("Info unavailable"));
719 if (Video::getInstance()->getFormat() == Video::PAL)
721 vsummary->setPosition(70, 100);
725 vsummary->setPosition(40, 70);
727 vsummary->setSize(580, 350);
731 BoxStack::getInstance()->update(this);
738 void VVideoMedia::removeSummary()
746 BoxStack::getInstance()->update(this);
751 hmsf VVideoMedia::ptsToHMS(ULLONG pts) {
752 ULLONG secs=pts/90000;
763 char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {
768 for (const char *p=title;*p!=0;p++) twidth+=(UINT)charWidth(*p);
769 for (const char *p=title2;*p!=0;p++) twidth+=(UINT)charWidth(*p);
770 const char *prfx="...";
771 UINT prfwidth=(UINT)(3*charWidth('.'));
772 const char *istart=intext+strlen(intext);
774 while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {
776 iwidth+=(UINT)charWidth(*istart);
778 if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;
779 if (istart == intext) prfx="";
780 sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);