Ticket #843: pipplayer.5.diff
File pipplayer.5.diff, 78.7 KB (added by , 17 years ago) |
---|
-
libs/libmythtv/NuppelVideoPlayer.cpp
204 204 audio_samplerate(44100), audio_stretchfactor(1.0f), 205 205 // Picture-in-Picture 206 206 pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false), 207 ispip(false), softwareScalingPIP(false), 207 208 // Preview window support 208 209 argb_buf(NULL), argb_size(0,0), 209 210 yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)), … … 294 295 295 296 if (m_playbackinfo) 296 297 { 297 m_playbackinfo->MarkAsInUse(false); 298 if (!ispip) 299 m_playbackinfo->MarkAsInUse(false); 298 300 delete m_playbackinfo; 299 301 } 300 302 … … 540 542 return false; 541 543 } 542 544 545 if (ispip) 546 { 547 if (m_tv) 548 videoOutput->SetAsPIP(kPIPOnTV); 549 else 550 videoOutput->SetAsPIP(kPIPOn); 551 } 552 543 553 if (!videoOutput->Init(video_width, video_height, video_aspect, 544 554 widget->winId(), 0, 0, widget->width(), 545 555 widget->height(), 0)) 546 556 { 547 557 errored = true; 558 } 559 560 if (errored && !videoOutput->hasXVAcceleration() && ispip) 561 { 562 softwareScalingPIP = true; 563 delete videoOutput; 564 videoOutput = NULL; 565 errored = true; 548 566 return false; 549 567 } 550 568 … … 636 654 { 637 655 QString errMsg = QString::null; 638 656 639 if ( (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))657 if (ispip || (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0)) 640 658 { 641 659 VERBOSE(VB_IMPORTANT, LOC + 642 660 QString("Disabling Audio, params(%1,%2,%3)") … … 756 774 757 775 void NuppelVideoPlayer::AutoDeint(VideoFrame *frame) 758 776 { 759 if (!frame || m_scan_locked )777 if (!frame || m_scan_locked || ispip) 760 778 return; 761 779 762 780 if (frame->interlaced_frame) … … 798 816 { 799 817 QMutexLocker locker(&videofiltersLock); 800 818 801 if (!videoOutput || !videosync )819 if (!videoOutput || !videosync || ispip) 802 820 return; // hopefully this will be called again later... 803 821 804 822 m_scan_locked = (scan != kScan_Detect); … … 1059 1078 1060 1079 void NuppelVideoPlayer::InitFilters(void) 1061 1080 { 1081 if (ispip) 1082 return; 1083 1062 1084 VideoFrameType itmp = FMT_YV12; 1063 1085 VideoFrameType otmp = FMT_YV12; 1064 1086 int btmp; … … 2553 2575 else if (videoOutput) 2554 2576 { 2555 2577 // Set up deinterlacing in the video output method 2556 m_double_framerate = 2557 (videoOutput->SetupDeinterlace(true) && 2558 videoOutput->NeedsDoubleFramerate()); 2559 2578 if (ispip) 2579 { 2580 m_double_framerate = false; 2581 videoOutput->SetupDeinterlace(true, "linearblend"); 2582 } 2583 else 2584 { 2585 m_double_framerate = 2586 (videoOutput->SetupDeinterlace(true) && 2587 videoOutput->NeedsDoubleFramerate()); 2588 } 2589 2560 2590 videosync = VideoSync::BestMethod( 2561 2591 videoOutput, fr_int, rf_int, m_double_framerate); 2562 2592 … … 2589 2619 { 2590 2620 pipplayer = setpipplayer; 2591 2621 needsetpipplayer = false; 2622 if (m_tv) 2623 m_tv->PIPPlayerWake(); 2592 2624 } 2593 2625 2594 2626 if (ringBuffer->isDVD()) … … 3049 3081 3050 3082 if (!InitVideo()) 3051 3083 { 3052 qApp->lock(); 3053 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3084 if (!ispip) 3085 { 3086 qApp->lock(); 3087 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3054 3088 QObject::tr("Unable to initialize video.")); 3055 dialog->AddButton(QObject::tr("Return to menu.")); 3056 dialog->exec(); 3057 delete dialog; 3089 dialog->AddButton(QObject::tr("Return to menu.")); 3090 dialog->exec(); 3091 delete dialog; 3092 qApp->unlock(); 3093 } 3058 3094 3059 qApp->unlock();3060 3061 3095 if (audioOutput) 3062 3096 { 3063 3097 delete audioOutput; … … 3656 3690 int numFrames = totalFrames; 3657 3691 3658 3692 if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE) 3659 numFrames = ( m_playbackinfo->endts.toTime_t() -3660 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate ;3693 numFrames = (int)((m_playbackinfo->endts.toTime_t() - 3694 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate); 3661 3695 3662 3696 int offset = (int) round(0.14 * (numFrames / video_frame_rate)); 3663 3697 -
libs/libmythtv/libmythtv.pro
216 216 217 217 # Video playback 218 218 HEADERS += tv_play.h NuppelVideoPlayer.h 219 HEADERS += DVDRingBuffer.h 219 HEADERS += DVDRingBuffer.h pipplayer.h 220 220 SOURCES += tv_play.cpp NuppelVideoPlayer.cpp 221 SOURCES += DVDRingBuffer.cpp 221 SOURCES += DVDRingBuffer.cpp pipplayer.cpp 222 222 223 223 # Text subtitle parser 224 224 HEADERS += textsubtitleparser.h xine_demux_sputext.h -
libs/libmythtv/tv_play.h
33 33 class OSDListTreeType; 34 34 class OSDGenericTree; 35 35 class LiveTVChain; 36 class PIPPlayer; 36 37 37 38 typedef QValueVector<QString> str_vec_t; 38 39 typedef QMap<QString,QString> InfoMap; … … 126 127 void ShowNoRecorderDialog(void); 127 128 void FinishRecording(void); 128 129 void AskAllowRecording(const QStringList&, int, bool); 130 void PIPPlayerWake(void) { pipplayerCond.wakeAll(); } 129 131 void PromptStopWatchingRecording(void); 130 132 void PromptDeleteRecording(QString title); 131 133 132 133 134 // Boolean queries 134 135 135 136 /// Returns true if we are playing back a non-LiveTV recording. … … 320 321 321 322 void SetupPlayer(bool isWatchingRecording); 322 323 void TeardownPlayer(void); 323 void SetupPipPlayer(void);324 void TeardownPipPlayer(void);325 324 326 325 void HandleStateChange(void); 327 326 bool InStateChange(void) const; … … 331 330 void TogglePIPView(void); 332 331 void ToggleActiveWindow(void); 333 332 void SwapPIP(void); 333 TVState GetPIPState(PIPPlayer *pip); 334 334 void SwapPIPSoon(void) { needToSwapPIP = true; } 335 335 336 336 void ToggleAutoExpire(void); 337 337 338 338 void BrowseStart(void); … … 529 529 530 530 // Video Players 531 531 NuppelVideoPlayer *nvp; 532 NuppelVideoPlayer *pipnvp;532 PIPPlayer *pipplayer; 533 533 NuppelVideoPlayer *activenvp; ///< Player to which LiveTV events are sent 534 534 535 //PIP Stuff 536 QWaitCondition pipplayerCond; 537 535 538 // Remote Encoders 536 539 /// Main recorder 537 540 RemoteEncoder *recorder; 538 /// Picture-in-Picture recorder539 RemoteEncoder *piprecorder;540 541 /// Recorder to which LiveTV events are being sent 541 542 RemoteEncoder *activerecorder; 542 543 /// Main recorder to use after a successful SwitchCards() call. … … 546 547 547 548 // LiveTVChain 548 549 LiveTVChain *tvchain; 549 LiveTVChain *piptvchain;550 550 QStringList tvchainUpdate; 551 551 QMutex tvchainUpdateLock; 552 552 553 553 // RingBuffers 554 554 RingBuffer *prbuffer; 555 RingBuffer *piprbuffer;556 555 RingBuffer *activerbuffer; ///< Ringbuffer to which LiveTV events are sent 557 556 558 557 // OSD info … … 589 588 pthread_t event; 590 589 /// Video decoder thread, runs nvp's NuppelVideoPlayer::StartPlaying(). 591 590 pthread_t decode; 592 /// Picture-in-Picture video decoder thread,593 /// runs pipnvp's NuppelVideoPlayer::StartPlaying().594 pthread_t pipdecode;595 591 596 592 /// Condition to signal that the Event thread is up and running 597 593 QWaitCondition mainLoopCond; -
libs/libmythtv/pipplayer.h
1 #ifndef PIPPLAYER_H 2 #define PIPPLAYER_H 3 4 #include <qpainter.h> 5 #include "NuppelVideoPlayer.h" 6 #include "RingBuffer.h" 7 #include "programinfo.h" 8 #include "livetvchain.h" 9 #include "remoteencoder.h" 10 11 class RingBuffer; 12 class ProgramInfo; 13 class LiveTVChain; 14 class RemoteEncoder; 15 class NuppelVideoPlayer; 16 17 class PIPPlayer 18 { 19 public: 20 PIPPlayer(void); 21 ~PIPPlayer(void); 22 static PIPPlayer *Create(const QRect &rect); 23 static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location); 24 bool StartPlaying(ProgramInfo *rec = NULL, 25 bool piptype = false, 26 bool nullvideo = false); 27 void StopPlaying(); 28 bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); } 29 bool IsSameProgram(ProgramInfo *rec); 30 RingBuffer *GetRingBuffer(void) { return piprbuffer; } 31 RemoteEncoder *GetRecorder(void) { return piprecorder; } 32 LiveTVChain *GetLiveTVChain(void) { return piptvchain; } 33 NuppelVideoPlayer *GetNVP(void) { return pipnvp; } 34 ProgramInfo *GetProgramInfo(void) { return piprecinfo; } 35 void SetRingBuffer(RingBuffer *rbuffer); 36 void SetLiveTVChain(LiveTVChain *tvchain); 37 void SetRecorder(RemoteEncoder *recorder); 38 void SetProgramInfo(ProgramInfo *pginfo); 39 void SetReinit(bool change) { reinit = change; } 40 bool IsLiveTV(void) { return islivetv; } 41 bool IsHidden(void); 42 void Hide(void); 43 void Show(void); 44 bool UsingNullVideo(void) { return using_nullvideo; } 45 void DisplaySoftwareScaledImage(void); 46 47 48 private: 49 bool StartRecorder(RemoteEncoder *rec, int maxWait); 50 void Reinitialize(void); 51 void Init(QRect rect, QString name); 52 53 private: 54 RemoteEncoder *piprecorder; 55 RingBuffer *piprbuffer; 56 LiveTVChain *piptvchain; 57 ProgramInfo *piprecinfo; 58 NuppelVideoPlayer *pipnvp; 59 pthread_t videoThread; 60 pthread_t pipdecode; 61 QWidget *pipWindow; 62 bool islivetv; 63 bool reinit; 64 bool using_nullvideo; 65 }; 66 67 #endif 68 #ifndef PIPPLAYER_H 69 #define PIPPLAYER_H 70 71 #include <qpainter.h> 72 #include "NuppelVideoPlayer.h" 73 #include "RingBuffer.h" 74 #include "programinfo.h" 75 #include "livetvchain.h" 76 #include "remoteencoder.h" 77 78 class RingBuffer; 79 class ProgramInfo; 80 class LiveTVChain; 81 class RemoteEncoder; 82 class NuppelVideoPlayer; 83 84 class PIPPlayer 85 { 86 public: 87 PIPPlayer(void); 88 ~PIPPlayer(void); 89 static PIPPlayer *Create(const QRect &rect); 90 static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location); 91 bool StartPlaying(ProgramInfo *rec = NULL, 92 bool piptype = false, 93 bool nullvideo = false); 94 void StopPlaying(); 95 bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); } 96 void SetFrameRate(double fps); 97 bool IsSameProgram(ProgramInfo *rec); 98 RingBuffer *GetRingBuffer(void) { return piprbuffer; } 99 RemoteEncoder *GetRecorder(void) { return piprecorder; } 100 LiveTVChain *GetLiveTVChain(void) { return piptvchain; } 101 NuppelVideoPlayer *GetNVP(void) { return pipnvp; } 102 ProgramInfo *GetProgramInfo(void) { return piprecinfo; } 103 void SetRingBuffer(RingBuffer *rbuffer); 104 void SetLiveTVChain(LiveTVChain *tvchain); 105 void SetRecorder(RemoteEncoder *recorder); 106 void SetProgramInfo(ProgramInfo *pginfo); 107 void SetReinit(bool change) { reinit = change; } 108 bool IsLiveTV(void) { return islivetv; } 109 bool IsHidden(void); 110 void Hide(void); 111 void Show(void); 112 bool UsingNullVideo(void) { return using_nullvideo; } 113 void DisplaySoftwareScaledImage(void); 114 115 116 private: 117 bool StartRecorder(RemoteEncoder *rec, int maxWait); 118 void Reinitialize(void); 119 void Init(QRect rect, QString name); 120 121 private: 122 RemoteEncoder *piprecorder; 123 RingBuffer *piprbuffer; 124 LiveTVChain *piptvchain; 125 ProgramInfo *piprecinfo; 126 NuppelVideoPlayer *pipnvp; 127 pthread_t videoThread; 128 pthread_t pipdecode; 129 QWidget *pipWindow; 130 bool islivetv; 131 bool reinit; 132 bool using_nullvideo; 133 }; 134 135 #endif -
libs/libmythtv/NuppelVideoPlayer.h
128 128 129 129 // Sets 130 130 void SetParentWidget(QWidget *widget) { parentWidget = widget; } 131 void SetAsPIP(void) { SetNoAudio(); SetNullVideo(); } 131 void SetAsPIP(bool setNullVideo) 132 { if (setNullVideo) SetNullVideo(); ispip = true; } 132 133 void SetNullVideo(void) { using_null_videoout = true; } 133 134 void SetFileName(QString lfilename) { filename = lfilename; } 134 135 void SetExactSeeks(bool exact) { exactseeks = exact; } … … 140 141 void SetVideoFilters(QString &filters) { videoFilterList = filters; } 141 142 void SetFramesPlayed(long long played) { framesPlayed = played; } 142 143 void SetEof(void) { eof = true; } 143 void SetP ipPlayer(NuppelVideoPlayer *pip)144 void SetPIPPlayer(NuppelVideoPlayer *pip) 144 145 { setpipplayer = pip; needsetpipplayer = true; } 145 146 void SetRecorder(RemoteEncoder *recorder); 146 147 void SetParentPlayer(TV *tv) { m_tv = tv; } … … 193 194 bool GetRawAudioState(void) const; 194 195 bool GetLimitKeyRepeat(void) const { return limitKeyRepeat; } 195 196 bool GetEof(void) const { return eof; } 196 bool PipPlayerSet(void) const { return !needsetpipplayer; } 197 bool PIPPlayerSet(void) const { return !needsetpipplayer; } 198 bool HasPIPPlayer(void) const { return (pipplayer != NULL); } 197 199 bool IsErrored(void) const { return errored; } 198 200 bool IsPlaying(void) const { return playing; } 199 201 bool AtNormalSpeed(void) const { return next_normal_speed; } … … 203 205 bool PlayingSlowForPrebuffer(void) const { return m_playing_slower; } 204 206 bool HasAudioIn(void) const { return !no_audio_in; } 205 207 bool HasAudioOut(void) const { return !no_audio_out; } 208 bool PIPSoftwareScaling(void) { return softwareScalingPIP; } 206 209 207 210 // Complicated gets 208 211 long long CalcMaxFFTime(long long ff, bool setjump = true) const; … … 223 226 void StartPlaying(void); 224 227 void ResetPlaying(void); 225 228 void StopPlaying(void) { killplayer = true; decoder_thread_alive = false; } 229 226 230 227 231 // Pause stuff 228 232 void PauseDecoder(void); … … 670 674 NuppelVideoPlayer *pipplayer; 671 675 NuppelVideoPlayer *setpipplayer; 672 676 bool needsetpipplayer; 677 bool ispip; 678 bool softwareScalingPIP; 673 679 674 680 // Preview window support 675 681 unsigned char *argb_buf; -
libs/libmythtv/tv_play.cpp
39 39 #include "DVDRingBuffer.h" 40 40 #include "datadirect.h" 41 41 #include "sourceutil.h" 42 #include "pipplayer.h" 42 43 43 44 #ifndef HAVE_ROUND 44 45 #define round(x) ((int) ((x) + 0.5)) … … 462 463 lastProgram(NULL), jumpToProgram(false), 463 464 inPlaylist(false), underNetworkControl(false), 464 465 // Video Players 465 nvp(NULL), pip nvp(NULL), activenvp(NULL),466 nvp(NULL), pipplayer(NULL), activenvp(NULL), 466 467 // Remote Encoders 467 recorder(NULL), piprecorder(NULL),activerecorder(NULL),468 recorder(NULL), activerecorder(NULL), 468 469 switchToRec(NULL), lastrecordernum(-1), 469 470 // LiveTVChain 470 tvchain(NULL), piptvchain(NULL),471 tvchain(NULL), 471 472 // RingBuffers 472 prbuffer(NULL), piprbuffer(NULL),activerbuffer(NULL),473 prbuffer(NULL), activerbuffer(NULL), 473 474 // OSD info 474 475 dialogname(""), treeMenu(NULL), udpnotify(NULL), osdlock(true), 475 476 // LCD Info … … 679 680 delete tvchain; 680 681 } 681 682 682 if (piptvchain)683 {684 VERBOSE(VB_IMPORTANT, LOC + "Deleting PiP TV Chain in destructor");685 piptvchain->DestroyChain();686 delete piptvchain;687 }688 689 683 if (ddMapLoaderRunning) 690 684 { 691 685 pthread_join(ddMapLoader, NULL); … … 699 693 pthread_detach(ddMapLoader); 700 694 } 701 695 } 696 702 697 } 703 698 704 699 TVState TV::GetState(void) const … … 1379 1374 prbuffer->Pause(); 1380 1375 prbuffer->WaitForPause(); 1381 1376 } 1382 1383 if (piprbuffer)1384 {1385 piprbuffer->StopReads();1386 piprbuffer->Pause();1387 piprbuffer->WaitForPause();1388 }1389 1377 } 1390 1378 1391 1379 if (stopPlayers) … … 1393 1381 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (1/2)"); 1394 1382 if (nvp) 1395 1383 nvp->StopPlaying(); 1396 1397 if (pipnvp)1398 pipnvp->StopPlaying();1399 1384 } 1400 1385 1401 1386 if (stopRecorders) … … 1403 1388 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping recorder[s]"); 1404 1389 if (recorder) 1405 1390 recorder->StopLiveTV(); 1406 1407 if (piprecorder)1408 piprecorder->StopLiveTV();1409 1391 } 1410 1392 1411 1393 if (stopPlayers) … … 1413 1395 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (2/2)"); 1414 1396 if (nvp) 1415 1397 TeardownPlayer(); 1416 1417 if (pipnvp) 1418 TeardownPipPlayer(); 1398 if (pipplayer) 1399 { 1400 delete pipplayer; 1401 pipplayer = NULL; 1402 } 1419 1403 } 1420 1404 VERBOSE(VB_PLAYBACK, LOC + "StopStuff() -- end"); 1421 1405 } … … 1497 1481 return filters; 1498 1482 } 1499 1483 1500 void TV::SetupPipPlayer(void)1501 {1502 if (pipnvp)1503 {1504 VERBOSE(VB_IMPORTANT, LOC_ERR +1505 "Attempting to setup a PiP player, but it already exists.");1506 return;1507 }1508 1509 pipnvp = new NuppelVideoPlayer("PIP player");1510 pipnvp->SetAsPIP();1511 pipnvp->SetRingBuffer(piprbuffer);1512 pipnvp->SetRecorder(piprecorder);1513 pipnvp->SetAudioInfo(gContext->GetSetting("AudioOutputDevice"),1514 gContext->GetSetting("PassThruOutputDevice"),1515 gContext->GetNumSetting("AudioSampleRate", 44100));1516 pipnvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking", 0));1517 pipnvp->SetLiveTVChain(piptvchain);1518 1519 pipnvp->SetLength(playbackLen);1520 }1521 1522 1484 void TV::TeardownPlayer(void) 1523 1485 { 1524 1486 if (nvp) … … 1568 1530 prbuffer = activerbuffer = NULL; 1569 1531 } 1570 1532 1571 if (piprbuffer)1572 {1573 delete piprbuffer;1574 piprbuffer = NULL;1575 }1576 1577 1533 if (tvchain) 1578 1534 { 1579 1535 tvchain->DestroyChain(); … … 1582 1538 } 1583 1539 } 1584 1540 1585 void TV::TeardownPipPlayer(void)1586 {1587 if (pipnvp)1588 {1589 if (activerecorder == piprecorder)1590 ToggleActiveWindow();1591 1592 osdlock.lock(); // prevent UpdateOSDSignal from using osd...1593 NuppelVideoPlayer *xnvp = pipnvp;1594 pthread_t xdec = pipdecode;1595 pipnvp = NULL;1596 osdlock.unlock();1597 1598 // NVP may try to get qapp lock if there is an error,1599 // so we need to do this outside of the osdlock.1600 pthread_join(xdec, NULL);1601 delete xnvp;1602 }1603 1604 if (piprecorder)1605 {1606 delete piprecorder;1607 piprecorder = NULL;1608 }1609 1610 if (piprbuffer)1611 {1612 delete piprbuffer;1613 piprbuffer = NULL;1614 }1615 1616 if (piptvchain)1617 {1618 piptvchain->DestroyChain();1619 delete piptvchain;1620 piptvchain = NULL;1621 }1622 }1623 1624 1541 void *TV::EventThread(void *param) 1625 1542 { 1626 1543 TV *thetv = (TV *)param; … … 1686 1603 if (nvp->GetTVChain()) 1687 1604 nvp->CheckTVChain(); 1688 1605 } 1689 if (piptvchain && pipnvp && *it == piptvchain->GetID()) 1606 if (pipplayer && pipplayer->IsLiveTV() 1607 && *it == pipplayer->GetLiveTVChain()->GetID()) 1690 1608 { 1609 LiveTVChain *piptvchain = pipplayer->GetLiveTVChain(); 1691 1610 piptvchain->ReloadAll(); 1692 if (pip nvp->GetTVChain())1693 pip nvp->CheckTVChain();1611 if (pipplayer->GetNVP()->GetTVChain()) 1612 pipplayer->GetNVP()->CheckTVChain(); 1694 1613 } 1695 1614 } 1696 1615 tvchainUpdate.clear(); … … 1752 1671 wantsToQuit = true; 1753 1672 } 1754 1673 1674 if (pipplayer && !pipplayer->IsPlaying()) 1675 TogglePIPView(); 1676 1755 1677 if (StateIsPlaying(internalState)) 1756 1678 { 1757 1679 #ifdef USING_VALGRIND … … 1859 1781 prevChan = tmp; 1860 1782 pseudoLiveTVState[i] = kPseudoRecording; 1861 1783 1862 if (i && pip nvp)1784 if (i && pipplayer) 1863 1785 TogglePIPView(); 1864 1786 } 1865 1787 … … 1976 1898 { 1977 1899 if (nvp) 1978 1900 nvp->ExposeEvent(); 1901 if (pipplayer && pipplayer->GetNVP()) 1902 pipplayer->GetNVP()->ExposeEvent(); 1979 1903 return true; 1980 1904 } 1981 1905 case MythEvent::MythEventMessage: … … 2558 2482 DoQueueTranscode("Low Quality"); 2559 2483 else if (action == "PLAY") 2560 2484 DoPlay(); 2485 else if (action == "TOGGLEPIPMODE") 2486 TogglePIPView(); 2487 else if (action == "TOGGLEPIPWINDOW") 2488 ToggleActiveWindow(); 2489 else if (action == "SWAPPIP") 2490 SwapPIPSoon(); 2561 2491 else if (action == "PAUSE") 2562 2492 DoPause(); 2563 2493 else if (action == "SPEEDINC" && !activerbuffer->InDVDMenuOrStillFrame()) … … 2926 2856 SwitchCards(); 2927 2857 else if (action == "GUIDE") 2928 2858 EditSchedule(kScheduleProgramGuide); 2929 else if (action == "TOGGLEPIPMODE")2930 TogglePIPView();2931 else if (action == "TOGGLEPIPWINDOW")2932 ToggleActiveWindow();2933 else if (action == "SWAPPIP")2934 SwapPIPSoon();2935 2859 else if (action == "TOGGLEBROWSE") 2936 2860 BrowseStart(); 2937 2861 else if (action == "PREVCHAN") … … 3215 3139 3216 3140 void TV::TogglePIPView(void) 3217 3141 { 3218 if (!pip nvp)3142 if (!pipplayer && !activenvp->HasPIPPlayer()) 3219 3143 { 3220 RemoteEncoder *testrec = RemoteRequestRecorder(); 3221 3222 if (!testrec || !testrec->IsValidRecorder()) 3223 { 3224 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder"); 3225 if (testrec) 3226 delete testrec; 3144 int pip_location = gContext->GetNumSetting("PIPLocation", 0); 3145 QRect rect = activenvp->getVideoOutput()->GetPIPRect(pip_location, NULL); 3146 pipplayer = PIPPlayer::Create(rect); 3147 if (!pipplayer) 3227 3148 return; 3228 } 3229 3230 testrec->Setup(); 3231 3232 piptvchain = new LiveTVChain(); 3233 piptvchain->InitializeNewChain("PIP"+gContext->GetHostName()); 3234 testrec->SpawnLiveTV(piptvchain->GetID(), true); 3235 piptvchain->ReloadAll(); 3236 playbackinfo = piptvchain->GetProgramAt(-1); 3237 if (!playbackinfo) 3238 { 3239 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP not successfully started"); 3240 delete testrec; 3241 piptvchain->DestroyChain(); 3242 delete piptvchain; 3243 piptvchain = NULL; 3244 } 3149 pipplayer->Hide(); 3150 pipplayer->StartPlaying(NULL, true); 3151 if (pipplayer->IsPlaying()) 3152 pipplayer->Show(); 3245 3153 else 3246 3154 { 3247 QString playbackURL = playbackinfo->GetPlaybackURL(); 3248 3249 piptvchain->SetProgram(playbackinfo); 3250 piprbuffer = new RingBuffer(playbackURL, false); 3251 piprbuffer->SetLiveMode(piptvchain); 3252 } 3253 3254 piprecorder = testrec; 3255 3256 if (StartRecorder(piprecorder, -1)) 3257 { 3258 SetupPipPlayer(); 3259 VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP"); 3260 pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp); 3261 while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive()) 3155 if (pipplayer->GetNVP() && 3156 pipplayer->GetNVP()->PIPSoftwareScaling()) 3262 3157 { 3263 piptvchain->ReloadAll(); 3264 usleep(5000); 3265 } 3266 VERBOSE(VB_PLAYBACK, "PiP NVP Started"); 3267 3268 if (pipnvp->IsDecoderThreadAlive()) 3269 nvp->SetPipPlayer(pipnvp); 3158 pipplayer->StartPlaying(NULL, true, true); 3159 if (pipplayer->IsPlaying()) 3160 activenvp->SetPIPPlayer(pipplayer->GetNVP()); 3161 pipplayerCond.wait(); 3162 } 3270 3163 else 3271 3164 { 3272 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start"); 3273 osdlock.lock(); 3274 delete pipnvp; 3275 pipnvp = NULL; 3276 osdlock.unlock(); 3277 TeardownPipPlayer(); 3165 delete pipplayer; 3166 pipplayer = NULL; 3278 3167 } 3279 3168 } 3280 else3281 {3282 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");3283 TeardownPipPlayer();3284 }3285 3169 } 3286 3170 else 3287 3171 { 3288 if (activenvp != nvp) 3289 ToggleActiveWindow(); 3290 3291 nvp->SetPipPlayer(NULL); 3292 while (!nvp->PipPlayerSet()) 3293 usleep(50); 3294 3295 piprbuffer->StopReads(); 3296 piprbuffer->Pause(); 3297 while (!piprbuffer->isPaused()) 3298 usleep(50); 3299 3300 pipnvp->StopPlaying(); 3301 3302 piprecorder->StopLiveTV(); 3303 3304 TeardownPipPlayer(); 3305 3306 SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV); 3172 activenvp->SetPIPPlayer(NULL); 3173 pipplayerCond.wait(); 3174 delete pipplayer; 3175 pipplayer = NULL; 3307 3176 } 3308 3177 } 3309 3178 3310 3179 void TV::ToggleActiveWindow(void) 3311 3180 { 3312 if (!pipnvp) 3181 // toggleactivewindow works only if the main window is live tv. 3182 // problem is playbackinfo and internalstate management. 3183 if (!pipplayer || !pipplayer->IsPlaying() || 3184 StateIsPlaying(internalState)) 3185 { 3313 3186 return; 3314 3187 } 3188 3315 3189 lockTimerOn = false; 3190 LiveTVChain *piptvchain = NULL; 3191 3316 3192 if (activenvp == nvp) 3317 3193 { 3318 activenvp = pipnvp; 3319 activerbuffer = piprbuffer; 3320 activerecorder = piprecorder; 3194 3195 activenvp = pipplayer->GetNVP(); 3196 activerbuffer = pipplayer->GetRingBuffer(); 3197 activerecorder = pipplayer->GetRecorder(); 3198 piptvchain = pipplayer->GetLiveTVChain(); 3321 3199 } 3322 3200 else 3323 3201 { 3324 activenvp = nvp;3325 activerbuffer = prbuffer;3202 activenvp = nvp; 3203 activerbuffer = prbuffer; 3326 3204 activerecorder = recorder; 3327 3205 } 3328 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3329 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3330 if (pginfo) 3331 { 3332 SetCurrentlyPlaying(pginfo); 3333 delete pginfo; 3334 } 3206 3207 if (activerecorder) 3208 { 3209 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3210 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3211 if (pginfo) 3212 { 3213 SetCurrentlyPlaying(pginfo); 3214 delete pginfo; 3215 } 3216 } 3335 3217 } 3336 3218 3219 3337 3220 struct pip_info 3338 3221 { 3339 3222 RingBuffer *buffer; 3340 3223 RemoteEncoder *recorder; 3341 3224 LiveTVChain *chain; 3342 3225 long long frame; 3226 ProgramInfo *pginfo; 3343 3227 }; 3344 3228 3345 3229 void TV::SwapPIP(void) 3346 3230 { 3347 if (!pipnvp || !piptvchain || !tvchain) 3231 if (!pipplayer) 3232 // TODO print something on OSD informing use that PIP swap cannot be done 3348 3233 return; 3349 3234 3350 lockTimerOn = false; 3235 bool use_nullvideo = pipplayer->UsingNullVideo(); 3236 bool pipislivetv = StateIsLiveTV(internalState); 3237 3238 if (activenvp != nvp) 3239 ToggleActiveWindow(); 3351 3240 3352 struct pip_info main, pip; 3353 main.buffer = prbuffer; 3354 main.recorder = recorder; 3355 main.chain = tvchain; 3356 main.frame = nvp->GetFramesPlayed(); 3357 pip.buffer = piprbuffer; 3358 pip.recorder = piprecorder; 3359 pip.chain = piptvchain; 3360 pip.frame = pipnvp->GetFramesPlayed(); 3241 if (paused) 3242 DoPause(); 3243 StopFFRew(); 3244 NormalSpeed(); 3361 3245 3246 if (playbackinfo) 3247 playbackinfo->setIgnoreBookmark(false); 3248 if (pipplayer->GetProgramInfo()) 3249 pipplayer->GetProgramInfo()->setIgnoreBookmark(false); 3250 3251 // set the bookmark 3252 activenvp->SetBookmark(); 3253 pipplayer->GetNVP()->SetBookmark(); 3254 3255 struct pip_info main, pip; 3256 main.buffer = prbuffer; 3257 main.recorder = recorder; 3258 main.chain = tvchain; 3259 main.frame = nvp->GetFramesPlayed(); 3260 if (StateIsPlaying(internalState)) 3261 main.pginfo = new ProgramInfo(*playbackinfo); 3262 else 3263 main.pginfo = NULL; 3264 3265 pip.buffer = pipplayer->GetRingBuffer(); 3266 pip.recorder = pipplayer->GetRecorder(); 3267 pip.chain = pipplayer->GetLiveTVChain(); 3268 pip.frame = pipplayer->GetNVP()->GetFramesPlayed(); 3269 if (!pipplayer->IsLiveTV()) 3270 pip.pginfo = new ProgramInfo(*pipplayer->GetProgramInfo()); 3271 else 3272 pip.pginfo = NULL; 3273 3274 pipplayer->Hide(); 3275 if (use_nullvideo) 3276 { 3277 activenvp->SetPIPPlayer(NULL); 3278 pipplayerCond.wait(); 3279 } 3280 pipplayer->SetReinit(false); 3281 pipplayer->StopPlaying(); 3282 3362 3283 prbuffer->Pause(); 3363 3284 prbuffer->WaitForPause(); 3364 3285 3365 piprbuffer->Pause();3366 piprbuffer->WaitForPause();3367 3368 3286 nvp->StopPlaying(); 3369 pipnvp->StopPlaying(); 3287 3370 3288 { 3371 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. .3289 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. 3372 3290 pthread_join(decode, NULL); 3373 3291 delete nvp; 3374 3292 nvp = NULL; 3375 pthread_join(pipdecode, NULL);3376 delete pipnvp;3377 pipnvp = NULL;3378 3293 } 3379 3294 3295 if (playbackinfo) 3296 delete playbackinfo; 3297 3380 3298 activerbuffer = prbuffer = pip.buffer; 3381 3299 activerecorder = recorder = pip.recorder; 3382 3300 tvchain = pip.chain; 3301 playbackinfo = pip.pginfo; 3302 internalState = GetPIPState(pipplayer); 3383 3303 3384 piprbuffer = main.buffer; 3385 piprecorder = main.recorder; 3386 piptvchain = main.chain; 3387 3304 pipplayer->SetRingBuffer(main.buffer); 3305 pipplayer->SetRecorder(main.recorder); 3306 pipplayer->SetLiveTVChain(main.chain); 3307 pipplayer->SetProgramInfo(main.pginfo); 3308 3309 VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1") 3310 .arg(StateToString(internalState))); 3311 3388 3312 prbuffer->Seek(0, SEEK_SET); 3389 3313 prbuffer->Unpause(); 3390 StartPlayer(false);3391 activenvp = nvp;3392 nvp->FastForward(pip.frame/recorder->GetFrameRate());3393 3314 3394 piprbuffer->Seek(0, SEEK_SET); 3395 piprbuffer->Unpause(); 3396 SetupPipPlayer(); 3397 VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP -- restart"); 3398 pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp); 3399 while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive()) 3315 if (internalState == kState_WatchingRecording) 3316 StartPlayer(true); 3317 else 3318 StartPlayer(false); 3319 3320 activenvp = nvp; 3321 usleep(10000); 3322 if (tvchain) 3323 nvp->FastForward(pip.frame/recorder->GetFrameRate()); 3324 3325 pipplayer->GetRingBuffer()->Seek(0, SEEK_SET); 3326 pipplayer->GetRingBuffer()->Unpause(); 3327 3328 if (use_nullvideo) 3400 3329 { 3401 piptvchain->ReloadAll(); 3402 usleep(5000); 3330 pipplayer->StartPlaying(main.pginfo, pipislivetv, true); 3331 if (pipplayer->IsPlaying()) 3332 activenvp->SetPIPPlayer(pipplayer->GetNVP()); 3403 3333 } 3404 VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");3405 pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());3406 3407 if (pipnvp->IsDecoderThreadAlive())3408 nvp->SetPipPlayer(pipnvp);3409 3334 else 3335 pipplayer->StartPlaying(main.pginfo, pipislivetv); 3336 3337 if (pipplayer->IsPlaying()) 3410 3338 { 3411 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start"); 3412 TeardownPipPlayer(); 3339 if (!use_nullvideo) 3340 pipplayer->Show(); 3341 if (pipplayer->GetLiveTVChain()) 3342 { 3343 pipplayer->GetLiveTVChain()->ReloadAll(); 3344 usleep(5000); 3345 } 3413 3346 } 3414 3347 3415 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3416 if (pginfo) 3348 if (internalState == kState_WatchingLiveTV) 3349 SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV); 3350 3351 if (pipplayer->IsLiveTV()) 3352 SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV); 3353 3354 if (pipplayer->GetLiveTVChain()) 3355 pipplayer->GetNVP()->FastForward(main.frame/pipplayer->GetRecorder()->GetFrameRate()); 3356 3357 if (tvchain) 3417 3358 { 3418 SetCurrentlyPlaying(pginfo); 3419 delete pginfo; 3359 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3360 if (pginfo) 3361 { 3362 SetCurrentlyPlaying(pginfo); 3363 delete pginfo; 3364 } 3420 3365 } 3366 pipplayer->SetReinit(true); 3421 3367 } 3422 3368 3369 TVState TV::GetPIPState(PIPPlayer *player) 3370 { 3371 if (player->IsLiveTV()) 3372 return kState_WatchingLiveTV; 3373 else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0)) 3374 return kState_WatchingRecording; 3375 else 3376 return kState_WatchingPreRecorded; 3377 } 3378 3423 3379 void TV::DoPlay(void) 3424 3380 { 3425 3381 float time = 0.0; … … 3474 3430 float time = 0.0; 3475 3431 3476 3432 if (paused) 3433 { 3477 3434 activenvp->Play(normal_speed, true); 3435 if (pipplayer && pipplayer->IsPlaying()) 3436 pipplayer->GetNVP()->Play(normal_speed, true); 3437 } 3478 3438 else 3479 3439 { 3480 3440 if (doing_ff_rew) … … 3485 3445 } 3486 3446 3487 3447 activenvp->Pause(); 3448 if (pipplayer && pipplayer->IsPlaying()) 3449 pipplayer->GetNVP()->Pause(); 3488 3450 } 3489 3451 3490 3452 paused = !paused; … … 3849 3811 3850 3812 RemoteEncoder *testrec = NULL; 3851 3813 3852 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pip nvp)3814 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer) 3853 3815 return; 3854 3816 3855 3817 if (/*chanid || */!channum.isEmpty()) … … 5369 5331 menurunning = false; 5370 5332 AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec); 5371 5333 } 5372 else if (pip recorder&&5373 cardnum == pip recorder->GetRecorderNumber())5334 else if (pipplayer && pipplayer->GetRecorder() && 5335 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5374 5336 { 5375 5337 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording"); 5376 5338 TogglePIPView(); … … 5388 5350 wantsToQuit = false; 5389 5351 exitPlayer = true; 5390 5352 } 5391 else if (pip recorder&&5392 cardnum == pip recorder->GetRecorderNumber())5353 else if (pipplayer && pipplayer->GetRecorder() && 5354 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5393 5355 { 5394 5356 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV"); 5395 5357 TogglePIPView(); … … 5405 5367 uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1; 5406 5368 5407 5369 if ((recorder && cardnum == recorder->GetRecorderNumber()) || 5408 (piprecorder && cardnum == piprecorder->GetRecorderNumber())) 5370 (pipplayer && pipplayer->GetRecorder() && 5371 cardnum == pipplayer->GetRecorder()->GetRecorderNumber())) 5409 5372 { 5410 5373 if (watch) 5411 5374 { … … 5414 5377 if (pi.FromStringList(list, 0)) 5415 5378 SetPseudoLiveTV(s, &pi, kPseudoChangeChannel); 5416 5379 5417 if (!s && pip nvp)5380 if (!s && pipplayer) 5418 5381 TogglePIPView(); 5419 5382 } 5420 5383 else … … 6436 6399 6437 6400 if (StateIsLiveTV(GetState())) 6438 6401 { 6439 bool freeRecorders = (pip nvp!= NULL);6402 bool freeRecorders = (pipplayer != NULL); 6440 6403 if (!freeRecorders) 6441 6404 freeRecorders = RemoteGetFreeRecorderCount(); 6442 6405 … … 7076 7039 { 7077 7040 VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()"); 7078 7041 7042 LiveTVChain *piptvchain = NULL; 7043 if (pipplayer) 7044 piptvchain = pipplayer->GetLiveTVChain(); 7045 7079 7046 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 7080 7047 7081 7048 if (activenvp && chain) -
libs/libmythtv/videooutbase.cpp
171 171 pip_desired_display_size(160,128), pip_display_size(0,0), 172 172 pip_video_size(0,0), 173 173 pip_tmp_buf(NULL), pip_scaling_context(NULL), 174 piptype(kPIPOff), 174 175 175 176 // Video resizing (for ITV) 176 177 vsz_enabled(false), … … 253 254 254 255 db_vdisp_profile->SetInput(video_dim); 255 256 256 letterbox = db_letterbox; 257 if (piptype == kPIPOff) 258 letterbox = db_letterbox; 257 259 258 260 VideoAspectRatioChanged(aspect); // apply aspect ratio and letterbox mode 259 261 … … 1044 1046 1045 1047 db_pict_attr[attributeType] = newValue; 1046 1048 } 1049 /* 1050 * \brief Determines PIP Window size and Position. 1051 */ 1052 QRect VideoOutput::GetPIPRect(int location, NuppelVideoPlayer *pipplayer) 1053 { 1054 1055 int tmph; 1056 int tmpw; 1057 int letterXadj = 0; 1058 int letterYadj = 0; 1059 float letterAdj = 1.0f; 1060 int xpos = 0; 1061 int ypos = 0; 1062 int frame_height; 1063 int frame_width; 1064 1065 if (pipplayer) 1066 { 1067 frame_height = video_dim.height(); 1068 frame_width = video_dim.width(); 1069 } 1070 else 1071 { 1072 frame_height = display_visible_rect.height(); 1073 frame_width = display_visible_rect.width(); 1074 } 1075 float pipVideoAspect; 1076 uint pipVideoWidth; 1077 uint pipVideoHeight; 1078 1079 if (pipplayer) 1080 { 1081 pipVideoAspect = pipplayer->GetVideoAspect(); 1082 pipVideoWidth = pipplayer->GetVideoWidth(); 1083 pipVideoHeight = pipplayer->GetVideoHeight(); 1084 } 1085 1086 if (pipplayer && letterbox != kLetterbox_Off) 1087 { 1088 letterXadj = max(-display_video_rect.left(), 0); 1089 float xadj = (float) video_rect.width() / display_visible_rect.width(); 1090 letterXadj = (int) (letterXadj * xadj); 1047 1091 1092 float yadj = (float)video_rect.height() / display_visible_rect.height(); 1093 letterYadj = max(-display_video_rect.top(), 0); 1094 letterYadj = (int) (letterYadj * yadj); 1095 if (!pipplayer) 1096 { 1097 if (location == kPIPTopLeft || location == kPIPTopRight) 1098 ypos = display_video_rect.y(); 1099 else 1100 ypos = -(display_video_rect.y()); 1101 } 1102 1103 letterAdj = video_aspect / letterboxed_video_aspect; 1104 1105 } 1106 1107 // set height 1108 tmph = (frame_height * db_pip_size) / 100; 1109 1110 float dispPixelAdj = video_dim.width() / video_dim.height(); 1111 1112 tmpw = (int)(tmph * letterAdj * dispPixelAdj); 1113 1114 switch (location) 1115 { 1116 default: 1117 case kPIPTopLeft: 1118 xpos = 30 + letterXadj; 1119 ypos += 40 + letterYadj; 1120 break; 1121 case kPIPBottomLeft: 1122 xpos = 30 + letterXadj; 1123 ypos += frame_height - tmph - 40 - letterYadj; 1124 break; 1125 case kPIPTopRight: 1126 xpos = frame_width - tmpw - 30 - letterXadj; 1127 ypos += 40 + letterXadj; 1128 break; 1129 case kPIPBottomRight: 1130 xpos = frame_width - tmpw - 30 - letterXadj; 1131 ypos += frame_height - tmph - 40 - letterYadj; 1132 break; 1133 } 1134 return QRect(xpos, ypos, tmpw, tmph); 1135 } 1136 1048 1137 /** 1049 1138 * \fn VideoOutput::DoPipResize(int,int) 1050 1139 * \brief Sets up Picture in Picture image resampler. … … 1111 1200 int pipw, piph; 1112 1201 1113 1202 VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph); 1203 1114 1204 float pipVideoAspect = pipplayer->GetVideoAspect(); 1115 uint pipVideoWidth = pipplayer->GetVideoWidth();1116 uint pipVideoHeight = pipplayer->GetVideoHeight();1117 1205 1118 1206 // If PiP is not initialized to values we like, silently ignore the frame. 1119 1207 if ((video_aspect <= 0) || (pipVideoAspect <= 0) || … … 1123 1211 pipplayer->ReleaseCurrentFrame(pipimage); 1124 1212 return; 1125 1213 } 1214 1215 QRect piprect = GetPIPRect(db_pip_location, pipplayer); 1126 1216 1127 // set height 1128 int tmph = (frame->height * db_pip_size) / 100; 1129 pip_desired_display_size.setHeight((tmph >> 1) << 1); 1130 1131 // adjust for letterbox modes... 1132 int letterXadj = 0; 1133 int letterYadj = 0; 1134 float letterAdj = 1.0f; 1135 if (letterbox != kLetterbox_Off) 1136 { 1137 letterXadj = max(-display_video_rect.left(), 0); 1138 float xadj = (float) video_rect.width() / display_visible_rect.width(); 1139 letterXadj = (int) (letterXadj * xadj); 1140 1141 float yadj = (float)video_rect.height() /display_visible_rect.height(); 1142 letterYadj = max(-display_video_rect.top(), 0); 1143 letterYadj = (int) (letterYadj * yadj); 1144 1145 letterAdj = video_aspect / letterboxed_video_aspect; 1146 } 1147 1148 // adjust for non-square pixels on screen 1149 float dispPixelAdj = (GetDisplayAspect() * video_dim.height()) / 1150 video_dim.width(); 1151 1152 // adjust for non-square pixels in video 1153 float vidPixelAdj = pipVideoWidth / (pipVideoAspect * pipVideoHeight); 1154 1155 // set width 1156 int tmpw = (int) (pip_desired_display_size.height() * pipVideoAspect * 1157 vidPixelAdj * dispPixelAdj * letterAdj); 1158 pip_desired_display_size.setWidth((tmpw >> 1) << 1); 1159 1217 pip_desired_display_size.setWidth((piprect.width() >> 1 ) << 1); 1218 pip_desired_display_size.setHeight((piprect.height() >> 1) << 1); 1219 1220 1160 1221 // Scale the image if we have to... 1161 1222 unsigned char *pipbuf = pipimage->buf; 1162 1223 if (pipw != pip_desired_display_size.width() || … … 1186 1247 1187 1248 1188 1249 // Figure out where to put the Picture-in-Picture window 1189 int xoff = 0; 1190 int yoff = 0; 1191 switch (db_pip_location) 1192 { 1193 default: 1194 case kPIPTopLeft: 1195 xoff = 30 + letterXadj; 1196 yoff = 40 + letterYadj; 1197 break; 1198 case kPIPBottomLeft: 1199 xoff = 30 + letterXadj; 1200 yoff = frame->height - piph - 40 - letterYadj; 1201 break; 1202 case kPIPTopRight: 1203 xoff = frame->width - pipw - 30 - letterXadj; 1204 yoff = 40 + letterYadj; 1205 break; 1206 case kPIPBottomRight: 1207 xoff = frame->width - pipw - 30 - letterXadj; 1208 yoff = frame->height - piph - 40 - letterYadj; 1209 break; 1210 } 1250 int xoff = piprect.x(); 1251 int yoff = piprect.y(); 1211 1252 1212 1253 // Copy Y (intensity values) 1213 1254 for (int i = 0; i < piph; i++) -
libs/libmythtv/pipplayer.cpp
1 #include <math.h> 2 #include "pipplayer.h" 3 #include "remoteutil.h" 4 5 #define LOC QString("PIPPlayer: ") 6 #define LOC_ERR QString("PIPPlayer Error: ") 7 8 static void *SpawnPIPVideoThread(void *param) 9 { 10 NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param; 11 nvp->StartPlaying(); 12 nvp->StopPlaying(); 13 return NULL; 14 } 15 16 PIPPlayer::PIPPlayer(void) 17 : piprecorder(NULL), piprbuffer(NULL), 18 piptvchain(NULL), piprecinfo(NULL), 19 pipnvp(NULL), pipWindow(NULL), 20 islivetv(false), 21 reinit(true), using_nullvideo(false) 22 { 23 }; 24 25 PIPPlayer::~PIPPlayer(void) 26 { 27 StopPlaying(); 28 if (pipWindow) 29 pipWindow->deleteLater(); 30 }; 31 32 PIPPlayer * PIPPlayer::Create(NuppelVideoPlayer *parentnvp, int location) 33 { 34 PIPPlayer *tmppip = new PIPPlayer(); 35 if (parentnvp) 36 { 37 QRect rect = parentnvp->getVideoOutput()->GetPIPRect(location, NULL); 38 tmppip->Init(rect, QString("pip player %1").arg((int)location)); 39 return tmppip; 40 } 41 delete tmppip; 42 return NULL; 43 } 44 45 PIPPlayer * PIPPlayer::Create(const QRect &rect) 46 { 47 PIPPlayer *tmppip = new PIPPlayer(); 48 tmppip->Init(rect, "pip player"); 49 return tmppip; 50 } 51 52 void PIPPlayer::Init(QRect rect, QString name) 53 { 54 QRect piprect = QRect(rect); 55 MythDialog *window = new MythDialog(gContext->GetMainWindow(), name); 56 window->setNoErase(); 57 window->setGeometry(piprect); 58 window->setFixedSize(piprect.size()); 59 window->show(); 60 window->setBackgroundColor(Qt::black); 61 gContext->GetMainWindow()->detach(window); 62 pipWindow = window; 63 } 64 65 void PIPPlayer::Reinitialize(void) 66 { 67 if (pipnvp) 68 delete pipnvp; 69 70 pipnvp = NULL; 71 72 if (piprbuffer) 73 delete piprbuffer; 74 piprbuffer = NULL; 75 76 if (piprecinfo) 77 delete piprecinfo; 78 piprecinfo = NULL; 79 80 if (piprecorder) 81 delete piprecorder; 82 piprecorder = NULL; 83 84 if (piptvchain) 85 { 86 piptvchain->DestroyChain(); 87 delete piptvchain; 88 } 89 piptvchain = NULL; 90 } 91 92 /* 93 * \brief Setup pip and start playing it. 94 * \param piptype: set to true, if pip should open a tuner 95 * \returns true if setup is complete 96 */ 97 bool PIPPlayer::StartPlaying(ProgramInfo *rec, bool piptype, bool nullvideo) 98 { 99 100 using_nullvideo = nullvideo; 101 islivetv = piptype; 102 103 if (reinit) 104 Reinitialize(); 105 106 RemoteEncoder *testrec = NULL; 107 108 VERBOSE(VB_PLAYBACK, LOC + 109 QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording")); 110 111 if (islivetv) 112 { 113 if (!(piprecorder && piprbuffer && piptvchain)) 114 { 115 testrec = RemoteRequestRecorder(); 116 117 if (!testrec || !testrec->IsValidRecorder()) 118 { 119 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder"); 120 if (testrec) 121 delete testrec; 122 return false; 123 } 124 125 testrec->Setup(); 126 127 piptvchain = new LiveTVChain(); 128 piptvchain->InitializeNewChain("PIP"+gContext->GetHostName()); 129 testrec->SpawnLiveTV(piptvchain->GetID(), true); 130 piptvchain->ReloadAll(); 131 piprecinfo = piptvchain->GetProgramAt(-1); 132 if (!piprecinfo) 133 { 134 VERBOSE(VB_IMPORTANT, LOC_ERR + 135 "PIP cannot find live tv programinfo. Exiting"); 136 delete testrec; 137 piptvchain->DestroyChain(); 138 delete piptvchain; 139 return false; 140 } 141 else 142 { 143 QString playbackURL = piprecinfo->GetPlaybackURL(); 144 piptvchain->SetProgram(piprecinfo); 145 piprbuffer = new RingBuffer(playbackURL, false); 146 piprbuffer->SetLiveMode(piptvchain); 147 } 148 149 piprecorder = testrec; 150 151 if (!StartRecorder(piprecorder, -1)) 152 { 153 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start"); 154 return false; 155 } 156 } 157 } 158 else // pip is not Live TV 159 { 160 if (!piprecinfo) 161 piprecinfo = new ProgramInfo(*rec); 162 if (!piprbuffer) 163 piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1); 164 if (!piprbuffer->IsOpen()) 165 { 166 VERBOSE(VB_IMPORTANT, LOC_ERR + 167 QString("Failed to open Ringbuffer %1") 168 .arg(piprecinfo->pathname)); 169 return false; 170 } 171 } 172 173 // when starting pipplayer for the first time, always start 174 // from the beginning 175 if (reinit && piprecinfo) 176 piprecinfo->setIgnoreBookmark(true); 177 178 pipnvp = new NuppelVideoPlayer("pip player", piprecinfo); 179 pipnvp->SetParentWidget(pipWindow); 180 pipnvp->SetRingBuffer(piprbuffer); 181 if (islivetv) 182 { 183 pipnvp->SetRecorder(piprecorder); 184 pipnvp->SetLiveTVChain(piptvchain); 185 } 186 else 187 pipnvp->SetLength(piprecinfo->CalculateLength()); 188 189 190 // setAsPIP is true if null video output is used 191 // PIP will be embedded in XV 192 if (using_nullvideo) 193 { 194 pipnvp->SetAsPIP(true); 195 } 196 else 197 pipnvp->SetAsPIP(false); 198 199 VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP"); 200 pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp); 201 int maxWait = 20000; 202 MythTimer t; 203 t.start(); 204 while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive() && 205 t.elapsed() < maxWait) 206 { 207 usleep(5000); 208 } 209 210 if (!pipnvp->IsPlaying()) 211 { 212 VERBOSE(VB_PLAYBACK, LOC_ERR + "PIP NVP Failed to Start"); 213 return false; 214 } 215 216 VERBOSE(VB_PLAYBACK, LOC + "PIP NVP Started"); 217 return true; 218 } 219 220 void PIPPlayer::StopPlaying(void) 221 { 222 223 if (!pipnvp) 224 return; 225 226 if (pipnvp->IsPlaying()) 227 { 228 if (reinit) 229 piprbuffer->StopReads(); 230 piprbuffer->Pause(); 231 piprbuffer->WaitForPause(); 232 pipnvp->StopPlaying(); 233 } 234 235 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing"); 236 { 237 pthread_join(pipdecode, NULL); 238 delete pipnvp; 239 pipnvp = NULL; 240 } 241 242 if (reinit) 243 { 244 if (islivetv && piprecorder ) 245 piprecorder->StopLiveTV(); 246 247 Reinitialize(); 248 } 249 250 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted"); 251 } 252 253 /* 254 * \brief set pip ringbuffer if pip is not playing 255 */ 256 void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer) 257 { 258 if (!IsPlaying()) 259 piprbuffer = rbuffer; 260 } 261 262 /* 263 * \brief set pip tvchain if pip is not playing 264 */ 265 void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain) 266 { 267 if (!IsPlaying()) 268 piptvchain = tvchain; 269 } 270 271 /* 272 * \brief set pip recorder if pip is not playing 273 */ 274 void PIPPlayer::SetRecorder(RemoteEncoder *recorder) 275 { 276 if (!IsPlaying()) 277 piprecorder = recorder; 278 } 279 280 void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo) 281 { 282 if (!IsPlaying()) 283 { 284 if (piprecinfo) 285 delete piprecinfo; 286 piprecinfo = pginfo; 287 } 288 } 289 290 bool PIPPlayer::IsSameProgram(ProgramInfo *rec) 291 { 292 if (!rec || !piprecinfo) 293 return false; 294 295 if (piprecinfo->IsSameProgram(*rec)) 296 return true; 297 298 return false; 299 } 300 301 bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait) 302 { 303 maxWait = (maxWait <= 0) ? 40000 : maxWait; 304 MythTimer t; 305 t.start(); 306 while (rec && !rec->IsRecording() && t.elapsed() < maxWait) 307 usleep(5000); 308 if (rec && !rec->IsRecording()) 309 { 310 VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out"); 311 return false; 312 } 313 return true; 314 } 315 316 void PIPPlayer::Hide(void) 317 { 318 if (pipWindow && pipWindow->isVisible()) 319 pipWindow->hide(); 320 } 321 322 void PIPPlayer::Show(void) 323 { 324 if (pipWindow && pipWindow->isHidden()) 325 pipWindow->show(); 326 } 327 328 bool PIPPlayer::IsHidden(void) 329 { 330 if (pipWindow && pipWindow->isHidden()) 331 return true; 332 return false; 333 } 334 335 void PIPPlayer::DisplaySoftwareScaledImage(void) 336 { 337 if (!using_nullvideo) 338 return; 339 340 QPainter p(pipWindow); 341 QSize size = pipWindow->size(); 342 float saspect = ((float)size.width())/ ((float)size.height()); 343 float vaspect = pipnvp->GetVideoAspect(); 344 size.setHeight((int) ceil(size.height() * (saspect / vaspect))); 345 size.setHeight(((size.height() + 7) / 8) * 8); 346 size.setWidth( ((size.width() + 7) / 8) * 8); 347 const QImage &img = pipnvp->GetARGBFrame(size); 348 p.drawImage(0, 0, img); 349 } -
libs/libmythtv/videoout_xv.h
88 88 { return XVideoIDCT <= VideoOutputSubType(); } 89 89 virtual bool hasVLDAcceleration(void) const 90 90 { return XVideoVLD == VideoOutputSubType(); } 91 virtual bool hasXVAcceleration(void) const 92 { return VideoOutputSubType() >= XVideo; } 91 93 92 94 void CheckFrameStates(void); 93 95 -
libs/libmythtv/videoout_xv.cpp
1218 1218 db_vdisp_profile->SetVideoRenderer(renderer); 1219 1219 } 1220 1220 1221 const QString osdrenderer = db_vdisp_profile->GetOSDRenderer(); 1222 if (piptype == kPIPOnTV && 1223 (osdrenderer != "opengl" || osdrenderer != "composite")) 1224 { 1225 VERBOSE(VB_IMPORTANT, LOC + QString("XV PIP not supported with blended OSD. " 1226 "Using software scaled PIP.")); 1227 return false; 1228 } 1221 1229 // Initialize the OSD, if we need to 1222 InitOSD(db_vdisp_profile->GetOSDRenderer()); 1230 if (piptype == kPIPOff) 1231 InitOSD(osdrenderer); 1223 1232 1224 1233 // Create video buffers 1225 1234 bool use_xv = (renderer.left(2) == "xv"); … … 1259 1268 { 1260 1269 needrepaint = true; 1261 1270 1271 // for PIP use software scaled image if width or height <= 64 1272 if (piptype > kPIPOff && 1273 (width <= 64 || height <= 64)) 1274 return false; 1275 1262 1276 XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID."); 1263 1277 1264 1278 XJ_disp = MythXOpenDisplay(); -
libs/libmythtv/videooutbase.h
79 79 kPIPBottomRight 80 80 }; 81 81 82 enum PIPType 83 { 84 kPIPOff = 0, 85 kPIPOn, // PIP but not for TV 86 kPIPOnTV // PIP used in TV mode 87 }; 88 82 89 enum ZoomDirections 83 90 { 84 91 kZoomHome = 0, … … 225 232 bool AllowPreviewEPG(void) { return allowpreviewepg; } 226 233 227 234 /// \brief Returns true iff Motion Compensation acceleration is available. 228 virtual bool hasMCAcceleration( ) const { return false; }235 virtual bool hasMCAcceleration(void) const { return false; } 229 236 /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration 230 237 /// is available. 231 virtual bool hasIDCTAcceleration( ) const { return false; }238 virtual bool hasIDCTAcceleration(void) const { return false; } 232 239 /// \brief Returns true iff VLD acceleration is available. 233 virtual bool hasVLDAcceleration() const { return false; } 240 virtual bool hasVLDAcceleration(void) const { return false; } 241 /// \brief Returns true if XV or XVMC is available 242 virtual bool hasXVAcceleration(void) const { return false; } 234 243 235 244 /// \brief Sets the number of frames played 236 245 virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; }; … … 308 317 /// \brief Tells the player to resize the video frame (used for ITV) 309 318 void SetVideoResize(const QRect &videoRect); 310 319 320 /// \brief returns QRect of PIP based on PIPLocation 321 virtual QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer = NULL); 322 323 /// set PIP Type 324 void SetAsPIP(PIPType setting) { piptype = setting; } 325 326 311 327 protected: 312 328 void InitBuffers(int numdecode, bool extra_for_pause, int need_free, 313 329 int needprebuffer_normal, int needprebuffer_small, … … 384 400 QSize pip_video_size; 385 401 unsigned char *pip_tmp_buf; 386 402 ImgReSampleContext *pip_scaling_context; 403 PIPType piptype; 387 404 388 405 // Video resizing (for ITV) 389 406 bool vsz_enabled; -
programs/mythfrontend/playbackbox.cpp
38 38 #include "remoteutil.h" 39 39 #include "lcddevice.h" 40 40 #include "previewgenerator.h" 41 #include "pipplayer.h" 41 42 #include "playgroup.h" 42 43 #include "customedit.h" 43 44 … … 262 263 // Volatile drawing variables 263 264 paintSkipCount(0), paintSkipUpdate(false), 264 265 // Preview Video Variables 265 previewVideoNVP(NULL), previewVideoRingBuf(NULL), 266 previewVideoRefreshTimer(new QTimer(this)), 267 previewVideoBrokenRecId(0), previewVideoState(kStopped), 268 previewVideoStartTimerOn(false), previewVideoEnabled(false), 269 previewVideoPlaying(false), previewVideoThreadRunning(false), 270 previewVideoKillState(kDone), 266 previewPlayer(NULL), previewVideoStartTimer(new QTimer(this)), 267 previewVideoRefreshTimer(new QTimer(this)), 268 previewVideoEnabled(false), 269 previewTimeout(2000), software_scaled(false), 271 270 // Preview Image Variables 272 271 previewPixmapEnabled(false), previewPixmap(NULL), 273 272 previewSuspend(false), previewChanid(""), … … 369 368 connected = FillList(); 370 369 371 370 // connect up timers... 372 connect(previewVideo RefreshTimer,SIGNAL(timeout()),371 connect(previewVideoStartTimer, SIGNAL(timeout()), 373 372 this, SLOT(timeout())); 373 connect(previewVideoRefreshTimer, SIGNAL(timeout()), 374 this, SLOT(refreshVideo())); 374 375 connect(freeSpaceTimer, SIGNAL(timeout()), 375 376 this, SLOT(setUpdateFreeSpace())); 376 377 connect(fillListTimer, SIGNAL(timeout()), 377 378 this, SLOT(listChanged())); 378 379 379 380 // preview video & preview pixmap init 380 previewVideoRefreshTimer->start(500);381 381 previewStartts = QDateTime::currentDateTime(); 382 382 previewVideoStartTimer->start(previewTimeout); 383 previewVideoRefreshTimer->start(50); 383 384 // misc setup 384 385 updateBackground(); 385 386 setNoErase(); … … 398 399 gContext->removeListener(this); 399 400 gContext->removeCurrentLocation(); 400 401 401 if (!m_player) 402 killPlayerSafe(); 402 killPlayer(); 403 404 if (previewVideoStartTimer) 405 { 406 previewVideoStartTimer->disconnect(this); 407 previewVideoStartTimer->deleteLater(); 408 previewVideoStartTimer = NULL; 409 } 403 410 404 411 if (previewVideoRefreshTimer) 405 412 { … … 407 414 previewVideoRefreshTimer->deleteLater(); 408 415 previewVideoRefreshTimer = NULL; 409 416 } 410 417 411 418 if (fillListTimer) 412 419 { 413 420 fillListTimer->disconnect(this); … … 464 471 delete previewPixmap; 465 472 previewPixmap = NULL; 466 473 } 467 }468 474 469 /* blocks until playing has stopped */470 void PlaybackBox::killPlayerSafe(void)471 {472 QMutexLocker locker(&previewVideoKillLock);473 474 // Don't process any keys while we are trying to make the nvp stop.475 // Qt's setEnabled(false) doesn't work, because of LIRC events...476 ignoreKeyPressEvents = true;477 478 while (previewVideoState != kKilled && previewVideoState != kStopped &&479 previewVideoThreadRunning)480 {481 /* ensure that key events don't mess up our previewVideoStates */482 previewVideoState = (previewVideoState == kKilled) ?483 kKilled : kKilling;484 485 /* NOTE: need unlock/process/lock here because we need486 to allow updateVideo() to run to handle changes in487 previewVideoStates */488 qApp->unlock();489 qApp->processEvents();490 usleep(500);491 qApp->lock();492 }493 previewVideoState = kStopped;494 495 ignoreKeyPressEvents = false;496 475 } 497 476 498 477 void PlaybackBox::LoadWindow(QDomElement &element) … … 523 502 } 524 503 } 525 504 } 505 506 if (previewVideoEnabled) 507 { 508 previewPlayer = PIPPlayer::Create(drawVideoBounds); 509 if (previewPlayer) 510 previewPlayer->Hide(); 511 previewPixmapEnabled = true; 512 } 526 513 } 527 514 528 515 void PlaybackBox::parseContainer(QDomElement &element) … … 596 583 597 584 void PlaybackBox::exitWin() 598 585 { 586 killPlayer(); 599 587 if (m_player) 600 588 { 601 589 if (curitem) … … 603 591 curitem = NULL; 604 592 pbbIsVisibleCond.wakeAll(); 605 593 } 606 else607 killPlayerSafe();608 609 594 accept(); 610 595 } 611 596 … … 785 770 QMap<QString, QString> infoMap; 786 771 QPainter tmp(&pix); 787 772 788 if (previewVideoPlaying)789 previewVideoState = kChanging;790 773 791 774 LayerSet *container = NULL; 792 775 if (type != Delete) … … 799 782 if (curitem) 800 783 curitem->ToMap(infoMap); 801 784 802 if ((previewVideoEnabled == 0) && 803 (previewPixmapEnabled == 0)) 785 if (previewPixmapEnabled == 0) 804 786 container->UseAlternateArea(true); 805 787 806 788 container->ClearAllText(); … … 845 827 tmp.end(); 846 828 p->drawPixmap(pr.topLeft(), pix); 847 829 848 previewVideoStartTimer.start();849 previewVideoStartTimerOn = true;850 830 } 851 831 852 832 void PlaybackBox::updateInfo(QPainter *p) … … 883 863 // If we're displaying group info don't update the video. 884 864 if (inTitle && haveGroupInfoSet) 885 865 return; 886 866 887 867 /* show a still frame if the user doesn't want a video preview or nvp 888 868 * hasn't started playing the video preview yet */ 889 if (curitem && !playingSomething && 890 (!previewVideoEnabled || 891 !previewVideoPlaying || 892 (previewVideoState == kStarting) || 893 (previewVideoState == kChanging))) 869 if ((curitem && previewPixmapEnabled && !previewPlayer) || 870 (curitem && previewPlayer && previewPlayer->IsHidden())) 894 871 { 895 872 QPixmap temp = getPixmap(curitem); 896 873 if (temp.width() > 0) 897 874 p->drawPixmap(drawVideoBounds.x(), drawVideoBounds.y(), temp); 898 875 } 899 900 /* keep calling killPlayer() to handle nvp cleanup */ 901 /* until killPlayer() is done */ 902 if (previewVideoKillState != kDone && !killPlayer()) 903 return; 904 905 /* if we aren't supposed to have a preview playing then always go */ 906 /* to the stopping previewVideoState */ 907 if (!previewVideoEnabled && 908 (previewVideoState != kKilling) && (previewVideoState != kKilled)) 876 877 if (curitem && previewVideoEnabled && previewPlayer && 878 !previewPlayer->IsHidden()) 909 879 { 910 previewVideoState = kStopping; 911 } 912 913 /* if we have no nvp and aren't playing yet */ 914 /* if we have an item we should start playing */ 915 if (!previewVideoNVP && previewVideoEnabled && 916 curitem && !previewVideoPlaying && 917 (previewVideoState != kKilling) && 918 (previewVideoState != kKilled) && 919 (previewVideoState != kStarting)) 920 { 921 ProgramInfo *rec = curitem; 922 923 if (fileExists(rec) == false) 924 { 925 VERBOSE(VB_IMPORTANT, QString("Error: File '%1' missing.") 926 .arg(rec->pathname)); 927 928 previewVideoState = kStopping; 929 930 ProgramInfo *tmpItem = findMatchingProg(rec); 931 if (tmpItem) 932 tmpItem->availableStatus = asFileNotFound; 933 934 return; 935 } 936 previewVideoState = kStarting; 937 } 938 939 if (previewVideoState == kChanging) 940 { 941 if (previewVideoNVP) 942 { 943 killPlayer(); /* start killing the player */ 944 return; 945 } 946 947 previewVideoState = kStarting; 948 } 949 950 if ((previewVideoState == kStarting) && 951 (!previewVideoStartTimerOn || 952 (previewVideoStartTimer.elapsed() > 500))) 953 { 954 previewVideoStartTimerOn = false; 955 956 if (!previewVideoNVP) 957 startPlayer(curitem); 958 959 if (previewVideoNVP) 960 { 961 if (previewVideoNVP->IsPlaying()) 962 previewVideoState = kPlaying; 963 } 880 if (!previewPlayer->IsSameProgram(curitem)) 881 stopPlayer(); 964 882 else 965 { 966 // already dead, so clean up 967 killPlayer(); 968 return; 969 } 883 previewPlayer->GetNVP()->ExposeEvent(); 970 884 } 971 972 if ((previewVideoState == kStopping) || (previewVideoState == kKilling)) 973 { 974 if (previewVideoNVP) 975 { 976 killPlayer(); /* start killing the player and exit */ 977 return; 978 } 979 980 if (previewVideoState == kKilling) 981 previewVideoState = kKilled; 982 else 983 previewVideoState = kStopped; 984 } 985 986 /* if we are playing and nvp is running, then grab a new video frame */ 987 if ((previewVideoState == kPlaying) && previewVideoNVP->IsPlaying() && 988 !playingSomething) 989 { 990 QSize size = drawVideoBounds.size(); 991 float saspect = ((float)size.width()) / ((float)size.height()); 992 float vaspect = previewVideoNVP->GetVideoAspect(); 993 size.setHeight((int) ceil(size.height() * (saspect / vaspect))); 994 size.setHeight(((size.height() + 7) / 8) * 8); 995 size.setWidth( ((size.width() + 7) / 8) * 8); 996 const QImage &img = previewVideoNVP->GetARGBFrame(size); 997 p->drawImage(drawVideoBounds.x(), drawVideoBounds.y(), img); 998 } 999 1000 /* have we timed out waiting for nvp to start? */ 1001 if ((previewVideoState == kPlaying) && !previewVideoNVP->IsPlaying()) 1002 { 1003 if (previewVideoPlayingTimer.elapsed() > 2000) 1004 { 1005 previewVideoState = kStarting; 1006 killPlayer(); 1007 return; 1008 } 1009 } 885 886 previewVideoStartTimer->changeInterval(previewTimeout); 1010 887 } 1011 888 1012 889 void PlaybackBox::updateUsage(QPainter *p) … … 1360 1237 if (!inTitle) 1361 1238 { 1362 1239 if (haveGroupInfoSet) 1363 killPlayer Safe();1240 killPlayer(); 1364 1241 1365 1242 inTitle = true; 1366 1243 paintSkipUpdate = false; … … 1964 1841 return (progCache != NULL); 1965 1842 } 1966 1843 1967 static void *SpawnPreviewVideoThread(void *param)1844 void PlaybackBox::killPlayer(void) 1968 1845 { 1969 NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param; 1970 nvp->StartPlaying(); 1971 return NULL; 1972 } 1973 1974 bool PlaybackBox::killPlayer(void) 1975 { 1976 QMutexLocker locker(&previewVideoUnsafeKillLock); 1977 1978 previewVideoPlaying = false; 1979 1980 /* if we don't have nvp to deal with then we are done */ 1981 if (!previewVideoNVP) 1846 if (previewPlayer) 1982 1847 { 1983 previewVideoKillState = kDone; 1984 return true; 1848 stopPlayer(); 1849 delete previewPlayer; 1850 previewPlayer = NULL; 1985 1851 } 1986 1987 if (previewVideoKillState == kDone)1988 {1989 previewVideoKillState = kNvpToPlay;1990 previewVideoKillTimeout.start();1991 }1992 1993 if (previewVideoKillState == kNvpToPlay)1994 {1995 if (previewVideoNVP->IsPlaying() ||1996 (previewVideoKillTimeout.elapsed() > 2000))1997 {1998 previewVideoKillState = kNvpToStop;1999 2000 previewVideoRingBuf->Pause();2001 previewVideoNVP->StopPlaying();2002 }2003 else /* return false status since we aren't done yet */2004 return false;2005 }2006 2007 if (previewVideoKillState == kNvpToStop)2008 {2009 if (!previewVideoNVP->IsPlaying() ||2010 (previewVideoKillTimeout.elapsed() > 2000))2011 {2012 pthread_join(previewVideoThread, NULL);2013 previewVideoThreadRunning = true;2014 delete previewVideoNVP;2015 delete previewVideoRingBuf;2016 2017 previewVideoNVP = NULL;2018 previewVideoRingBuf = NULL;2019 previewVideoKillState = kDone;2020 }2021 else /* return false status since we aren't done yet */2022 return false;2023 }2024 2025 return true;2026 1852 } 2027 1853 2028 1854 void PlaybackBox::startPlayer(ProgramInfo *rec) 2029 1855 { 2030 previewVideoPlaying = true;2031 2032 if (rec != NULL )1856 ignoreKeyPressEvents = true; 1857 QMutexLocker locker(&previewVideoLock); 1858 if (rec != NULL && previewPlayer) 2033 1859 { 2034 // Don't keep trying to open broken files when just sitting on entry 2035 if (previewVideoBrokenRecId && 2036 previewVideoBrokenRecId == rec->recordid) 1860 previewPlayer->Show(); 1861 if (!software_scaled) 1862 previewPlayer->StartPlaying(rec, false); 1863 if (!previewPlayer->IsPlaying()) 2037 1864 { 2038 return; 1865 software_scaled = true; 1866 previewPlayer->StartPlaying(rec, false, true); 2039 1867 } 1868 } 1869 ignoreKeyPressEvents = false; 1870 } 2040 1871 2041 if (previewVideoRingBuf || previewVideoNVP) 2042 { 2043 VERBOSE(VB_IMPORTANT, 2044 "PlaybackBox::startPlayer(): Error, last preview window " 2045 "didn't clean up. Not starting a new preview."); 2046 return; 2047 } 2048 2049 previewVideoRingBuf = new RingBuffer(rec->pathname, false, false, 1); 2050 if (!previewVideoRingBuf->IsOpen()) 2051 { 2052 VERBOSE(VB_IMPORTANT, LOC_ERR + 2053 "Could not open file for preview video."); 2054 delete previewVideoRingBuf; 2055 previewVideoRingBuf = NULL; 2056 previewVideoBrokenRecId = rec->recordid; 2057 return; 2058 } 2059 previewVideoBrokenRecId = 0; 2060 2061 previewVideoNVP = new NuppelVideoPlayer("preview player"); 2062 previewVideoNVP->SetRingBuffer(previewVideoRingBuf); 2063 previewVideoNVP->SetAsPIP(); 2064 QString filters = ""; 2065 previewVideoNVP->SetVideoFilters(filters); 2066 2067 previewVideoThreadRunning = true; 2068 pthread_create(&previewVideoThread, NULL, 2069 SpawnPreviewVideoThread, previewVideoNVP); 2070 2071 previewVideoPlayingTimer.start(); 2072 2073 previewVideoState = kStarting; 2074 2075 int previewRate = 30; 2076 if (gContext->GetNumSetting("PlaybackPreviewLowCPU", 0)) 2077 { 2078 previewRate = 12; 2079 } 2080 2081 previewVideoRefreshTimer->start(1000 / previewRate); 1872 void PlaybackBox::stopPlayer(void) 1873 { 1874 ignoreKeyPressEvents = true; 1875 QMutexLocker locker(&previewVideoLock); 1876 if (previewPlayer) 1877 { 1878 previewPlayer->StopPlaying(); 1879 previewPlayer->Hide(); 2082 1880 } 1881 ignoreKeyPressEvents = false; 2083 1882 } 2084 1883 2085 1884 void PlaybackBox::playSelectedPlaylist(bool random) 2086 1885 { 2087 previewVideoState = kStopping;2088 1886 2089 1887 if (!curitem) 2090 1888 return; … … 2115 1913 2116 1914 void PlaybackBox::playSelected() 2117 1915 { 2118 previewVideoState = kStopping;2119 1916 2120 1917 if (!curitem) 2121 1918 return; … … 2137 1934 2138 1935 void PlaybackBox::stopSelected() 2139 1936 { 2140 previewVideoState = kStopping;2141 1937 2142 1938 if (!curitem) 2143 1939 return; … … 2147 1943 2148 1944 void PlaybackBox::deleteSelected() 2149 1945 { 2150 previewVideoState = kStopping;2151 1946 2152 1947 if (!curitem) 2153 1948 return; … … 2161 1956 2162 1957 void PlaybackBox::upcoming() 2163 1958 { 2164 previewVideoState = kStopping;2165 1959 2166 1960 if (!curitem) 2167 1961 return; … … 2180 1974 2181 1975 void PlaybackBox::customEdit() 2182 1976 { 2183 previewVideoState = kStopping;2184 1977 2185 1978 if (!curitem) 2186 1979 return; … … 2203 1996 2204 1997 void PlaybackBox::details() 2205 1998 { 2206 previewVideoState = kStopping;2207 1999 2208 2000 if (!curitem) 2209 2001 return; … … 2216 2008 2217 2009 void PlaybackBox::selected() 2218 2010 { 2219 previewVideoState = kStopping;2220 2011 2221 2012 if (inTitle && haveGroupInfoSet) 2222 2013 { … … 2236 2027 2237 2028 void PlaybackBox::showMenu() 2238 2029 { 2239 killPlayerSafe();2030 stopPlayer(); 2240 2031 2241 2032 popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid, 2242 2033 drawPopupFgColor, drawPopupBgColor, … … 2299 2090 2300 2091 bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist) 2301 2092 { 2093 killPlayer(); 2094 2302 2095 bool playCompleted = false; 2303 2096 2304 2097 if (!rec) … … 2327 2120 ProgramInfo *tvrec = new ProgramInfo(*rec); 2328 2121 2329 2122 setEnabled(false); 2330 previewVideoState = kKilling; // stop preview playback and don't restart it2331 2123 playingSomething = true; 2332 2124 2333 2125 playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl); … … 2335 2127 playingSomething = false; 2336 2128 setEnabled(true); 2337 2129 2338 2339 previewVideoState = kStarting; // restart playback preview2340 2341 2130 delete tvrec; 2342 2131 2343 2132 connected = FillList(); 2344 2133 2134 if (previewVideoEnabled && !previewPlayer) 2135 { 2136 previewPlayer = PIPPlayer::Create(drawVideoBounds); 2137 if (previewPlayer) 2138 previewPlayer->Hide(); 2139 } 2140 2345 2141 return playCompleted; 2346 2142 } 2347 2143 … … 2353 2149 bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory, 2354 2150 bool forceMetadataDelete) 2355 2151 { 2356 previewVideoBrokenRecId = rec->recordid; 2357 killPlayerSafe(); 2152 stopPlayer(); 2358 2153 2359 2154 if (playList.grep(rec->MakeUniqueKey()).count()) 2360 2155 togglePlayListItem(rec); … … 2367 2162 2368 2163 void PlaybackBox::remove(ProgramInfo *toDel) 2369 2164 { 2370 previewVideoState = kStopping;2371 2165 2372 2166 if (delitem) 2373 2167 delete delitem; … … 2378 2172 2379 2173 void PlaybackBox::showActions(ProgramInfo *toExp) 2380 2174 { 2381 killPlayer();2175 stopPlayer(); 2382 2176 2383 2177 if (delitem) 2384 2178 delete delitem; … … 3041 2835 void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program, 3042 2836 QString message, QString message2) 3043 2837 { 3044 killPlayerSafe();2838 stopPlayer(); 3045 2839 3046 2840 QDateTime recstartts = program->recstartts; 3047 2841 QDateTime recendts = program->recendts; … … 3150 2944 3151 2945 cancelPopup(); 3152 2946 3153 previewVideoState = kChanging;3154 2947 3155 previewVideoRefreshTimer->start(500);3156 2948 } 3157 2949 3158 2950 void PlaybackBox::doStop(void) … … 3164 2956 3165 2957 stop(delitem); 3166 2958 3167 previewVideoState = kChanging;3168 2959 3169 previewVideoRefreshTimer->start(500);3170 2960 } 3171 2961 3172 2962 void PlaybackBox::showProgramDetails() … … 3316 3106 3317 3107 cancelPopup(); 3318 3108 3319 previewVideoState = kChanging;3320 3109 3321 previewVideoRefreshTimer->start(500);3322 3110 } 3323 3111 3324 3112 void PlaybackBox::doPlaylistDelete(void) … … 3362 3150 3363 3151 bool result = doRemove(delitem, false, false); 3364 3152 3365 previewVideoState = kChanging;3366 3153 3367 previewVideoRefreshTimer->start(500);3368 3154 3369 3155 if (result) 3370 3156 { … … 3397 3183 3398 3184 doRemove(delitem, true, true); 3399 3185 3400 previewVideoState = kChanging;3401 3186 3402 previewVideoRefreshTimer->start(500);3403 3187 } 3404 3188 3405 3189 void PlaybackBox::doDeleteForgetHistory(void) … … 3422 3206 3423 3207 bool result = doRemove(delitem, true, false); 3424 3208 3425 previewVideoState = kChanging;3426 3209 3427 previewVideoRefreshTimer->start(500);3428 3210 3429 3211 if (result) 3430 3212 { … … 3499 3281 delete delitem; 3500 3282 delitem = NULL; 3501 3283 3502 previewVideoState = kChanging;3503 3504 3284 connected = FillList(); 3505 3285 update(drawListBounds); 3506 3286 } … … 3521 3301 delete delitem; 3522 3302 delitem = NULL; 3523 3303 3524 previewVideoState = kChanging;3525 3304 3526 3305 connected = FillList(); 3527 3306 update(drawListBounds); … … 3570 3349 3571 3350 cancelPopup(); 3572 3351 3573 previewVideoState = kChanging;3574 3352 } 3575 3353 3576 3354 void PlaybackBox::toggleView(ViewMask itemMask, bool setOn) … … 3590 3368 if (!rec) 3591 3369 return; 3592 3370 3593 previewVideoState = kStopping;3594 3595 3371 if (!rec) 3596 3372 return; 3597 3373 … … 3688 3464 update(drawListBounds); 3689 3465 } 3690 3466 3467 void PlaybackBox::refreshVideo(void) 3468 { 3469 if (previewPlayer && 3470 previewPlayer->IsPlaying() && 3471 previewPlayer->UsingNullVideo()) 3472 { 3473 QMutexLocker locker(&previewVideoLock); 3474 previewPlayer->DisplaySoftwareScaledImage(); 3475 } 3476 } 3477 3691 3478 void PlaybackBox::timeout(void) 3692 3479 { 3693 3480 if (titleList.count() <= 1) 3694 3481 return; 3695 3482 3696 if (previewVideoEnabled) 3697 update(drawVideoBounds); 3483 if (previewPlayer) 3484 { 3485 if (expectingPopup || 3486 !(this == gContext->GetMainWindow()->currentWidget())) 3487 { 3488 return; 3489 } 3490 else if (previewPlayer->GetNVP() == NULL) 3491 startPlayer(curitem); 3492 else if (!previewPlayer->IsPlaying()) 3493 stopPlayer(); 3494 } 3698 3495 } 3699 3496 3700 3497 void PlaybackBox::processNetworkControlCommands(void) … … 4286 4083 return; 4287 4084 } 4288 4085 4289 killPlayerSafe();4290 4291 4086 iconhelp->addLayout(grid); 4292 4087 4293 4088 QButton *button = iconhelp->addButton(tr("Ok")); … … 4297 4092 4298 4093 delete iconhelp; 4299 4094 4300 previewVideoState = kChanging;4301 4095 4302 4096 paintSkipUpdate = false; 4303 4097 paintSkipCount = 2; … … 4317 4111 QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false); 4318 4112 label->setAlignment(Qt::AlignCenter); 4319 4113 4320 killPlayerSafe();4114 stopPlayer(); 4321 4115 4322 4116 } 4323 4117 … … 4342 4136 paintSkipUpdate = false; 4343 4137 paintSkipCount = 2; 4344 4138 4345 previewVideoState = kChanging;4346 4347 4139 setActiveWindow(); 4348 4140 4349 4141 if (delitem) -
programs/mythfrontend/globalsettings.cpp
1839 1839 return gc; 1840 1840 } 1841 1841 1842 static HostCheckBox *PlaybackPreviewLowCPU()1843 {1844 HostCheckBox *gc = new HostCheckBox("PlaybackPreviewLowCPU");1845 gc->setLabel(QObject::tr("CPU friendly preview of recordings"));1846 gc->setValue(false);1847 gc->setHelpText(QObject::tr("When enabled, recording previews "1848 "will play with reduced FPS to save CPU."));1849 return gc;1850 }1851 1852 1842 static HostCheckBox *PlayBoxTransparency() 1853 1843 { 1854 1844 HostCheckBox *gc = new HostCheckBox("PlayBoxTransparency"); … … 4187 4177 pbox->addChild(PreviewPixmapOffset()); 4188 4178 pbox->addChild(PreviewFromBookmark()); 4189 4179 pbox->addChild(PlaybackPreview()); 4190 pbox->addChild(PlaybackPreviewLowCPU());4191 4180 pbox->addChild(PBBStartInTitle()); 4192 4181 pbox->addChild(PBBShowGroupSummary()); 4193 4182 addChild(pbox); -
programs/mythfrontend/playbackbox.h
26 26 class QTimer; 27 27 class ProgramInfo; 28 28 class PreviewGenerator; 29 class PIPPlayer; 29 30 30 31 class LayerSet; 31 32 … … 108 109 109 110 protected slots: 110 111 void timeout(void); 112 void refreshVideo(void); 111 113 112 114 void cursorLeft(); 113 115 void cursorRight(); … … 267 269 ProgramInfo *findMatchingProg(QString key); 268 270 ProgramInfo *findMatchingProg(QString chanid, QString recstartts); 269 271 270 bool killPlayer(void); 271 void killPlayerSafe(void); 272 void killPlayer(void); 272 273 void startPlayer(ProgramInfo *rec); 274 void stopPlayer(void); 273 275 274 276 bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete); 275 277 void promptEndOfRecording(ProgramInfo *); … … 420 422 QPixmap paintBackgroundPixmap; 421 423 422 424 // Preview Video Variables //////////////////////////////////////////////// 423 NuppelVideoPlayer *previewVideoNVP;424 RingBuffer *previewVideoRingBuf;425 QTimer *previewVideoRefreshTimer;426 MythTimer previewVideoStartTimer;427 MythTimer previewVideoPlayingTimer;428 int previewVideoBrokenRecId;429 playerStateType previewVideoState;430 bool previewVideoStartTimerOn;431 bool previewVideoEnabled;432 bool previewVideoPlaying;433 bool previewVideoThreadRunning;434 pthread_t previewVideoThread;435 425 436 mutable QMutex previewVideoKillLock; 437 mutable QMutex previewVideoUnsafeKillLock; 438 killStateType previewVideoKillState; 439 MythTimer previewVideoKillTimeout; 426 PIPPlayer *previewPlayer; 427 QTimer *previewVideoStartTimer; // if this elapses start the PIP. 428 QTimer *previewVideoRefreshTimer; // refresh software scaled PIP 429 bool previewVideoEnabled; 430 QMutex previewVideoLock; 431 int previewTimeout; 432 bool software_scaled; // pip is software scaled. 440 433 441 434 // Preview Pixmap Variables /////////////////////////////////////////////// 442 435 bool previewPixmapEnabled;