Ticket #843: pipplayer.7.diff
File pipplayer.7.diff, 86.6 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 && 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 1077 1060 1078 void NuppelVideoPlayer::InitFilters(void) 1061 1079 { 1080 if (ispip) 1081 return; 1082 1062 1083 VideoFrameType itmp = FMT_YV12; 1063 1084 VideoFrameType otmp = FMT_YV12; 1064 1085 int btmp; … … 2078 2099 { 2079 2100 float diverge = 0.0f; 2080 2101 2102 if (ispip && framesPlayed % 2) 2103 { 2104 videosync->AdvanceTrigger(); 2105 framesPlayed++; 2106 if (!using_null_videoout) 2107 videoOutput->SetFramesPlayed(framesPlayed + 1); 2108 return; 2109 } 2110 2081 2111 VideoFrame *buffer = videoOutput->GetLastShownFrame(); 2082 2112 if (!buffer) 2083 2113 { … … 2553 2583 else if (videoOutput) 2554 2584 { 2555 2585 // Set up deinterlacing in the video output method 2556 m_double_framerate = 2557 (videoOutput->SetupDeinterlace(true) && 2558 videoOutput->NeedsDoubleFramerate()); 2559 2586 if (ispip) 2587 { 2588 m_double_framerate = false; 2589 videoOutput->SetupDeinterlace(true, "onefield"); 2590 } 2591 else 2592 { 2593 m_double_framerate = 2594 (videoOutput->SetupDeinterlace(true) && 2595 videoOutput->NeedsDoubleFramerate()); 2596 } 2597 2560 2598 videosync = VideoSync::BestMethod( 2561 2599 videoOutput, fr_int, rf_int, m_double_framerate); 2562 2600 … … 2589 2627 { 2590 2628 pipplayer = setpipplayer; 2591 2629 needsetpipplayer = false; 2630 if (m_tv) 2631 m_tv->PIPPlayerWake(); 2592 2632 } 2593 2633 2594 2634 if (ringBuffer->isDVD()) … … 3049 3089 3050 3090 if (!InitVideo()) 3051 3091 { 3052 qApp->lock(); 3053 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3092 if (!ispip) 3093 { 3094 qApp->lock(); 3095 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3054 3096 QObject::tr("Unable to initialize video.")); 3055 dialog->AddButton(QObject::tr("Return to menu.")); 3056 dialog->exec(); 3057 delete dialog; 3097 dialog->AddButton(QObject::tr("Return to menu.")); 3098 dialog->exec(); 3099 delete dialog; 3100 qApp->unlock(); 3101 } 3058 3102 3059 qApp->unlock();3060 3061 3103 if (audioOutput) 3062 3104 { 3063 3105 delete audioOutput; … … 3656 3698 int numFrames = totalFrames; 3657 3699 3658 3700 if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE) 3659 numFrames = ( m_playbackinfo->endts.toTime_t() -3660 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate ;3701 numFrames = (int)((m_playbackinfo->endts.toTime_t() - 3702 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate); 3661 3703 3662 3704 int offset = (int) round(0.14 * (numFrames / video_frame_rate)); 3663 3705 … … 3680 3722 3681 3723 void NuppelVideoPlayer::SetBookmark(void) 3682 3724 { 3683 if (!m_playbackinfo || !osd)3725 if (!m_playbackinfo) 3684 3726 return; 3685 3727 3686 3728 m_playbackinfo->SetBookmark(framesPlayed); 3687 osd->SetSettingsText(QObject::tr("Position Saved"), 1); 3729 if (osd) 3730 { 3731 osd->SetSettingsText(QObject::tr("Position Saved"), 1); 3688 3732 3689 struct StatusPosInfo posInfo; 3690 calcSliderPos(posInfo); 3691 osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2); 3733 struct StatusPosInfo posInfo; 3734 calcSliderPos(posInfo); 3735 osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2); 3736 } 3692 3737 } 3693 3738 3694 3739 void NuppelVideoPlayer::ClearBookmark(void) -
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. … … 161 162 bool IsErrored(void) const { return errored; } 162 163 /// true if dialog is either videoplayexit, playexit or askdelete dialog 163 164 bool IsVideoExitDialog(void); 165 /// true if PIP is active NVP 166 bool IsPIPActiveNVP(void); 164 167 165 168 // Other queries 166 169 int GetLastRecorderNum(void) const; … … 320 323 321 324 void SetupPlayer(bool isWatchingRecording); 322 325 void TeardownPlayer(void); 323 void SetupPipPlayer(void);324 void TeardownPipPlayer(void);325 326 326 327 void HandleStateChange(void); 327 328 bool InStateChange(void) const; … … 331 332 void TogglePIPView(void); 332 333 void ToggleActiveWindow(void); 333 334 void SwapPIP(void); 335 TVState GetPIPState(PIPPlayer *pip); 334 336 void SwapPIPSoon(void) { needToSwapPIP = true; } 335 337 336 338 void ToggleAutoExpire(void); 337 339 338 340 void BrowseStart(void); … … 529 531 530 532 // Video Players 531 533 NuppelVideoPlayer *nvp; 532 NuppelVideoPlayer *pipnvp;534 PIPPlayer *pipplayer; 533 535 NuppelVideoPlayer *activenvp; ///< Player to which LiveTV events are sent 534 536 537 //PIP Stuff 538 QWaitCondition pipplayerCond; 539 535 540 // Remote Encoders 536 541 /// Main recorder 537 542 RemoteEncoder *recorder; 538 /// Picture-in-Picture recorder539 RemoteEncoder *piprecorder;540 543 /// Recorder to which LiveTV events are being sent 541 544 RemoteEncoder *activerecorder; 542 545 /// Main recorder to use after a successful SwitchCards() call. … … 546 549 547 550 // LiveTVChain 548 551 LiveTVChain *tvchain; 549 LiveTVChain *piptvchain;550 552 QStringList tvchainUpdate; 551 553 QMutex tvchainUpdateLock; 552 554 553 555 // RingBuffers 554 556 RingBuffer *prbuffer; 555 RingBuffer *piprbuffer;556 557 RingBuffer *activerbuffer; ///< Ringbuffer to which LiveTV events are sent 557 558 558 559 // OSD info … … 589 590 pthread_t event; 590 591 /// Video decoder thread, runs nvp's NuppelVideoPlayer::StartPlaying(). 591 592 pthread_t decode; 592 /// Picture-in-Picture video decoder thread,593 /// runs pipnvp's NuppelVideoPlayer::StartPlaying().594 pthread_t pipdecode;595 593 596 594 /// Condition to signal that the Event thread is up and running 597 595 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 GetARGBFrame(void); 46 QSize GetVideoDimensions(void) 47 { return QSize(video_width, video_height); } 48 bool IsPaused(void) { return paused; } 49 void Pause(void); 50 void Play(float speed = 1.0); 51 52 53 private: 54 bool StartRecorder(RemoteEncoder *rec, int maxWait); 55 void Reinitialize(void); 56 void Init(QRect rect, QString name); 57 58 private: 59 RemoteEncoder *piprecorder; 60 RingBuffer *piprbuffer; 61 LiveTVChain *piptvchain; 62 ProgramInfo *piprecinfo; 63 NuppelVideoPlayer *pipnvp; 64 pthread_t videoThread; 65 pthread_t pipdecode; 66 QWidget *pipWindow; 67 bool islivetv; 68 bool reinit; 69 bool using_nullvideo; 70 int video_width; 71 int video_height; 72 bool paused; 73 }; 74 75 #endif 76 #ifndef PIPPLAYER_H 77 #define PIPPLAYER_H 78 79 #include <qpainter.h> 80 #include "NuppelVideoPlayer.h" 81 #include "RingBuffer.h" 82 #include "programinfo.h" 83 #include "livetvchain.h" 84 #include "remoteencoder.h" 85 86 class RingBuffer; 87 class ProgramInfo; 88 class LiveTVChain; 89 class RemoteEncoder; 90 class NuppelVideoPlayer; 91 92 class PIPPlayer 93 { 94 public: 95 PIPPlayer(void); 96 ~PIPPlayer(void); 97 static PIPPlayer *Create(const QRect &rect); 98 static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location); 99 bool StartPlaying(ProgramInfo *rec = NULL, 100 bool piptype = false, 101 bool nullvideo = false); 102 void StopPlaying(); 103 bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); } 104 void SetFrameRate(double fps); 105 bool IsSameProgram(ProgramInfo *rec); 106 RingBuffer *GetRingBuffer(void) { return piprbuffer; } 107 RemoteEncoder *GetRecorder(void) { return piprecorder; } 108 LiveTVChain *GetLiveTVChain(void) { return piptvchain; } 109 NuppelVideoPlayer *GetNVP(void) { return pipnvp; } 110 ProgramInfo *GetProgramInfo(void) { return piprecinfo; } 111 void SetRingBuffer(RingBuffer *rbuffer); 112 void SetLiveTVChain(LiveTVChain *tvchain); 113 void SetRecorder(RemoteEncoder *recorder); 114 void SetProgramInfo(ProgramInfo *pginfo); 115 void SetReinit(bool change) { reinit = change; } 116 bool IsLiveTV(void) { return islivetv; } 117 bool IsHidden(void); 118 void Hide(void); 119 void Show(void); 120 bool UsingNullVideo(void) { return using_nullvideo; } 121 void DisplaySoftwareScaledImage(void); 122 123 124 private: 125 bool StartRecorder(RemoteEncoder *rec, int maxWait); 126 void Reinitialize(void); 127 void Init(QRect rect, QString name); 128 129 private: 130 RemoteEncoder *piprecorder; 131 RingBuffer *piprbuffer; 132 LiveTVChain *piptvchain; 133 ProgramInfo *piprecinfo; 134 NuppelVideoPlayer *pipnvp; 135 pthread_t videoThread; 136 pthread_t pipdecode; 137 QWidget *pipWindow; 138 bool islivetv; 139 bool reinit; 140 bool using_nullvideo; 141 }; 142 143 #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; … … 670 673 NuppelVideoPlayer *pipplayer; 671 674 NuppelVideoPlayer *setpipplayer; 672 675 bool needsetpipplayer; 676 bool ispip; 677 bool softwareScalingPIP; 673 678 674 679 // Preview window support 675 680 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); … … 1379 1373 prbuffer->Pause(); 1380 1374 prbuffer->WaitForPause(); 1381 1375 } 1382 1383 if (piprbuffer)1384 {1385 piprbuffer->StopReads();1386 piprbuffer->Pause();1387 piprbuffer->WaitForPause();1388 }1389 1376 } 1390 1377 1391 1378 if (stopPlayers) … … 1393 1380 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (1/2)"); 1394 1381 if (nvp) 1395 1382 nvp->StopPlaying(); 1396 1397 if (pipnvp)1398 pipnvp->StopPlaying();1399 1383 } 1400 1384 1401 1385 if (stopRecorders) … … 1403 1387 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping recorder[s]"); 1404 1388 if (recorder) 1405 1389 recorder->StopLiveTV(); 1406 1407 if (piprecorder)1408 piprecorder->StopLiveTV();1409 1390 } 1410 1391 1411 1392 if (stopPlayers) … … 1413 1394 VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (2/2)"); 1414 1395 if (nvp) 1415 1396 TeardownPlayer(); 1416 1417 if (pipnvp) 1418 TeardownPipPlayer(); 1397 if (pipplayer) 1398 { 1399 delete pipplayer; 1400 pipplayer = NULL; 1401 } 1419 1402 } 1420 1403 VERBOSE(VB_PLAYBACK, LOC + "StopStuff() -- end"); 1421 1404 } … … 1497 1480 return filters; 1498 1481 } 1499 1482 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 1483 void TV::TeardownPlayer(void) 1523 1484 { 1524 1485 if (nvp) … … 1568 1529 prbuffer = activerbuffer = NULL; 1569 1530 } 1570 1531 1571 if (piprbuffer)1572 {1573 delete piprbuffer;1574 piprbuffer = NULL;1575 }1576 1577 1532 if (tvchain) 1578 1533 { 1579 1534 tvchain->DestroyChain(); … … 1582 1537 } 1583 1538 } 1584 1539 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 1540 void *TV::EventThread(void *param) 1625 1541 { 1626 1542 TV *thetv = (TV *)param; … … 1686 1602 if (nvp->GetTVChain()) 1687 1603 nvp->CheckTVChain(); 1688 1604 } 1689 if (piptvchain && pipnvp && *it == piptvchain->GetID()) 1605 if (pipplayer && pipplayer->IsLiveTV() 1606 && *it == pipplayer->GetLiveTVChain()->GetID()) 1690 1607 { 1608 LiveTVChain *piptvchain = pipplayer->GetLiveTVChain(); 1691 1609 piptvchain->ReloadAll(); 1692 if (pip nvp->GetTVChain())1693 pip nvp->CheckTVChain();1610 if (pipplayer->GetNVP()->GetTVChain()) 1611 pipplayer->GetNVP()->CheckTVChain(); 1694 1612 } 1695 1613 } 1696 1614 tvchainUpdate.clear(); … … 1752 1670 wantsToQuit = true; 1753 1671 } 1754 1672 1673 if (pipplayer && !pipplayer->IsPlaying()) 1674 TogglePIPView(); 1675 1755 1676 if (StateIsPlaying(internalState)) 1756 1677 { 1757 1678 #ifdef USING_VALGRIND … … 1859 1780 prevChan = tmp; 1860 1781 pseudoLiveTVState[i] = kPseudoRecording; 1861 1782 1862 if (i && pip nvp)1783 if (i && pipplayer) 1863 1784 TogglePIPView(); 1864 1785 } 1865 1786 … … 1884 1805 if (++updatecheck >= 100) 1885 1806 { 1886 1807 OSDSet *oset; 1887 if (GetOSD() && (oset = GetOSD()->GetSet("status")) && 1808 if (activenvp && GetOSD() && 1809 (oset = GetOSD()->GetSet("status")) && 1888 1810 oset->Displaying() && update_osd_pos && 1889 1811 (StateIsLiveTV(internalState) || 1890 1812 StateIsPlaying(internalState))) 1891 1813 { 1892 1814 struct StatusPosInfo posInfo; 1893 nvp->calcSliderPos(posInfo);1815 activenvp->calcSliderPos(posInfo); 1894 1816 GetOSD()->UpdateStatus(posInfo); 1895 1817 } 1896 1818 … … 1932 1854 if (activenvp) 1933 1855 { 1934 1856 struct StatusPosInfo posInfo; 1935 nvp->calcSliderPos(posInfo);1857 activenvp->calcSliderPos(posInfo); 1936 1858 progress = (float)posInfo.position / 1000; 1937 1859 } 1938 1860 lcd->setChannelProgress(progress); … … 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") … … 3213 3137 } 3214 3138 } 3215 3139 3140 bool TV::IsPIPActiveNVP(void) 3141 { 3142 if (pipplayer && pipplayer->GetNVP()) 3143 return (pipplayer->GetNVP() == activenvp); 3144 return false; 3145 } 3146 3216 3147 void TV::TogglePIPView(void) 3217 3148 { 3218 if (!pip nvp)3149 if (!pipplayer) 3219 3150 { 3220 RemoteEncoder *testrec = RemoteRequestRecorder(); 3221 3222 if (!testrec || !testrec->IsValidRecorder()) 3151 int pip_location = gContext->GetNumSetting("PIPLocation", 0); 3152 QRect rect = activenvp->getVideoOutput()->GetPIPRect(pip_location, NULL); 3153 pipplayer = PIPPlayer::Create(rect); 3154 if (!pipplayer) 3155 return; 3156 pipplayer->Hide(); 3157 pipplayer->StartPlaying(NULL, true); 3158 if (pipplayer->IsPlaying()) 3223 3159 { 3224 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder"); 3225 if (testrec) 3226 delete testrec; 3160 pipplayer->Show(); 3161 pipplayer->GetNVP()->DiscardVideoFrames(true); 3227 3162 return; 3228 3163 } 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 }3245 3164 else 3246 3165 { 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()) 3166 QSize pipdim = pipplayer->GetVideoDimensions(); 3167 VideoOutput *vid = nvp->getVideoOutput(); 3168 if (vid && 3169 vid->IsResolutionSupported(pipdim.width(), pipdim.height())) 3262 3170 { 3263 piptvchain->ReloadAll(); 3264 usleep(5000); 3171 if (pipplayer->GetNVP() && 3172 pipplayer->GetNVP()->PIPSoftwareScaling() && 3173 nvp->getVideoOutput() && 3174 nvp->getVideoOutput()->hasXVAcceleration()) 3175 { 3176 pipplayer->StartPlaying(NULL, true, true); 3177 if (pipplayer->IsPlaying()) 3178 { 3179 activenvp->SetPIPPlayer(pipplayer->GetNVP()); 3180 pipplayerCond.wait(); 3181 pipplayer->GetNVP()->DiscardVideoFrames(true); 3182 return; 3183 } 3184 } 3265 3185 } 3266 VERBOSE(VB_PLAYBACK, "PiP NVP Started");3267 3268 if (pipnvp->IsDecoderThreadAlive())3269 nvp->SetPipPlayer(pipnvp);3270 else3271 {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();3278 }3279 3186 } 3280 else3281 {3282 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");3283 TeardownPipPlayer();3284 }3285 3187 } 3286 else 3188 3189 if (IsPIPActiveNVP()) 3190 ToggleActiveWindow(); 3191 3192 if (nvp->HasPIPPlayer()) 3287 3193 { 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); 3194 activenvp->SetPIPPlayer(NULL); 3195 pipplayerCond.wait(); 3307 3196 } 3197 3198 delete pipplayer; 3199 pipplayer = NULL; 3308 3200 } 3309 3201 3310 3202 void TV::ToggleActiveWindow(void) 3311 3203 { 3312 if (!pipnvp) 3204 // toggleactivewindow works only if the main window is live tv. 3205 // problem is playbackinfo and internalstate management. 3206 if (!pipplayer || !pipplayer->GetNVP() || 3207 (!IsPIPActiveNVP() && StateIsPlaying(internalState))) 3208 { 3313 3209 return; 3314 3210 } 3211 3315 3212 lockTimerOn = false; 3316 if (activenvp == nvp) 3213 LiveTVChain *piptvchain = NULL; 3214 3215 if (!IsPIPActiveNVP()) 3317 3216 { 3318 activenvp = pipnvp; 3319 activerbuffer = piprbuffer; 3320 activerecorder = piprecorder; 3217 3218 activenvp = pipplayer->GetNVP(); 3219 activerbuffer = pipplayer->GetRingBuffer(); 3220 activerecorder = pipplayer->GetRecorder(); 3221 piptvchain = pipplayer->GetLiveTVChain(); 3222 internalState = GetPIPState(pipplayer); 3223 if (pipplayer->GetProgramInfo() && !pipplayer->IsLiveTV()) 3224 SetCurrentlyPlaying(pipplayer->GetProgramInfo()); 3321 3225 } 3322 3226 else 3323 3227 { 3324 activenvp = nvp;3325 activerbuffer = prbuffer;3228 activenvp = nvp; 3229 activerbuffer = prbuffer; 3326 3230 activerecorder = recorder; 3231 internalState = kState_WatchingLiveTV; 3327 3232 } 3328 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3329 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3330 if (pginfo) 3331 { 3332 SetCurrentlyPlaying(pginfo); 3333 delete pginfo; 3334 } 3233 3234 if (activerecorder) 3235 { 3236 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3237 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3238 if (pginfo) 3239 { 3240 SetCurrentlyPlaying(pginfo); 3241 delete pginfo; 3242 } 3243 } 3335 3244 } 3336 3245 3246 3337 3247 struct pip_info 3338 3248 { 3339 3249 RingBuffer *buffer; 3340 3250 RemoteEncoder *recorder; 3341 3251 LiveTVChain *chain; 3342 3252 long long frame; 3253 ProgramInfo *pginfo; 3343 3254 }; 3344 3255 3345 3256 void TV::SwapPIP(void) 3346 3257 { 3347 if (!pipnvp || !piptvchain || !tvchain) 3258 if (!pipplayer) 3259 // TODO print something on OSD informing use that PIP swap cannot be done 3348 3260 return; 3349 3261 3350 lockTimerOn = false; 3262 if (IsPIPActiveNVP()) 3263 ToggleActiveWindow(); 3264 3265 bool use_nullvideo = pipplayer->UsingNullVideo(); 3266 bool pipislivetv = StateIsLiveTV(internalState); 3267 3268 if (paused) 3269 DoPause(); 3270 StopFFRew(); 3271 NormalSpeed(); 3351 3272 3273 if (playbackinfo) 3274 playbackinfo->setIgnoreBookmark(false); 3275 if (pipplayer->GetProgramInfo()) 3276 pipplayer->GetProgramInfo()->setIgnoreBookmark(false); 3277 3278 // set the bookmark 3279 activenvp->SetBookmark(); 3280 pipplayer->GetNVP()->SetBookmark(); 3281 3352 3282 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(); 3361 3283 main.buffer = prbuffer; 3284 main.recorder = recorder; 3285 main.chain = tvchain; 3286 main.frame = nvp->GetFramesPlayed(); 3287 if (StateIsPlaying(internalState)) 3288 main.pginfo = new ProgramInfo(*playbackinfo); 3289 else 3290 main.pginfo = NULL; 3291 3292 pip.buffer = pipplayer->GetRingBuffer(); 3293 pip.recorder = pipplayer->GetRecorder(); 3294 pip.chain = pipplayer->GetLiveTVChain(); 3295 pip.frame = pipplayer->GetNVP()->GetFramesPlayed(); 3296 if (!pipplayer->IsLiveTV()) 3297 pip.pginfo = new ProgramInfo(*pipplayer->GetProgramInfo()); 3298 else 3299 pip.pginfo = NULL; 3300 3301 pipplayer->Hide(); 3302 if (use_nullvideo) 3303 { 3304 activenvp->SetPIPPlayer(NULL); 3305 pipplayerCond.wait(); 3306 } 3307 pipplayer->SetReinit(false); 3308 pipplayer->StopPlaying(); 3309 3362 3310 prbuffer->Pause(); 3363 3311 prbuffer->WaitForPause(); 3364 3312 3365 piprbuffer->Pause(); 3366 piprbuffer->WaitForPause(); 3313 nvp->StopPlaying(); 3367 3314 3368 nvp->StopPlaying();3369 pipnvp->StopPlaying();3370 3315 { 3371 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. .3316 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. 3372 3317 pthread_join(decode, NULL); 3373 3318 delete nvp; 3374 3319 nvp = NULL; 3375 pthread_join(pipdecode, NULL);3376 delete pipnvp;3377 pipnvp = NULL;3378 3320 } 3379 3321 3322 if (playbackinfo) 3323 delete playbackinfo; 3324 3380 3325 activerbuffer = prbuffer = pip.buffer; 3381 3326 activerecorder = recorder = pip.recorder; 3382 3327 tvchain = pip.chain; 3328 playbackinfo = pip.pginfo; 3329 internalState = GetPIPState(pipplayer); 3383 3330 3384 piprbuffer = main.buffer; 3385 piprecorder = main.recorder; 3386 piptvchain = main.chain; 3387 3331 pipplayer->SetRingBuffer(main.buffer); 3332 pipplayer->SetRecorder(main.recorder); 3333 pipplayer->SetLiveTVChain(main.chain); 3334 pipplayer->SetProgramInfo(main.pginfo); 3335 3336 VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1") 3337 .arg(StateToString(internalState))); 3338 3388 3339 prbuffer->Seek(0, SEEK_SET); 3389 3340 prbuffer->Unpause(); 3390 StartPlayer(false); 3341 3342 if (internalState == kState_WatchingRecording) 3343 StartPlayer(true); 3344 else 3345 StartPlayer(false); 3346 3391 3347 activenvp = nvp; 3392 nvp->FastForward(pip.frame/recorder->GetFrameRate()); 3348 usleep(10000); 3349 if (tvchain) 3350 { 3351 nvp->FastForward(pip.frame/recorder->GetFrameRate()); 3352 nvp->DiscardVideoFrames(true); 3353 } 3354 3355 pipplayer->GetRingBuffer()->Seek(0, SEEK_SET); 3356 pipplayer->GetRingBuffer()->Unpause(); 3357 3358 if (use_nullvideo) 3359 { 3360 pipplayer->StartPlaying(main.pginfo, pipislivetv, true); 3361 if (pipplayer->IsPlaying()) 3362 activenvp->SetPIPPlayer(pipplayer->GetNVP()); 3363 } 3364 else 3365 pipplayer->StartPlaying(main.pginfo, pipislivetv); 3393 3366 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()) 3367 if (pipplayer->IsPlaying()) 3400 3368 { 3401 piptvchain->ReloadAll(); 3402 usleep(5000); 3369 if (!use_nullvideo) 3370 pipplayer->Show(); 3371 if (pipplayer->GetLiveTVChain()) 3372 { 3373 pipplayer->GetLiveTVChain()->ReloadAll(); 3374 usleep(5000); 3375 } 3403 3376 } 3404 VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");3405 pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());3406 3377 3407 if (pipnvp->IsDecoderThreadAlive()) 3408 nvp->SetPipPlayer(pipnvp); 3409 else 3378 if (internalState == kState_WatchingLiveTV) 3379 SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV); 3380 3381 if (pipplayer->IsLiveTV()) 3382 SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV); 3383 3384 if (pipplayer->GetLiveTVChain()) 3410 3385 { 3411 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start"); 3412 TeardownPipPlayer(); 3386 NuppelVideoPlayer *pipnvp = pipplayer->GetNVP(); 3387 float pipframerate = pipplayer->GetRecorder()->GetFrameRate(); 3388 pipnvp->FastForward(main.frame/pipframerate); 3389 pipnvp->DiscardVideoFrames(true); 3413 3390 } 3414 3391 3415 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3416 if (pginfo) 3392 if (tvchain) 3417 3393 { 3418 SetCurrentlyPlaying(pginfo); 3419 delete pginfo; 3394 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3395 if (pginfo) 3396 { 3397 SetCurrentlyPlaying(pginfo); 3398 delete pginfo; 3399 } 3420 3400 } 3401 pipplayer->SetReinit(true); 3421 3402 } 3422 3403 3404 TVState TV::GetPIPState(PIPPlayer *player) 3405 { 3406 if (player->IsLiveTV()) 3407 return kState_WatchingLiveTV; 3408 else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0)) 3409 return kState_WatchingRecording; 3410 else 3411 return kState_WatchingPreRecorded; 3412 } 3413 3423 3414 void TV::DoPlay(void) 3424 3415 { 3425 3416 float time = 0.0; … … 3467 3458 3468 3459 void TV::DoPause(bool showOSD) 3469 3460 { 3461 QMutexLocker locker(&stateLock); 3470 3462 if (activerbuffer->InDVDMenuOrStillFrame()) 3471 3463 return; 3472 3464 3465 if (IsPIPActiveNVP()) 3466 { 3467 if (pipplayer->IsPaused()) 3468 pipplayer->Play(); 3469 else 3470 pipplayer->Pause(); 3471 return; 3472 } 3473 3473 3474 speed_index = 0; 3474 3475 float time = 0.0; 3475 3476 3476 3477 if (paused) 3478 { 3477 3479 activenvp->Play(normal_speed, true); 3480 if (pipplayer) 3481 pipplayer->Play(normal_speed); 3482 } 3478 3483 else 3479 3484 { 3480 3485 if (doing_ff_rew) … … 3485 3490 } 3486 3491 3487 3492 activenvp->Pause(); 3493 if (pipplayer) 3494 pipplayer->Pause(); 3488 3495 } 3489 3496 3490 3497 paused = !paused; … … 3849 3856 3850 3857 RemoteEncoder *testrec = NULL; 3851 3858 3852 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pip nvp)3859 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer) 3853 3860 return; 3854 3861 3855 3862 if (/*chanid || */!channum.isEmpty()) … … 4529 4536 if (showStatus) 4530 4537 { 4531 4538 osd->HideAll(); 4532 if ( nvp)4539 if (activenvp) 4533 4540 { 4534 4541 struct StatusPosInfo posInfo; 4535 nvp->calcSliderPos(posInfo);4542 activenvp->calcSliderPos(posInfo); 4536 4543 osd->ShowStatus(posInfo, false, tr("Position"), 4537 4544 osd_prog_info_timeout); 4538 4545 update_osd_pos = true; … … 4567 4574 4568 4575 void TV::UpdateOSDSeekMessage(const QString &mesg, int disptime) 4569 4576 { 4570 if (activenvp != nvp )4577 if (activenvp != nvp || !prbuffer) 4571 4578 return; 4572 4579 4573 4580 struct StatusPosInfo posInfo; … … 4967 4974 { 4968 4975 bool stayPaused = paused; 4969 4976 if (!paused) 4970 DoPause( );4977 DoPause(false); 4971 4978 4972 4979 switch (editType) 4973 4980 { … … 5002 5009 } 5003 5010 5004 5011 if (!stayPaused) 5005 DoPause( );5012 DoPause(false); 5006 5013 } 5007 5014 5008 5015 // Resize the window back to the MythTV Player size … … 5369 5376 menurunning = false; 5370 5377 AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec); 5371 5378 } 5372 else if (pip recorder&&5373 cardnum == pip recorder->GetRecorderNumber())5379 else if (pipplayer && pipplayer->GetRecorder() && 5380 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5374 5381 { 5375 5382 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording"); 5376 5383 TogglePIPView(); … … 5388 5395 wantsToQuit = false; 5389 5396 exitPlayer = true; 5390 5397 } 5391 else if (pip recorder&&5392 cardnum == pip recorder->GetRecorderNumber())5398 else if (pipplayer && pipplayer->GetRecorder() && 5399 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5393 5400 { 5394 5401 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV"); 5395 5402 TogglePIPView(); … … 5405 5412 uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1; 5406 5413 5407 5414 if ((recorder && cardnum == recorder->GetRecorderNumber()) || 5408 (piprecorder && cardnum == piprecorder->GetRecorderNumber())) 5415 (pipplayer && pipplayer->GetRecorder() && 5416 cardnum == pipplayer->GetRecorder()->GetRecorderNumber())) 5409 5417 { 5410 5418 if (watch) 5411 5419 { … … 5414 5422 if (pi.FromStringList(list, 0)) 5415 5423 SetPseudoLiveTV(s, &pi, kPseudoChangeChannel); 5416 5424 5417 if (!s && pip nvp)5425 if (!s && pipplayer) 5418 5426 TogglePIPView(); 5419 5427 } 5420 5428 else … … 6408 6416 6409 6417 void TV::ShowOSDTreeMenu(void) 6410 6418 { 6419 if (IsPIPActiveNVP()) 6420 return; 6421 6411 6422 BuildOSDTreeMenu(); 6412 6423 6413 6424 if (GetOSD()) … … 6436 6447 6437 6448 if (StateIsLiveTV(GetState())) 6438 6449 { 6439 bool freeRecorders = (pip nvp!= NULL);6450 bool freeRecorders = (pipplayer != NULL); 6440 6451 if (!freeRecorders) 6441 6452 freeRecorders = RemoteGetFreeRecorderCount(); 6442 6453 … … 7076 7087 { 7077 7088 VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()"); 7078 7089 7090 LiveTVChain *piptvchain = NULL; 7091 if (pipplayer) 7092 piptvchain = pipplayer->GetLiveTVChain(); 7093 7079 7094 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 7080 7095 7081 7096 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 … … 525 527 visible = GetVisibleOSDBounds(visible_aspect, font_scaling); 526 528 } 527 529 530 bool VideoOutput::IsResolutionSupported(int width, int height) 531 { 532 (void)width; 533 (void)height; 534 return true; 535 } 536 528 537 static float sq(float a) { return a*a; } 529 538 //static float lerp(float r, float a, float b) 530 539 // { return ((1.0f - r) * a) + (r * b); } … … 1044 1053 1045 1054 db_pict_attr[attributeType] = newValue; 1046 1055 } 1056 /* 1057 * \brief Determines PIP Window size and Position. 1058 */ 1059 QRect VideoOutput::GetPIPRect(int location, NuppelVideoPlayer *pipplayer) 1060 { 1061 1062 int tmph; 1063 int tmpw; 1064 int letterXadj = 0; 1065 int letterYadj = 0; 1066 float letterAdj = 1.0f; 1067 int xpos = 0; 1068 int ypos = 0; 1069 int frame_height; 1070 int frame_width; 1071 1072 if (pipplayer) 1073 { 1074 frame_height = video_dim.height(); 1075 frame_width = video_dim.width(); 1076 } 1077 else 1078 { 1079 frame_height = display_visible_rect.height(); 1080 frame_width = display_visible_rect.width(); 1081 } 1082 float pipVideoAspect; 1083 uint pipVideoWidth; 1084 uint pipVideoHeight; 1085 1086 if (pipplayer) 1087 { 1088 pipVideoAspect = pipplayer->GetVideoAspect(); 1089 pipVideoWidth = pipplayer->GetVideoWidth(); 1090 pipVideoHeight = pipplayer->GetVideoHeight(); 1091 } 1092 1093 if (pipplayer && letterbox != kLetterbox_Off) 1094 { 1095 letterXadj = max(-display_video_rect.left(), 0); 1096 float xadj = (float) video_rect.width() / display_visible_rect.width(); 1097 letterXadj = (int) (letterXadj * xadj); 1047 1098 1099 float yadj = (float)video_rect.height() / display_visible_rect.height(); 1100 letterYadj = max(-display_video_rect.top(), 0); 1101 letterYadj = (int) (letterYadj * yadj); 1102 if (!pipplayer) 1103 { 1104 if (location == kPIPTopLeft || location == kPIPTopRight) 1105 ypos = display_video_rect.y(); 1106 else 1107 ypos = -(display_video_rect.y()); 1108 } 1109 1110 letterAdj = video_aspect / letterboxed_video_aspect; 1111 1112 } 1113 1114 // set height 1115 tmph = (frame_height * db_pip_size) / 100; 1116 1117 float dispPixelAdj = video_dim.width() / video_dim.height(); 1118 1119 tmpw = (int)(tmph * letterAdj * dispPixelAdj); 1120 1121 switch (location) 1122 { 1123 default: 1124 case kPIPTopLeft: 1125 xpos = 30 + letterXadj; 1126 ypos += 40 + letterYadj; 1127 break; 1128 case kPIPBottomLeft: 1129 xpos = 30 + letterXadj; 1130 ypos += frame_height - tmph - 40 - letterYadj; 1131 break; 1132 case kPIPTopRight: 1133 xpos = frame_width - tmpw - 30 - letterXadj; 1134 ypos += 40 + letterXadj; 1135 break; 1136 case kPIPBottomRight: 1137 xpos = frame_width - tmpw - 30 - letterXadj; 1138 ypos += frame_height - tmph - 40 - letterYadj; 1139 break; 1140 } 1141 return QRect(xpos, ypos, tmpw, tmph); 1142 } 1143 1048 1144 /** 1049 1145 * \fn VideoOutput::DoPipResize(int,int) 1050 1146 * \brief Sets up Picture in Picture image resampler. … … 1111 1207 int pipw, piph; 1112 1208 1113 1209 VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph); 1210 1114 1211 float pipVideoAspect = pipplayer->GetVideoAspect(); 1115 uint pipVideoWidth = pipplayer->GetVideoWidth();1116 uint pipVideoHeight = pipplayer->GetVideoHeight();1117 1212 1118 1213 // If PiP is not initialized to values we like, silently ignore the frame. 1119 1214 if ((video_aspect <= 0) || (pipVideoAspect <= 0) || … … 1123 1218 pipplayer->ReleaseCurrentFrame(pipimage); 1124 1219 return; 1125 1220 } 1221 1222 QRect piprect = GetPIPRect(db_pip_location, pipplayer); 1126 1223 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 1224 pip_desired_display_size.setWidth((piprect.width() >> 1 ) << 1); 1225 pip_desired_display_size.setHeight((piprect.height() >> 1) << 1); 1226 1227 1160 1228 // Scale the image if we have to... 1161 1229 unsigned char *pipbuf = pipimage->buf; 1162 1230 if (pipw != pip_desired_display_size.width() || … … 1186 1254 1187 1255 1188 1256 // 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 } 1257 int xoff = piprect.x(); 1258 int yoff = piprect.y(); 1211 1259 1212 1260 // Copy Y (intensity values) 1213 1261 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 video_width(0), video_height(0), 23 paused(false) 24 { 25 }; 26 27 PIPPlayer::~PIPPlayer(void) 28 { 29 StopPlaying(); 30 if (pipWindow) 31 pipWindow->deleteLater(); 32 }; 33 34 PIPPlayer * PIPPlayer::Create(NuppelVideoPlayer *parentnvp, int location) 35 { 36 PIPPlayer *tmppip = new PIPPlayer(); 37 if (parentnvp) 38 { 39 QRect rect = parentnvp->getVideoOutput()->GetPIPRect(location, NULL); 40 tmppip->Init(rect, QString("pip player %1").arg((int)location)); 41 return tmppip; 42 } 43 delete tmppip; 44 return NULL; 45 } 46 47 PIPPlayer * PIPPlayer::Create(const QRect &rect) 48 { 49 PIPPlayer *tmppip = new PIPPlayer(); 50 tmppip->Init(rect, "pip player"); 51 return tmppip; 52 } 53 54 void PIPPlayer::Init(QRect rect, QString name) 55 { 56 QRect piprect = QRect(rect); 57 MythDialog *window = new MythDialog(gContext->GetMainWindow(), name); 58 window->setNoErase(); 59 window->setGeometry(piprect); 60 window->setFixedSize(piprect.size()); 61 window->show(); 62 window->setBackgroundColor(Qt::black); 63 gContext->GetMainWindow()->detach(window); 64 pipWindow = window; 65 } 66 67 void PIPPlayer::Reinitialize(void) 68 { 69 if (pipnvp) 70 delete pipnvp; 71 72 pipnvp = NULL; 73 74 if (piprbuffer) 75 delete piprbuffer; 76 piprbuffer = NULL; 77 78 if (piprecinfo) 79 delete piprecinfo; 80 piprecinfo = NULL; 81 82 if (piprecorder) 83 delete piprecorder; 84 piprecorder = NULL; 85 86 if (piptvchain) 87 { 88 piptvchain->DestroyChain(); 89 delete piptvchain; 90 } 91 piptvchain = NULL; 92 } 93 94 /* 95 * \brief Setup pip and start playing it. 96 * \param piptype: set to true, if pip should open a tuner 97 * \returns true if setup is complete 98 */ 99 bool PIPPlayer::StartPlaying(ProgramInfo *rec, bool piptype, bool nullvideo) 100 { 101 102 using_nullvideo = nullvideo; 103 islivetv = piptype; 104 105 if (reinit) 106 Reinitialize(); 107 108 RemoteEncoder *testrec = NULL; 109 110 VERBOSE(VB_PLAYBACK, LOC + 111 QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording")); 112 113 if (islivetv) 114 { 115 if (!(piprecorder && piprbuffer && piptvchain)) 116 { 117 testrec = RemoteRequestRecorder(); 118 119 if (!testrec || !testrec->IsValidRecorder()) 120 { 121 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder"); 122 if (testrec) 123 delete testrec; 124 return false; 125 } 126 127 testrec->Setup(); 128 129 piptvchain = new LiveTVChain(); 130 piptvchain->InitializeNewChain("PIP"+gContext->GetHostName()); 131 testrec->SpawnLiveTV(piptvchain->GetID(), true); 132 piptvchain->ReloadAll(); 133 piprecinfo = piptvchain->GetProgramAt(-1); 134 if (!piprecinfo) 135 { 136 VERBOSE(VB_IMPORTANT, LOC_ERR + 137 "PIP cannot find live tv programinfo. Exiting"); 138 delete testrec; 139 piptvchain->DestroyChain(); 140 delete piptvchain; 141 return false; 142 } 143 else 144 { 145 QString playbackURL = piprecinfo->GetPlaybackURL(); 146 piptvchain->SetProgram(piprecinfo); 147 piprbuffer = new RingBuffer(playbackURL, false); 148 piprbuffer->SetLiveMode(piptvchain); 149 } 150 151 piprecorder = testrec; 152 153 if (!StartRecorder(piprecorder, -1)) 154 { 155 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start"); 156 return false; 157 } 158 } 159 } 160 else // pip is not Live TV 161 { 162 if (!piprecinfo) 163 piprecinfo = new ProgramInfo(*rec); 164 if (!piprbuffer) 165 piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1); 166 if (!piprbuffer->IsOpen()) 167 { 168 VERBOSE(VB_IMPORTANT, LOC_ERR + 169 QString("Failed to open Ringbuffer %1") 170 .arg(piprecinfo->pathname)); 171 return false; 172 } 173 } 174 175 // when starting pipplayer for the first time, always start 176 // from the beginning 177 if (reinit && piprecinfo) 178 piprecinfo->setIgnoreBookmark(true); 179 180 pipnvp = new NuppelVideoPlayer("pip player", piprecinfo); 181 pipnvp->SetParentWidget(pipWindow); 182 pipnvp->SetRingBuffer(piprbuffer); 183 if (islivetv) 184 { 185 pipnvp->SetRecorder(piprecorder); 186 pipnvp->SetLiveTVChain(piptvchain); 187 } 188 else 189 pipnvp->SetLength(piprecinfo->CalculateLength()); 190 191 192 // setAsPIP is true if null video output is used 193 // PIP will be embedded in XV 194 if (using_nullvideo) 195 { 196 pipnvp->SetAsPIP(true); 197 } 198 else 199 pipnvp->SetAsPIP(false); 200 201 VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP"); 202 pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp); 203 int maxWait = 10000; 204 MythTimer t; 205 t.start(); 206 while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive() && 207 t.elapsed() < maxWait) 208 { 209 usleep(5000); 210 } 211 212 video_width = pipnvp->GetVideoWidth(); 213 video_height = pipnvp->GetVideoHeight(); 214 215 if (!pipnvp->IsPlaying()) 216 { 217 VERBOSE(VB_PLAYBACK, LOC_ERR + "PIP NVP Failed to Start"); 218 return false; 219 } 220 221 VERBOSE(VB_PLAYBACK, LOC + "PIP NVP Started"); 222 return true; 223 } 224 225 void PIPPlayer::StopPlaying(void) 226 { 227 228 if (!pipnvp) 229 return; 230 231 if (pipnvp->IsPlaying()) 232 { 233 if (reinit) 234 piprbuffer->StopReads(); 235 piprbuffer->Pause(); 236 piprbuffer->WaitForPause(); 237 pipnvp->StopPlaying(); 238 } 239 240 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing"); 241 { 242 pthread_join(pipdecode, NULL); 243 delete pipnvp; 244 pipnvp = NULL; 245 } 246 247 if (reinit) 248 { 249 if (islivetv && piprecorder ) 250 piprecorder->StopLiveTV(); 251 252 Reinitialize(); 253 } 254 255 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted"); 256 } 257 258 /* 259 * \brief set pip ringbuffer if pip is not playing 260 */ 261 void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer) 262 { 263 if (!IsPlaying()) 264 piprbuffer = rbuffer; 265 } 266 267 /* 268 * \brief set pip tvchain if pip is not playing 269 */ 270 void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain) 271 { 272 if (!IsPlaying()) 273 piptvchain = tvchain; 274 } 275 276 /* 277 * \brief set pip recorder if pip is not playing 278 */ 279 void PIPPlayer::SetRecorder(RemoteEncoder *recorder) 280 { 281 if (!IsPlaying()) 282 piprecorder = recorder; 283 } 284 285 void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo) 286 { 287 if (!IsPlaying()) 288 { 289 if (piprecinfo) 290 delete piprecinfo; 291 piprecinfo = pginfo; 292 } 293 } 294 295 bool PIPPlayer::IsSameProgram(ProgramInfo *rec) 296 { 297 if (!rec || !piprecinfo) 298 return false; 299 300 if (piprecinfo->IsSameProgram(*rec)) 301 return true; 302 303 return false; 304 } 305 306 bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait) 307 { 308 maxWait = (maxWait <= 0) ? 20000 : maxWait; 309 MythTimer t; 310 t.start(); 311 while (rec && !rec->IsRecording() && t.elapsed() < maxWait) 312 usleep(5000); 313 if (rec && !rec->IsRecording()) 314 { 315 VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out"); 316 return false; 317 } 318 return true; 319 } 320 321 void PIPPlayer::Hide(void) 322 { 323 if (pipWindow && pipWindow->isVisible()) 324 pipWindow->hide(); 325 } 326 327 void PIPPlayer::Show(void) 328 { 329 if (pipWindow && pipWindow->isHidden()) 330 pipWindow->show(); 331 } 332 333 bool PIPPlayer::IsHidden(void) 334 { 335 if (pipWindow && pipWindow->isHidden()) 336 return true; 337 return false; 338 } 339 340 void PIPPlayer::GetARGBFrame(void) 341 { 342 if (!using_nullvideo) 343 return; 344 345 QPainter p(pipWindow); 346 QSize size = pipWindow->size(); 347 float saspect = ((float)size.width())/ ((float)size.height()); 348 float vaspect = pipnvp->GetVideoAspect(); 349 size.setHeight((int) ceil(size.height() * (saspect / vaspect))); 350 size.setHeight(((size.height() + 7) / 8) * 8); 351 size.setWidth( ((size.width() + 7) / 8) * 8); 352 const QImage &img = pipnvp->GetARGBFrame(size); 353 p.drawImage(0, 0, img); 354 } 355 356 void PIPPlayer::Pause(void) 357 { 358 if (IsPlaying() && !paused) 359 { 360 pipnvp->Pause(); 361 paused = true; 362 } 363 } 364 365 void PIPPlayer::Play(float speed) 366 { 367 if (IsPlaying() && paused) 368 { 369 pipnvp->Play(speed); 370 paused = false; 371 } 372 } 373 -
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); 95 bool IsResolutionSupported(int width, int height); 93 96 94 97 static MythCodecID GetBestSupportedCodec(uint width, uint height, 95 98 uint osd_width, uint osd_height, -
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 + 1226 QString("XV PIP not supported with blended OSD. " 1227 "Using software scaled PIP.")); 1228 return false; 1229 } 1221 1230 // Initialize the OSD, if we need to 1222 InitOSD(db_vdisp_profile->GetOSDRenderer()); 1231 if (piptype == kPIPOff) 1232 InitOSD(osdrenderer); 1223 1233 1224 1234 // Create video buffers 1225 1235 bool use_xv = (renderer.left(2) == "xv"); … … 1259 1269 { 1260 1270 needrepaint = true; 1261 1271 1272 // for PIP use software scaled image if width or height <= 64 1273 if (piptype > kPIPOff && 1274 (width <= 64 || height <= 64)) 1275 { 1276 VERBOSE(VB_IMPORTANT, LOC_ERR + 1277 QString("PIP Video Init Failed. Dimensions less then 64 " 1278 "Video width %1, Video height %2") 1279 .arg(width).arg(height)); 1280 return false; 1281 } 1282 1262 1283 XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID."); 1263 1284 1264 1285 XJ_disp = MythXOpenDisplay(); … … 3267 3288 #endif // USING_XVMC 3268 3289 } 3269 3290 3291 bool VideoOutputXv::IsResolutionSupported(int width, int height) 3292 { 3293 if (width == 0 || height == 0) 3294 return false; 3295 3296 if (xv_port >= 0 && xv_chroma) 3297 { 3298 int size = 0; 3299 int desiredsize = 0; 3300 XvImage *img = NULL; 3301 XShmSegmentInfo *info = new XShmSegmentInfo; 3302 X11S(img = XvShmCreateImage(XJ_disp, xv_port, xv_chroma, 0, 3303 width, height, info)); 3304 size = img->data_size + 64; 3305 desiredsize = width * height * 3 / 2; 3306 if (img && size < desiredsize) 3307 { 3308 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("IsResolutionSupported(): " 3309 "WxH %1x%2 not supported on this Xv Surface") 3310 .arg(width).arg(height)); 3311 XFree(img); 3312 delete info; 3313 return false; 3314 } 3315 3316 return true; 3317 } 3318 return false; 3319 } 3320 3270 3321 bool VideoOutputXv::IsDisplaying(VideoFrame* frame) 3271 3322 { 3272 3323 (void)frame; -
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, … … 190 197 virtual void GetOSDBounds(QRect &visible, QRect &total, 191 198 float &pixelAspect, float &fontScale) const; 192 199 200 virtual bool IsResolutionSupported(int width, int height); 201 193 202 /// \brief Returns current display's frame refresh period in microseconds. 194 203 /// e.g. 1000000 / frame_rate_in_Hz 195 204 virtual int GetRefreshRate(void) = 0; … … 225 234 bool AllowPreviewEPG(void) { return allowpreviewepg; } 226 235 227 236 /// \brief Returns true iff Motion Compensation acceleration is available. 228 virtual bool hasMCAcceleration( ) const { return false; }237 virtual bool hasMCAcceleration(void) const { return false; } 229 238 /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration 230 239 /// is available. 231 virtual bool hasIDCTAcceleration( ) const { return false; }240 virtual bool hasIDCTAcceleration(void) const { return false; } 232 241 /// \brief Returns true iff VLD acceleration is available. 233 virtual bool hasVLDAcceleration() const { return false; } 242 virtual bool hasVLDAcceleration(void) const { return false; } 243 /// \brief Returns true if XV acceleration is available. 244 virtual bool hasXVAcceleration(void) const { return false; } 234 245 235 246 /// \brief Sets the number of frames played 236 247 virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; }; … … 308 319 /// \brief Tells the player to resize the video frame (used for ITV) 309 320 void SetVideoResize(const QRect &videoRect); 310 321 322 /// \brief returns QRect of PIP based on PIPLocation 323 virtual QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer = NULL); 324 325 /// set PIP Type 326 void SetAsPIP(PIPType setting) { piptype = setting; } 327 328 311 329 protected: 312 330 void InitBuffers(int numdecode, bool extra_for_pause, int need_free, 313 331 int needprebuffer_normal, int needprebuffer_small, … … 384 402 QSize pip_video_size; 385 403 unsigned char *pip_tmp_buf; 386 404 ImgReSampleContext *pip_scaling_context; 405 PIPType piptype; 387 406 388 407 // Video resizing (for ITV) 389 408 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 preview VideoNVP(NULL), previewVideoRingBuf(NULL),266 previewPlayer(NULL), previewVideoStartTimer(new QTimer(this)), 266 267 previewVideoRefreshTimer(new QTimer(this)), 267 previewVideoBrokenRecId(0), previewVideoState(kStopped), 268 previewVideoStartTimerOn(false), previewVideoEnabled(false), 269 previewVideoPlaying(false), previewVideoThreadRunning(false), 270 previewVideoKillState(kDone), 268 previewVideoStopTimer(new QTimer(this)), 269 previewVideoEnabled(false), 270 previewTimeout(2000), software_scaled(false), 271 271 // Preview Image Variables 272 272 previewPixmapEnabled(false), previewPixmap(NULL), 273 273 previewSuspend(false), previewChanid(""), … … 369 369 connected = FillList(); 370 370 371 371 // connect up timers... 372 connect(previewVideo RefreshTimer,SIGNAL(timeout()),372 connect(previewVideoStartTimer, SIGNAL(timeout()), 373 373 this, SLOT(timeout())); 374 connect(previewVideoRefreshTimer, SIGNAL(timeout()), 375 this, SLOT(refreshVideo())); 376 connect(previewVideoStopTimer, SIGNAL(timeout()), 377 this, SLOT(stopPlayer())); 374 378 connect(freeSpaceTimer, SIGNAL(timeout()), 375 379 this, SLOT(setUpdateFreeSpace())); 376 380 connect(fillListTimer, SIGNAL(timeout()), 377 381 this, SLOT(listChanged())); 378 382 379 383 // preview video & preview pixmap init 380 previewVideoRefreshTimer->start(500);381 384 previewStartts = QDateTime::currentDateTime(); 382 383 385 // misc setup 384 386 updateBackground(); 385 387 setNoErase(); … … 398 400 gContext->removeListener(this); 399 401 gContext->removeCurrentLocation(); 400 402 401 if (!m_player) 402 killPlayerSafe(); 403 killPlayer(); 404 405 if (previewVideoStartTimer) 406 { 407 previewVideoStartTimer->disconnect(this); 408 previewVideoStartTimer->deleteLater(); 409 previewVideoStartTimer = NULL; 410 } 403 411 404 412 if (previewVideoRefreshTimer) 405 413 { … … 408 416 previewVideoRefreshTimer = NULL; 409 417 } 410 418 419 if (previewVideoStopTimer) 420 { 421 previewVideoStopTimer->disconnect(this); 422 previewVideoStopTimer->deleteLater(); 423 previewVideoStopTimer = NULL; 424 } 425 411 426 if (fillListTimer) 412 427 { 413 428 fillListTimer->disconnect(this); … … 464 479 delete previewPixmap; 465 480 previewPixmap = NULL; 466 481 } 467 }468 482 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 483 } 497 484 498 485 void PlaybackBox::LoadWindow(QDomElement &element) … … 523 510 } 524 511 } 525 512 } 513 514 if (previewVideoEnabled) 515 { 516 previewPlayer = PIPPlayer::Create(drawVideoBounds); 517 if (previewPlayer) 518 previewPlayer->Hide(); 519 previewPixmapEnabled = true; 520 } 526 521 } 527 522 528 523 void PlaybackBox::parseContainer(QDomElement &element) … … 596 591 597 592 void PlaybackBox::exitWin() 598 593 { 594 killPlayer(); 599 595 if (m_player) 600 596 { 601 597 if (curitem) … … 603 599 curitem = NULL; 604 600 pbbIsVisibleCond.wakeAll(); 605 601 } 606 else607 killPlayerSafe();608 609 602 accept(); 610 603 } 611 604 … … 785 778 QMap<QString, QString> infoMap; 786 779 QPainter tmp(&pix); 787 780 788 if (previewVideoPlaying)789 previewVideoState = kChanging;790 781 791 782 LayerSet *container = NULL; 792 783 if (type != Delete) … … 799 790 if (curitem) 800 791 curitem->ToMap(infoMap); 801 792 802 if ((previewVideoEnabled == 0) && 803 (previewPixmapEnabled == 0)) 793 if (previewPixmapEnabled == 0) 804 794 container->UseAlternateArea(true); 805 795 806 796 container->ClearAllText(); … … 845 835 tmp.end(); 846 836 p->drawPixmap(pr.topLeft(), pix); 847 837 848 previewVideoStartTimer.start();849 previewVideoStartTimerOn = true;850 838 } 851 839 852 840 void PlaybackBox::updateInfo(QPainter *p) … … 883 871 // If we're displaying group info don't update the video. 884 872 if (inTitle && haveGroupInfoSet) 885 873 return; 886 874 887 875 /* show a still frame if the user doesn't want a video preview or nvp 888 876 * hasn't started playing the video preview yet */ 889 if (curitem && !playingSomething && 890 (!previewVideoEnabled || 891 !previewVideoPlaying || 892 (previewVideoState == kStarting) || 893 (previewVideoState == kChanging))) 877 if ((curitem && previewPixmapEnabled && !previewPlayer) || 878 (curitem && previewPlayer && previewPlayer->IsHidden())) 894 879 { 895 880 QPixmap temp = getPixmap(curitem); 896 881 if (temp.width() > 0) 897 882 p->drawPixmap(drawVideoBounds.x(), drawVideoBounds.y(), temp); 898 883 } 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)) 884 885 if (curitem && previewVideoEnabled && previewPlayer && 886 !previewPlayer->IsHidden()) 909 887 { 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 } 888 if (!previewPlayer->IsSameProgram(curitem)) 889 stopPlayer(); 964 890 else 965 { 966 // already dead, so clean up 967 killPlayer(); 968 return; 969 } 891 previewPlayer->GetNVP()->ExposeEvent(); 970 892 } 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 } 893 894 previewVideoStartTimer->start(previewTimeout); 1010 895 } 1011 896 1012 897 void PlaybackBox::updateUsage(QPainter *p) … … 1360 1245 if (!inTitle) 1361 1246 { 1362 1247 if (haveGroupInfoSet) 1363 killPlayer Safe();1248 killPlayer(); 1364 1249 1365 1250 inTitle = true; 1366 1251 paintSkipUpdate = false; … … 1964 1849 return (progCache != NULL); 1965 1850 } 1966 1851 1967 static void *SpawnPreviewVideoThread(void *param)1852 void PlaybackBox::killPlayer(void) 1968 1853 { 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) 1854 if (previewPlayer) 1982 1855 { 1983 previewVideoKillState = kDone; 1984 return true; 1856 stopPlayer(); 1857 delete previewPlayer; 1858 previewPlayer = NULL; 1985 1859 } 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 1860 } 2027 1861 2028 1862 void PlaybackBox::startPlayer(ProgramInfo *rec) 2029 1863 { 2030 previewVideoPlaying = true; 2031 2032 if (rec != NULL) 1864 ignoreKeyPressEvents = true; 1865 QMutexLocker locker(&previewVideoLock); 1866 previewVideoStartTimer->start(previewTimeout); 1867 previewVideoStopTimer->start(30000); 1868 if (rec != NULL && previewPlayer) 2033 1869 { 2034 // Don't keep trying to open broken files when just sitting on entry 2035 if (previewVideoBrokenRecId && 2036 previewVideoBrokenRecId == rec->recordid) 1870 previewPlayer->Show(); 1871 if (!software_scaled) 1872 previewPlayer->StartPlaying(rec, false); 1873 if (!previewPlayer->IsPlaying()) 2037 1874 { 2038 return; 1875 previewVideoRefreshTimer->start(50); 1876 software_scaled = true; 1877 previewPlayer->StartPlaying(rec, false, true); 2039 1878 } 1879 } 1880 ignoreKeyPressEvents = false; 1881 } 2040 1882 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); 1883 void PlaybackBox::stopPlayer(void) 1884 { 1885 ignoreKeyPressEvents = true; 1886 QMutexLocker locker(&previewVideoLock); 1887 if (previewPlayer) 1888 { 1889 previewVideoRefreshTimer->stop(); 1890 previewPlayer->StopPlaying(); 1891 previewPlayer->Hide(); 2082 1892 } 1893 ignoreKeyPressEvents = false; 2083 1894 } 2084 1895 2085 1896 void PlaybackBox::playSelectedPlaylist(bool random) 2086 1897 { 2087 previewVideoState = kStopping;2088 1898 2089 1899 if (!curitem) 2090 1900 return; … … 2115 1925 2116 1926 void PlaybackBox::playSelected() 2117 1927 { 2118 previewVideoState = kStopping;2119 1928 2120 1929 if (!curitem) 2121 1930 return; … … 2137 1946 2138 1947 void PlaybackBox::stopSelected() 2139 1948 { 2140 previewVideoState = kStopping;2141 1949 2142 1950 if (!curitem) 2143 1951 return; … … 2147 1955 2148 1956 void PlaybackBox::deleteSelected() 2149 1957 { 2150 previewVideoState = kStopping;2151 1958 2152 1959 if (!curitem) 2153 1960 return; … … 2161 1968 2162 1969 void PlaybackBox::upcoming() 2163 1970 { 2164 previewVideoState = kStopping;2165 1971 2166 1972 if (!curitem) 2167 1973 return; … … 2180 1986 2181 1987 void PlaybackBox::customEdit() 2182 1988 { 2183 previewVideoState = kStopping;2184 1989 2185 1990 if (!curitem) 2186 1991 return; … … 2203 2008 2204 2009 void PlaybackBox::details() 2205 2010 { 2206 previewVideoState = kStopping;2207 2011 2208 2012 if (!curitem) 2209 2013 return; … … 2216 2020 2217 2021 void PlaybackBox::selected() 2218 2022 { 2219 previewVideoState = kStopping;2220 2023 2221 2024 if (inTitle && haveGroupInfoSet) 2222 2025 { … … 2236 2039 2237 2040 void PlaybackBox::showMenu() 2238 2041 { 2239 killPlayerSafe();2042 stopPlayer(); 2240 2043 2241 2044 popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid, 2242 2045 drawPopupFgColor, drawPopupBgColor, … … 2299 2102 2300 2103 bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist) 2301 2104 { 2105 killPlayer(); 2106 2302 2107 bool playCompleted = false; 2303 2108 2304 2109 if (!rec) … … 2327 2132 ProgramInfo *tvrec = new ProgramInfo(*rec); 2328 2133 2329 2134 setEnabled(false); 2330 previewVideoState = kKilling; // stop preview playback and don't restart it2331 2135 playingSomething = true; 2332 2136 2333 2137 playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl); … … 2335 2139 playingSomething = false; 2336 2140 setEnabled(true); 2337 2141 2338 2339 previewVideoState = kStarting; // restart playback preview2340 2341 2142 delete tvrec; 2342 2143 2343 2144 connected = FillList(); 2344 2145 2146 if (previewVideoEnabled && !previewPlayer) 2147 { 2148 previewPlayer = PIPPlayer::Create(drawVideoBounds); 2149 if (previewPlayer) 2150 previewPlayer->Hide(); 2151 } 2152 2345 2153 return playCompleted; 2346 2154 } 2347 2155 … … 2353 2161 bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory, 2354 2162 bool forceMetadataDelete) 2355 2163 { 2356 previewVideoBrokenRecId = rec->recordid; 2357 killPlayerSafe(); 2164 stopPlayer(); 2358 2165 2359 2166 if (playList.grep(rec->MakeUniqueKey()).count()) 2360 2167 togglePlayListItem(rec); … … 2367 2174 2368 2175 void PlaybackBox::remove(ProgramInfo *toDel) 2369 2176 { 2370 previewVideoState = kStopping;2371 2177 2372 2178 if (delitem) 2373 2179 delete delitem; … … 2378 2184 2379 2185 void PlaybackBox::showActions(ProgramInfo *toExp) 2380 2186 { 2381 killPlayer();2187 stopPlayer(); 2382 2188 2383 2189 if (delitem) 2384 2190 delete delitem; … … 3041 2847 void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program, 3042 2848 QString message, QString message2) 3043 2849 { 3044 killPlayerSafe();2850 stopPlayer(); 3045 2851 3046 2852 QDateTime recstartts = program->recstartts; 3047 2853 QDateTime recendts = program->recendts; … … 3150 2956 3151 2957 cancelPopup(); 3152 2958 3153 previewVideoState = kChanging;3154 2959 3155 previewVideoRefreshTimer->start(500);3156 2960 } 3157 2961 3158 2962 void PlaybackBox::doStop(void) … … 3164 2968 3165 2969 stop(delitem); 3166 2970 3167 previewVideoState = kChanging;3168 2971 3169 previewVideoRefreshTimer->start(500);3170 2972 } 3171 2973 3172 2974 void PlaybackBox::showProgramDetails() … … 3316 3118 3317 3119 cancelPopup(); 3318 3120 3319 previewVideoState = kChanging;3320 3121 3321 previewVideoRefreshTimer->start(500);3322 3122 } 3323 3123 3324 3124 void PlaybackBox::doPlaylistDelete(void) … … 3362 3162 3363 3163 bool result = doRemove(delitem, false, false); 3364 3164 3365 previewVideoState = kChanging;3366 3165 3367 previewVideoRefreshTimer->start(500);3368 3166 3369 3167 if (result) 3370 3168 { … … 3397 3195 3398 3196 doRemove(delitem, true, true); 3399 3197 3400 previewVideoState = kChanging;3401 3198 3402 previewVideoRefreshTimer->start(500);3403 3199 } 3404 3200 3405 3201 void PlaybackBox::doDeleteForgetHistory(void) … … 3422 3218 3423 3219 bool result = doRemove(delitem, true, false); 3424 3220 3425 previewVideoState = kChanging;3426 3221 3427 previewVideoRefreshTimer->start(500);3428 3222 3429 3223 if (result) 3430 3224 { … … 3499 3293 delete delitem; 3500 3294 delitem = NULL; 3501 3295 3502 previewVideoState = kChanging;3503 3504 3296 connected = FillList(); 3505 3297 update(drawListBounds); 3506 3298 } … … 3521 3313 delete delitem; 3522 3314 delitem = NULL; 3523 3315 3524 previewVideoState = kChanging;3525 3316 3526 3317 connected = FillList(); 3527 3318 update(drawListBounds); … … 3570 3361 3571 3362 cancelPopup(); 3572 3363 3573 previewVideoState = kChanging;3574 3364 } 3575 3365 3576 3366 void PlaybackBox::toggleView(ViewMask itemMask, bool setOn) … … 3590 3380 if (!rec) 3591 3381 return; 3592 3382 3593 previewVideoState = kStopping;3594 3595 3383 if (!rec) 3596 3384 return; 3597 3385 … … 3688 3476 update(drawListBounds); 3689 3477 } 3690 3478 3479 void PlaybackBox::refreshVideo(void) 3480 { 3481 if (previewPlayer && 3482 previewPlayer->IsPlaying() && 3483 previewPlayer->UsingNullVideo()) 3484 { 3485 QMutexLocker locker(&previewVideoLock); 3486 previewPlayer->GetARGBFrame(); 3487 } 3488 } 3489 3691 3490 void PlaybackBox::timeout(void) 3692 3491 { 3693 3492 if (titleList.count() <= 1) 3694 3493 return; 3695 3494 3696 if (previewVideoEnabled) 3697 update(drawVideoBounds); 3495 if (previewPlayer) 3496 { 3497 if (expectingPopup || 3498 !(this == gContext->GetMainWindow()->currentWidget())) 3499 { 3500 return; 3501 } 3502 else if (previewPlayer->GetNVP() == NULL) 3503 startPlayer(curitem); 3504 else if (!previewPlayer->IsPlaying()) 3505 stopPlayer(); 3506 } 3698 3507 } 3699 3508 3509 3700 3510 void PlaybackBox::processNetworkControlCommands(void) 3701 3511 { 3702 3512 int commands = 0; … … 4286 4096 return; 4287 4097 } 4288 4098 4289 killPlayerSafe();4290 4291 4099 iconhelp->addLayout(grid); 4292 4100 4293 4101 QButton *button = iconhelp->addButton(tr("Ok")); … … 4297 4105 4298 4106 delete iconhelp; 4299 4107 4300 previewVideoState = kChanging;4301 4108 4302 4109 paintSkipUpdate = false; 4303 4110 paintSkipCount = 2; … … 4317 4124 QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false); 4318 4125 label->setAlignment(Qt::AlignCenter); 4319 4126 4320 killPlayerSafe();4127 stopPlayer(); 4321 4128 4322 4129 } 4323 4130 … … 4342 4149 paintSkipUpdate = false; 4343 4150 paintSkipCount = 2; 4344 4151 4345 previewVideoState = kChanging;4346 4347 4152 setActiveWindow(); 4348 4153 4349 4154 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(); … … 228 230 229 231 void previewThreadDone(const QString &fn, bool &success); 230 232 void previewReady(const ProgramInfo *pginfo); 233 void stopPlayer(void); 231 234 232 235 protected: 233 236 void paintEvent(QPaintEvent *); … … 267 270 ProgramInfo *findMatchingProg(QString key); 268 271 ProgramInfo *findMatchingProg(QString chanid, QString recstartts); 269 272 270 bool killPlayer(void); 271 void killPlayerSafe(void); 273 void killPlayer(void); 272 274 void startPlayer(ProgramInfo *rec); 273 275 274 276 bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete); … … 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 QTimer *previewVideoStopTimer; // if this elapses restart the PIP 430 bool previewVideoEnabled; 431 QMutex previewVideoLock; 432 int previewTimeout; 433 bool software_scaled; // pip is software scaled. 440 434 441 435 // Preview Pixmap Variables /////////////////////////////////////////////// 442 436 bool previewPixmapEnabled;