Ticket #843: pipplayer.2.diff
File pipplayer.2.diff, 88.8 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 … … 494 496 bool NuppelVideoPlayer::InitVideo(void) 495 497 { 496 498 InitFilters(); 499 500 PIPType piptype = kPIPOff; 501 497 502 if (using_null_videoout) 498 503 { 499 504 videoOutput = new VideoOutputNull(); 505 if (ispip) 506 { 507 if (m_tv) 508 { 509 if (livetv) 510 piptype = kPIPOnLiveTV; 511 else 512 piptype = kPIPOnTV; 513 } 514 else 515 piptype = kPIPOn; 516 517 videoOutput->SetAsPIP(piptype); 518 } 519 520 500 521 if (!videoOutput->Init(video_width, video_height, video_aspect, 501 522 0, 0, 0, 0, 0, 0)) 502 523 { … … 540 561 return false; 541 562 } 542 563 564 if (ispip) 565 { 566 if (m_tv) 567 piptype = kPIPOnTV; 568 else 569 piptype = kPIPOn; 570 571 videoOutput->SetAsPIP(piptype); 572 } 573 543 574 if (!videoOutput->Init(video_width, video_height, video_aspect, 544 575 widget->winId(), 0, 0, widget->width(), 545 576 widget->height(), 0)) 546 577 { 547 578 errored = true; 579 } 580 581 if (errored && ispip) 582 { 583 softwareScalingPIP = true; 584 delete videoOutput; 585 videoOutput = NULL; 586 errored = true; 548 587 return false; 549 588 } 550 589 … … 636 675 { 637 676 QString errMsg = QString::null; 638 677 639 if ( (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))678 if (ispip || (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0)) 640 679 { 641 680 VERBOSE(VB_IMPORTANT, LOC + 642 681 QString("Disabling Audio, params(%1,%2,%3)") … … 756 795 757 796 void NuppelVideoPlayer::AutoDeint(VideoFrame *frame) 758 797 { 759 if (!frame || m_scan_locked )798 if (!frame || m_scan_locked || ispip) 760 799 return; 761 800 762 801 if (frame->interlaced_frame) … … 798 837 { 799 838 QMutexLocker locker(&videofiltersLock); 800 839 801 if (!videoOutput || !videosync )840 if (!videoOutput || !videosync || ispip) 802 841 return; // hopefully this will be called again later... 803 842 804 843 m_scan_locked = (scan != kScan_Detect); … … 1059 1098 1060 1099 void NuppelVideoPlayer::InitFilters(void) 1061 1100 { 1101 if (ispip) 1102 return; 1103 1062 1104 VideoFrameType itmp = FMT_YV12; 1063 1105 VideoFrameType otmp = FMT_YV12; 1064 1106 int btmp; … … 2078 2120 { 2079 2121 float diverge = 0.0f; 2080 2122 2123 if (ispip && framesPlayed % 2) 2124 { 2125 videosync->AdvanceTrigger(); 2126 framesPlayed++; 2127 if (!using_null_videoout) 2128 videoOutput->SetFramesPlayed(framesPlayed + 1); 2129 return; 2130 } 2131 2081 2132 VideoFrame *buffer = videoOutput->GetLastShownFrame(); 2082 2133 if (!buffer) 2083 2134 { … … 2553 2604 else if (videoOutput) 2554 2605 { 2555 2606 // Set up deinterlacing in the video output method 2556 m_double_framerate = 2557 (videoOutput->SetupDeinterlace(true) && 2558 videoOutput->NeedsDoubleFramerate()); 2559 2607 if (ispip) 2608 { 2609 m_double_framerate = false; 2610 videoOutput->SetupDeinterlace(true, "onefield"); 2611 } 2612 else 2613 { 2614 m_double_framerate = 2615 (videoOutput->SetupDeinterlace(true) && 2616 videoOutput->NeedsDoubleFramerate()); 2617 } 2618 2560 2619 videosync = VideoSync::BestMethod( 2561 2620 videoOutput, fr_int, rf_int, m_double_framerate); 2562 2621 … … 2589 2648 { 2590 2649 pipplayer = setpipplayer; 2591 2650 needsetpipplayer = false; 2651 if (m_tv) 2652 m_tv->PIPPlayerWake(); 2592 2653 } 2593 2654 2594 2655 if (ringBuffer->isDVD()) … … 3049 3110 3050 3111 if (!InitVideo()) 3051 3112 { 3052 qApp->lock(); 3053 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3113 if (!ispip) 3114 { 3115 qApp->lock(); 3116 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(), 3054 3117 QObject::tr("Unable to initialize video.")); 3055 dialog->AddButton(QObject::tr("Return to menu.")); 3056 dialog->exec(); 3057 delete dialog; 3118 dialog->AddButton(QObject::tr("Return to menu.")); 3119 dialog->exec(); 3120 delete dialog; 3121 qApp->unlock(); 3122 } 3058 3123 3059 qApp->unlock();3060 3061 3124 if (audioOutput) 3062 3125 { 3063 3126 delete audioOutput; … … 3656 3719 int numFrames = totalFrames; 3657 3720 3658 3721 if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE) 3659 numFrames = ( m_playbackinfo->endts.toTime_t() -3660 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate ;3722 numFrames = (int)((m_playbackinfo->endts.toTime_t() - 3723 m_playbackinfo->recstartts.toTime_t()) * video_frame_rate); 3661 3724 3662 3725 int offset = (int) round(0.14 * (numFrames / video_frame_rate)); 3663 3726 … … 3680 3743 3681 3744 void NuppelVideoPlayer::SetBookmark(void) 3682 3745 { 3683 if (!m_playbackinfo || !osd)3746 if (!m_playbackinfo) 3684 3747 return; 3685 3748 3686 3749 m_playbackinfo->SetBookmark(framesPlayed); 3687 osd->SetSettingsText(QObject::tr("Position Saved"), 1); 3750 if (osd) 3751 { 3752 osd->SetSettingsText(QObject::tr("Position Saved"), 1); 3688 3753 3689 struct StatusPosInfo posInfo; 3690 calcSliderPos(posInfo); 3691 osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2); 3754 struct StatusPosInfo posInfo; 3755 calcSliderPos(posInfo); 3756 osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2); 3757 } 3692 3758 } 3693 3759 3694 3760 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 class TV; 17 18 class PIPPlayer 19 { 20 public: 21 PIPPlayer(void); 22 ~PIPPlayer(void); 23 static PIPPlayer *Create(const QRect &rect); 24 static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location); 25 bool StartPlaying(ProgramInfo *rec = NULL, 26 bool piptype = false, 27 bool nullvideo = false, 28 TV *parent = NULL); 29 void StopPlaying(); 30 bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); } 31 bool IsSameProgram(ProgramInfo *rec); 32 RingBuffer *GetRingBuffer(void) { return piprbuffer; } 33 RemoteEncoder *GetRecorder(void) { return piprecorder; } 34 LiveTVChain *GetLiveTVChain(void) { return piptvchain; } 35 NuppelVideoPlayer *GetNVP(void) { return pipnvp; } 36 ProgramInfo *GetProgramInfo(void) { return piprecinfo; } 37 void SetRingBuffer(RingBuffer *rbuffer); 38 void SetLiveTVChain(LiveTVChain *tvchain); 39 void SetRecorder(RemoteEncoder *recorder); 40 void SetProgramInfo(ProgramInfo *pginfo); 41 void SetReinit(bool change) { reinit = change; } 42 bool IsLiveTV(void) { return islivetv; } 43 bool IsHidden(void); 44 void Hide(void); 45 void Show(void); 46 bool UsingNullVideo(void) { return using_nullvideo; } 47 void GetARGBFrame(void); 48 QSize GetVideoDimensions(void) 49 { return QSize(video_width, video_height); } 50 bool IsPaused(void) { return paused; } 51 void Pause(void); 52 void Play(float speed = 1.0); 53 54 55 private: 56 bool StartRecorder(RemoteEncoder *rec, int maxWait); 57 void Reinitialize(void); 58 void Init(QRect rect, QString name); 59 60 private: 61 RemoteEncoder *piprecorder; 62 RingBuffer *piprbuffer; 63 LiveTVChain *piptvchain; 64 ProgramInfo *piprecinfo; 65 NuppelVideoPlayer *pipnvp; 66 pthread_t videoThread; 67 pthread_t pipdecode; 68 QWidget *pipWindow; 69 bool islivetv; 70 bool reinit; 71 bool using_nullvideo; 72 int video_width; 73 int video_height; 74 bool paused; 75 }; 76 77 #endif 78 #ifndef PIPPLAYER_H 79 #define PIPPLAYER_H 80 81 #include <qpainter.h> 82 #include "NuppelVideoPlayer.h" 83 #include "RingBuffer.h" 84 #include "programinfo.h" 85 #include "livetvchain.h" 86 #include "remoteencoder.h" 87 88 class RingBuffer; 89 class ProgramInfo; 90 class LiveTVChain; 91 class RemoteEncoder; 92 class NuppelVideoPlayer; 93 94 class PIPPlayer 95 { 96 public: 97 PIPPlayer(void); 98 ~PIPPlayer(void); 99 static PIPPlayer *Create(const QRect &rect); 100 static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location); 101 bool StartPlaying(ProgramInfo *rec = NULL, 102 bool piptype = false, 103 bool nullvideo = false); 104 void StopPlaying(); 105 bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); } 106 void SetFrameRate(double fps); 107 bool IsSameProgram(ProgramInfo *rec); 108 RingBuffer *GetRingBuffer(void) { return piprbuffer; } 109 RemoteEncoder *GetRecorder(void) { return piprecorder; } 110 LiveTVChain *GetLiveTVChain(void) { return piptvchain; } 111 NuppelVideoPlayer *GetNVP(void) { return pipnvp; } 112 ProgramInfo *GetProgramInfo(void) { return piprecinfo; } 113 void SetRingBuffer(RingBuffer *rbuffer); 114 void SetLiveTVChain(LiveTVChain *tvchain); 115 void SetRecorder(RemoteEncoder *recorder); 116 void SetProgramInfo(ProgramInfo *pginfo); 117 void SetReinit(bool change) { reinit = change; } 118 bool IsLiveTV(void) { return islivetv; } 119 bool IsHidden(void); 120 void Hide(void); 121 void Show(void); 122 bool UsingNullVideo(void) { return using_nullvideo; } 123 void DisplaySoftwareScaledImage(void); 124 125 126 private: 127 bool StartRecorder(RemoteEncoder *rec, int maxWait); 128 void Reinitialize(void); 129 void Init(QRect rect, QString name); 130 131 private: 132 RemoteEncoder *piprecorder; 133 RingBuffer *piprbuffer; 134 LiveTVChain *piptvchain; 135 ProgramInfo *piprecinfo; 136 NuppelVideoPlayer *pipnvp; 137 pthread_t videoThread; 138 pthread_t pipdecode; 139 QWidget *pipWindow; 140 bool islivetv; 141 bool reinit; 142 bool using_nullvideo; 143 }; 144 145 #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->StartPlaying(NULL, true, false, this); 3157 if (pipplayer->IsPlaying()) 3223 3158 { 3224 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder"); 3225 if (testrec) 3226 delete testrec; 3159 pipplayer->Show(); 3160 pipplayer->GetNVP()->DiscardVideoFrames(true); 3227 3161 return; 3228 3162 } 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 3163 else 3246 3164 { 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()) 3165 QSize pipdim = pipplayer->GetVideoDimensions(); 3166 VideoOutput *vid = nvp->getVideoOutput(); 3167 if (vid && 3168 vid->IsResolutionSupported(pipdim.width(), pipdim.height())) 3262 3169 { 3263 piptvchain->ReloadAll(); 3264 usleep(5000); 3170 if (pipplayer->GetNVP() && 3171 pipplayer->GetNVP()->PIPSoftwareScaling() && 3172 nvp->getVideoOutput() && 3173 nvp->getVideoOutput()->hasXVAcceleration()) 3174 { 3175 pipplayer->StartPlaying(NULL, true, true, this); 3176 if (pipplayer->IsPlaying()) 3177 { 3178 pipplayer->Hide(); 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 else 3281 { 3282 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start"); 3283 TeardownPipPlayer(); 3284 } 3187 if (GetOSD()) 3188 GetOSD()->SetSettingsText(tr("PIP Failed to Start"), 3); 3285 3189 } 3286 else 3190 3191 if (IsPIPActiveNVP()) 3192 ToggleActiveWindow(); 3193 3194 if (nvp->HasPIPPlayer()) 3287 3195 { 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); 3196 activenvp->SetPIPPlayer(NULL); 3197 pipplayerCond.wait(); 3307 3198 } 3199 3200 if (pipplayer->IsPlaying() && 3201 !pipplayer->IsLiveTV()) 3202 { 3203 pipplayer->GetNVP()->SetBookmark(); 3204 } 3205 3206 delete pipplayer; 3207 pipplayer = NULL; 3308 3208 } 3309 3209 3310 3210 void TV::ToggleActiveWindow(void) 3311 3211 { 3312 if (!pipnvp) 3212 // toggleactivewindow works only if the main window is live tv. 3213 // problem is playbackinfo and internalstate management. 3214 if (!pipplayer || !pipplayer->GetNVP() || 3215 (!IsPIPActiveNVP() && StateIsPlaying(internalState))) 3216 { 3217 if (GetOSD()) 3218 GetOSD()->SetSettingsText("Toggle PIP Not Allowed", 3); 3313 3219 return; 3314 3220 } 3221 3315 3222 lockTimerOn = false; 3316 if (activenvp == nvp) 3223 LiveTVChain *piptvchain = NULL; 3224 3225 if (!IsPIPActiveNVP()) 3317 3226 { 3318 activenvp = pipnvp; 3319 activerbuffer = piprbuffer; 3320 activerecorder = piprecorder; 3227 3228 activenvp = pipplayer->GetNVP(); 3229 activerbuffer = pipplayer->GetRingBuffer(); 3230 activerecorder = pipplayer->GetRecorder(); 3231 piptvchain = pipplayer->GetLiveTVChain(); 3232 internalState = GetPIPState(pipplayer); 3233 if (pipplayer->GetProgramInfo() && !pipplayer->IsLiveTV()) 3234 SetCurrentlyPlaying(pipplayer->GetProgramInfo()); 3235 if (GetOSD()) 3236 GetOSD()->SetSettingsText("Toggle Active Window: PIP", 3); 3321 3237 } 3322 3238 else 3323 3239 { 3324 activenvp = nvp;3325 activerbuffer = prbuffer;3240 activenvp = nvp; 3241 activerbuffer = prbuffer; 3326 3242 activerecorder = recorder; 3243 internalState = kState_WatchingLiveTV; 3244 if (GetOSD()) 3245 GetOSD()->SetSettingsText("Toggle Active Window: Main", 3); 3327 3246 } 3328 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3329 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3330 if (pginfo) 3331 { 3332 SetCurrentlyPlaying(pginfo); 3333 delete pginfo; 3334 } 3247 3248 if (activerecorder) 3249 { 3250 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 3251 ProgramInfo *pginfo = chain->GetProgramAt(-1); 3252 if (pginfo) 3253 { 3254 SetCurrentlyPlaying(pginfo); 3255 delete pginfo; 3256 } 3257 } 3335 3258 } 3336 3259 3260 3337 3261 struct pip_info 3338 3262 { 3339 3263 RingBuffer *buffer; 3340 3264 RemoteEncoder *recorder; 3341 3265 LiveTVChain *chain; 3342 3266 long long frame; 3267 ProgramInfo *pginfo; 3343 3268 }; 3344 3269 3345 3270 void TV::SwapPIP(void) 3346 3271 { 3347 if (!pipnvp || !piptvchain || !tvchain) 3272 if (!pipplayer) 3273 { 3274 if (GetOSD()) 3275 GetOSD()->SetSettingsText("PIP Not Present", 3); 3348 3276 return; 3277 } 3278 if (IsPIPActiveNVP()) 3279 ToggleActiveWindow(); 3280 3281 bool use_nullvideo = pipplayer->UsingNullVideo(); 3282 bool pipislivetv = StateIsLiveTV(internalState); 3283 3284 if (paused) 3285 DoPause(); 3286 StopFFRew(); 3287 NormalSpeed(); 3349 3288 3350 lockTimerOn = false; 3351 3289 if (playbackinfo) 3290 playbackinfo->setIgnoreBookmark(false); 3291 if (pipplayer->GetProgramInfo()) 3292 pipplayer->GetProgramInfo()->setIgnoreBookmark(false); 3293 3294 // set the bookmark 3295 activenvp->SetBookmark(); 3296 pipplayer->GetNVP()->SetBookmark(); 3297 3352 3298 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 3299 main.buffer = prbuffer; 3300 main.recorder = recorder; 3301 main.chain = tvchain; 3302 main.frame = nvp->GetFramesPlayed(); 3303 if (StateIsPlaying(internalState)) 3304 main.pginfo = new ProgramInfo(*playbackinfo); 3305 else 3306 main.pginfo = NULL; 3307 3308 pip.buffer = pipplayer->GetRingBuffer(); 3309 pip.recorder = pipplayer->GetRecorder(); 3310 pip.chain = pipplayer->GetLiveTVChain(); 3311 pip.frame = pipplayer->GetNVP()->GetFramesPlayed(); 3312 if (!pipplayer->IsLiveTV()) 3313 pip.pginfo = new ProgramInfo(*pipplayer->GetProgramInfo()); 3314 else 3315 pip.pginfo = NULL; 3316 3317 pipplayer->Hide(); 3318 if (use_nullvideo) 3319 { 3320 activenvp->SetPIPPlayer(NULL); 3321 pipplayerCond.wait(); 3322 } 3323 pipplayer->SetReinit(false); 3324 pipplayer->StopPlaying(); 3325 3362 3326 prbuffer->Pause(); 3363 3327 prbuffer->WaitForPause(); 3364 3328 3365 piprbuffer->Pause(); 3366 piprbuffer->WaitForPause(); 3329 nvp->StopPlaying(); 3367 3330 3368 nvp->StopPlaying();3369 pipnvp->StopPlaying();3370 3331 { 3371 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. .3332 QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd.. 3372 3333 pthread_join(decode, NULL); 3373 3334 delete nvp; 3374 3335 nvp = NULL; 3375 pthread_join(pipdecode, NULL);3376 delete pipnvp;3377 pipnvp = NULL;3378 3336 } 3379 3337 3338 if (playbackinfo) 3339 delete playbackinfo; 3340 3380 3341 activerbuffer = prbuffer = pip.buffer; 3381 3342 activerecorder = recorder = pip.recorder; 3382 3343 tvchain = pip.chain; 3344 playbackinfo = pip.pginfo; 3345 internalState = GetPIPState(pipplayer); 3383 3346 3384 piprbuffer = main.buffer; 3385 piprecorder = main.recorder; 3386 piptvchain = main.chain; 3387 3347 pipplayer->SetRingBuffer(main.buffer); 3348 pipplayer->SetRecorder(main.recorder); 3349 pipplayer->SetLiveTVChain(main.chain); 3350 pipplayer->SetProgramInfo(main.pginfo); 3351 3352 VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1") 3353 .arg(StateToString(internalState))); 3354 3388 3355 prbuffer->Seek(0, SEEK_SET); 3389 3356 prbuffer->Unpause(); 3390 StartPlayer(false); 3357 3358 if (internalState == kState_WatchingRecording) 3359 StartPlayer(true); 3360 else 3361 StartPlayer(false); 3362 3391 3363 activenvp = nvp; 3392 nvp->FastForward(pip.frame/recorder->GetFrameRate()); 3364 usleep(10000); 3365 if (tvchain) 3366 { 3367 nvp->FastForward(pip.frame/recorder->GetFrameRate()); 3368 nvp->DiscardVideoFrames(true); 3369 } 3370 3371 pipplayer->GetRingBuffer()->Seek(0, SEEK_SET); 3372 pipplayer->GetRingBuffer()->Unpause(); 3373 3374 if (use_nullvideo) 3375 { 3376 pipplayer->StartPlaying(main.pginfo, pipislivetv, true, this); 3377 if (pipplayer->IsPlaying()) 3378 activenvp->SetPIPPlayer(pipplayer->GetNVP()); 3379 } 3380 else 3381 pipplayer->StartPlaying(main.pginfo, pipislivetv, this); 3393 3382 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()) 3383 if (pipplayer->IsPlaying()) 3400 3384 { 3401 piptvchain->ReloadAll(); 3402 usleep(5000); 3385 if (!use_nullvideo) 3386 pipplayer->Show(); 3387 if (pipplayer->GetLiveTVChain()) 3388 { 3389 pipplayer->GetLiveTVChain()->ReloadAll(); 3390 usleep(5000); 3391 } 3403 3392 } 3404 VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");3405 pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());3406 3393 3407 if (pipnvp->IsDecoderThreadAlive()) 3408 nvp->SetPipPlayer(pipnvp); 3409 else 3394 if (internalState == kState_WatchingLiveTV) 3395 SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV); 3396 3397 if (pipplayer->IsLiveTV()) 3398 SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV); 3399 3400 if (pipplayer->GetLiveTVChain()) 3410 3401 { 3411 VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start"); 3412 TeardownPipPlayer(); 3402 NuppelVideoPlayer *pipnvp = pipplayer->GetNVP(); 3403 float pipframerate = pipplayer->GetRecorder()->GetFrameRate(); 3404 pipnvp->FastForward(main.frame/pipframerate); 3405 pipnvp->DiscardVideoFrames(true); 3413 3406 } 3414 3407 3415 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3416 if (pginfo) 3408 if (tvchain) 3417 3409 { 3418 SetCurrentlyPlaying(pginfo); 3419 delete pginfo; 3410 ProgramInfo *pginfo = tvchain->GetProgramAt(-1); 3411 if (pginfo) 3412 { 3413 SetCurrentlyPlaying(pginfo); 3414 delete pginfo; 3415 } 3420 3416 } 3417 pipplayer->SetReinit(true); 3421 3418 } 3422 3419 3420 TVState TV::GetPIPState(PIPPlayer *player) 3421 { 3422 if (player->IsLiveTV()) 3423 return kState_WatchingLiveTV; 3424 else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0)) 3425 return kState_WatchingRecording; 3426 else 3427 return kState_WatchingPreRecorded; 3428 } 3429 3423 3430 void TV::DoPlay(void) 3424 3431 { 3425 3432 float time = 0.0; … … 3467 3474 3468 3475 void TV::DoPause(bool showOSD) 3469 3476 { 3477 QMutexLocker locker(&stateLock); 3470 3478 if (activerbuffer->InDVDMenuOrStillFrame()) 3471 3479 return; 3472 3480 3481 if (IsPIPActiveNVP()) 3482 { 3483 if (pipplayer->IsPaused()) 3484 pipplayer->Play(); 3485 else 3486 pipplayer->Pause(); 3487 return; 3488 } 3489 3473 3490 speed_index = 0; 3474 3491 float time = 0.0; 3475 3492 3476 3493 if (paused) 3494 { 3477 3495 activenvp->Play(normal_speed, true); 3496 if (pipplayer) 3497 pipplayer->Play(normal_speed); 3498 } 3478 3499 else 3479 3500 { 3480 3501 if (doing_ff_rew) … … 3485 3506 } 3486 3507 3487 3508 activenvp->Pause(); 3509 if (pipplayer) 3510 pipplayer->Pause(); 3488 3511 } 3489 3512 3490 3513 paused = !paused; … … 3849 3872 3850 3873 RemoteEncoder *testrec = NULL; 3851 3874 3852 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pip nvp)3875 if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer) 3853 3876 return; 3854 3877 3855 3878 if (/*chanid || */!channum.isEmpty()) … … 4529 4552 if (showStatus) 4530 4553 { 4531 4554 osd->HideAll(); 4532 if ( nvp)4555 if (activenvp) 4533 4556 { 4534 4557 struct StatusPosInfo posInfo; 4535 nvp->calcSliderPos(posInfo);4558 activenvp->calcSliderPos(posInfo); 4536 4559 osd->ShowStatus(posInfo, false, tr("Position"), 4537 4560 osd_prog_info_timeout); 4538 4561 update_osd_pos = true; … … 4567 4590 4568 4591 void TV::UpdateOSDSeekMessage(const QString &mesg, int disptime) 4569 4592 { 4570 if (activenvp != nvp )4593 if (activenvp != nvp || !prbuffer) 4571 4594 return; 4572 4595 4573 4596 struct StatusPosInfo posInfo; … … 4967 4990 { 4968 4991 bool stayPaused = paused; 4969 4992 if (!paused) 4970 DoPause( );4993 DoPause(false); 4971 4994 4972 4995 switch (editType) 4973 4996 { … … 5002 5025 } 5003 5026 5004 5027 if (!stayPaused) 5005 DoPause( );5028 DoPause(false); 5006 5029 } 5007 5030 5008 5031 // Resize the window back to the MythTV Player size … … 5369 5392 menurunning = false; 5370 5393 AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec); 5371 5394 } 5372 else if (pip recorder&&5373 cardnum == pip recorder->GetRecorderNumber())5395 else if (pipplayer && pipplayer->GetRecorder() && 5396 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5374 5397 { 5375 5398 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording"); 5376 5399 TogglePIPView(); … … 5388 5411 wantsToQuit = false; 5389 5412 exitPlayer = true; 5390 5413 } 5391 else if (pip recorder&&5392 cardnum == pip recorder->GetRecorderNumber())5414 else if (pipplayer && pipplayer->GetRecorder() && 5415 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()) 5393 5416 { 5394 5417 VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV"); 5395 5418 TogglePIPView(); … … 5405 5428 uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1; 5406 5429 5407 5430 if ((recorder && cardnum == recorder->GetRecorderNumber()) || 5408 (piprecorder && cardnum == piprecorder->GetRecorderNumber())) 5431 (pipplayer && pipplayer->GetRecorder() && 5432 cardnum == pipplayer->GetRecorder()->GetRecorderNumber())) 5409 5433 { 5410 5434 if (watch) 5411 5435 { … … 5414 5438 if (pi.FromStringList(list, 0)) 5415 5439 SetPseudoLiveTV(s, &pi, kPseudoChangeChannel); 5416 5440 5417 if (!s && pip nvp)5441 if (!s && pipplayer) 5418 5442 TogglePIPView(); 5419 5443 } 5420 5444 else … … 6408 6432 6409 6433 void TV::ShowOSDTreeMenu(void) 6410 6434 { 6435 if (IsPIPActiveNVP()) 6436 return; 6437 6411 6438 BuildOSDTreeMenu(); 6412 6439 6413 6440 if (GetOSD()) … … 6436 6463 6437 6464 if (StateIsLiveTV(GetState())) 6438 6465 { 6439 bool freeRecorders = (pip nvp!= NULL);6466 bool freeRecorders = (pipplayer != NULL); 6440 6467 if (!freeRecorders) 6441 6468 freeRecorders = RemoteGetFreeRecorderCount(); 6442 6469 … … 7076 7103 { 7077 7104 VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()"); 7078 7105 7106 LiveTVChain *piptvchain = NULL; 7107 if (pipplayer) 7108 piptvchain = pipplayer->GetLiveTVChain(); 7109 7079 7110 LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain; 7080 7111 7081 7112 if (activenvp && chain) -
libs/libmythtv/videoout_null.cpp
88 88 if ((width <= 0) || (height <= 0)) 89 89 return false; 90 90 91 int prebufferframes; 92 if (piptype == kPIPOnLiveTV) 93 prebufferframes = 20; 94 else 95 prebufferframes = kPrebufferFramesSmall; 96 91 97 vbuffers.Init(kNumBuffers, true, kNeedFreeFrames, 92 98 kPrebufferFramesNormal, kPrebufferFramesSmall, 93 kKeepPrebuffer);99 prebufferframes); 94 100 VideoOutput::Init(width, height, aspect, winid, 95 101 winx, winy, winw, winh, embedid); 96 102 -
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, 100 bool piptype, bool nullvideo, 101 TV *parent) 102 { 103 104 using_nullvideo = nullvideo; 105 islivetv = piptype; 106 107 if (reinit) 108 Reinitialize(); 109 110 RemoteEncoder *testrec = NULL; 111 112 VERBOSE(VB_PLAYBACK, LOC + 113 QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording")); 114 115 if (islivetv) 116 { 117 if (!(piprecorder && piprbuffer && piptvchain)) 118 { 119 testrec = RemoteRequestRecorder(); 120 121 if (!testrec || !testrec->IsValidRecorder()) 122 { 123 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder"); 124 if (testrec) 125 delete testrec; 126 return false; 127 } 128 129 testrec->Setup(); 130 131 piptvchain = new LiveTVChain(); 132 piptvchain->InitializeNewChain("PIP"+gContext->GetHostName()); 133 testrec->SpawnLiveTV(piptvchain->GetID(), true); 134 piptvchain->ReloadAll(); 135 piprecinfo = piptvchain->GetProgramAt(-1); 136 if (!piprecinfo) 137 { 138 VERBOSE(VB_IMPORTANT, LOC_ERR + 139 "PIP cannot find live tv programinfo. Exiting"); 140 delete testrec; 141 piptvchain->DestroyChain(); 142 delete piptvchain; 143 return false; 144 } 145 else 146 { 147 QString playbackURL = piprecinfo->GetPlaybackURL(); 148 piptvchain->SetProgram(piprecinfo); 149 piprbuffer = new RingBuffer(playbackURL, false); 150 piprbuffer->SetLiveMode(piptvchain); 151 } 152 153 piprecorder = testrec; 154 155 if (!StartRecorder(piprecorder, -1)) 156 { 157 VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start"); 158 return false; 159 } 160 } 161 } 162 else // pip is not Live TV 163 { 164 if (!piprecinfo) 165 piprecinfo = new ProgramInfo(*rec); 166 if (!piprbuffer) 167 piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1); 168 if (!piprbuffer->IsOpen()) 169 { 170 VERBOSE(VB_IMPORTANT, LOC_ERR + 171 QString("Failed to open Ringbuffer %1") 172 .arg(piprecinfo->pathname)); 173 return false; 174 } 175 } 176 177 // when starting pipplayer for the first time, always start 178 // from the beginning 179 if (reinit && piprecinfo) 180 piprecinfo->setIgnoreBookmark(true); 181 182 pipnvp = new NuppelVideoPlayer("pip player", piprecinfo); 183 pipnvp->SetParentWidget(pipWindow); 184 pipnvp->SetRingBuffer(piprbuffer); 185 if (parent) 186 pipnvp->SetParentPlayer(parent); 187 if (islivetv) 188 { 189 pipnvp->SetRecorder(piprecorder); 190 pipnvp->SetLiveTVChain(piptvchain); 191 } 192 else 193 pipnvp->SetLength(piprecinfo->CalculateLength()); 194 195 196 // setAsPIP is true if null video output is used 197 // PIP will be embedded in XV 198 if (using_nullvideo) 199 { 200 pipnvp->SetAsPIP(true); 201 } 202 else 203 pipnvp->SetAsPIP(false); 204 205 VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP"); 206 pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp); 207 int maxWait = 10000; 208 MythTimer t; 209 t.start(); 210 while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive() && 211 t.elapsed() < maxWait) 212 { 213 usleep(5000); 214 } 215 216 video_width = pipnvp->GetVideoWidth(); 217 video_height = pipnvp->GetVideoHeight(); 218 219 if (!pipnvp->IsPlaying()) 220 { 221 VERBOSE(VB_PLAYBACK, LOC_ERR + "PIP NVP Failed to Start"); 222 return false; 223 } 224 225 VERBOSE(VB_PLAYBACK, LOC + "PIP NVP Started"); 226 return true; 227 } 228 229 void PIPPlayer::StopPlaying(void) 230 { 231 232 if (!pipnvp) 233 return; 234 235 if (pipnvp->IsPlaying()) 236 { 237 if (reinit) 238 piprbuffer->StopReads(); 239 piprbuffer->Pause(); 240 piprbuffer->WaitForPause(); 241 pipnvp->StopPlaying(); 242 } 243 244 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing"); 245 { 246 pthread_join(pipdecode, NULL); 247 delete pipnvp; 248 pipnvp = NULL; 249 } 250 251 if (reinit) 252 { 253 if (islivetv && piprecorder ) 254 piprecorder->StopLiveTV(); 255 256 Reinitialize(); 257 } 258 259 VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted"); 260 } 261 262 /* 263 * \brief set pip ringbuffer if pip is not playing 264 */ 265 void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer) 266 { 267 if (!IsPlaying()) 268 piprbuffer = rbuffer; 269 } 270 271 /* 272 * \brief set pip tvchain if pip is not playing 273 */ 274 void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain) 275 { 276 if (!IsPlaying()) 277 piptvchain = tvchain; 278 } 279 280 /* 281 * \brief set pip recorder if pip is not playing 282 */ 283 void PIPPlayer::SetRecorder(RemoteEncoder *recorder) 284 { 285 if (!IsPlaying()) 286 piprecorder = recorder; 287 } 288 289 void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo) 290 { 291 if (!IsPlaying()) 292 { 293 if (piprecinfo) 294 delete piprecinfo; 295 piprecinfo = pginfo; 296 } 297 } 298 299 bool PIPPlayer::IsSameProgram(ProgramInfo *rec) 300 { 301 if (!rec || !piprecinfo) 302 return false; 303 304 if (piprecinfo->IsSameProgram(*rec)) 305 return true; 306 307 return false; 308 } 309 310 bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait) 311 { 312 maxWait = (maxWait <= 0) ? 20000 : maxWait; 313 MythTimer t; 314 t.start(); 315 while (rec && !rec->IsRecording() && t.elapsed() < maxWait) 316 usleep(5000); 317 if (rec && !rec->IsRecording()) 318 { 319 VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out"); 320 return false; 321 } 322 return true; 323 } 324 325 void PIPPlayer::Hide(void) 326 { 327 if (pipWindow && pipWindow->isVisible()) 328 pipWindow->hide(); 329 } 330 331 void PIPPlayer::Show(void) 332 { 333 if (pipWindow && pipWindow->isHidden()) 334 pipWindow->show(); 335 } 336 337 bool PIPPlayer::IsHidden(void) 338 { 339 if (pipWindow && pipWindow->isHidden()) 340 return true; 341 return false; 342 } 343 344 void PIPPlayer::GetARGBFrame(void) 345 { 346 if (!using_nullvideo) 347 return; 348 349 QPainter p(pipWindow); 350 QSize size = pipWindow->size(); 351 float saspect = ((float)size.width())/ ((float)size.height()); 352 float vaspect = pipnvp->GetVideoAspect(); 353 size.setHeight((int) ceil(size.height() * (saspect / vaspect))); 354 size.setHeight(((size.height() + 7) / 8) * 8); 355 size.setWidth( ((size.width() + 7) / 8) * 8); 356 const QImage &img = pipnvp->GetARGBFrame(size); 357 p.drawImage(0, 0, img); 358 } 359 360 void PIPPlayer::Pause(void) 361 { 362 if (IsPlaying() && !paused) 363 { 364 pipnvp->Pause(); 365 paused = true; 366 } 367 } 368 369 void PIPPlayer::Play(float speed) 370 { 371 if (IsPlaying() && paused) 372 { 373 pipnvp->Play(speed); 374 paused = false; 375 } 376 } 377 -
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 kPIPOnLiveTV // Live TV used in TV Mode 88 }; 89 82 90 enum ZoomDirections 83 91 { 84 92 kZoomHome = 0, … … 190 198 virtual void GetOSDBounds(QRect &visible, QRect &total, 191 199 float &pixelAspect, float &fontScale) const; 192 200 201 virtual bool IsResolutionSupported(int width, int height); 202 193 203 /// \brief Returns current display's frame refresh period in microseconds. 194 204 /// e.g. 1000000 / frame_rate_in_Hz 195 205 virtual int GetRefreshRate(void) = 0; … … 225 235 bool AllowPreviewEPG(void) { return allowpreviewepg; } 226 236 227 237 /// \brief Returns true iff Motion Compensation acceleration is available. 228 virtual bool hasMCAcceleration( ) const { return false; }238 virtual bool hasMCAcceleration(void) const { return false; } 229 239 /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration 230 240 /// is available. 231 virtual bool hasIDCTAcceleration( ) const { return false; }241 virtual bool hasIDCTAcceleration(void) const { return false; } 232 242 /// \brief Returns true iff VLD acceleration is available. 233 virtual bool hasVLDAcceleration() const { return false; } 243 virtual bool hasVLDAcceleration(void) const { return false; } 244 /// \brief Returns true if XV acceleration is available. 245 virtual bool hasXVAcceleration(void) const { return false; } 234 246 235 247 /// \brief Sets the number of frames played 236 248 virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; }; … … 308 320 /// \brief Tells the player to resize the video frame (used for ITV) 309 321 void SetVideoResize(const QRect &videoRect); 310 322 323 /// \brief returns QRect of PIP based on PIPLocation 324 virtual QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer = NULL); 325 326 /// set PIP Type 327 void SetAsPIP(PIPType setting) { piptype = setting; } 328 329 311 330 protected: 312 331 void InitBuffers(int numdecode, bool extra_for_pause, int need_free, 313 332 int needprebuffer_normal, int needprebuffer_small, … … 384 403 QSize pip_video_size; 385 404 unsigned char *pip_tmp_buf; 386 405 ImgReSampleContext *pip_scaling_context; 406 PIPType piptype; 387 407 388 408 // Video resizing (for ITV) 389 409 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;